博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 7.1 SystemUI--Multi-Window多窗口模式
阅读量:7141 次
发布时间:2019-06-28

本文共 17555 字,大约阅读时间需要 58 分钟。

PhoneStatusBar.java

private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() {        @Override        public boolean onLongClick(View v) {            if (mRecents == null || !ActivityManager.supportsMultiWindow()                    || !getComponent(Divider.class).getView().getSnapAlgorithm()                            .isSplitScreenFeasible()) {                return false;            }            toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,                    MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);            return true;        }    };

 

@Override    protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {        if (mRecents == null) {            return;        }        int dockSide = WindowManagerProxy.getInstance().getDockSide();        if (dockSide == WindowManager.DOCKED_INVALID) {            // 进入分屏            mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);        } else {            // 退出分屏            EventBus.getDefault().send(new UndockingTaskEvent());            if (metricsUndockAction != -1) {                MetricsLogger.action(mContext, metricsUndockAction);            }        }    }

 

 

Recents.java

@Override    public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds,            int metricsDockAction) {        // Ensure the device has been provisioned before allowing the user to interact with        // recents        if (!isUserSetup()) {            return false;        }        Point realSize = new Point();        if (initialBounds == null) {            mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)                    .getRealSize(realSize);            initialBounds = new Rect(0, 0, realSize.x, realSize.y);        }        int currentUser = sSystemServicesProxy.getCurrentUser();        SystemServicesProxy ssp = Recents.getSystemServices();        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();        boolean screenPinningActive = ssp.isScreenPinningActive();        boolean isRunningTaskInHomeStack = runningTask != null &&                SystemServicesProxy.isHomeStack(runningTask.stackId);        if (runningTask != null && !isRunningTaskInHomeStack && !screenPinningActive) {            logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);             // 可分屏            if (runningTask.isDockable) {                if (metricsDockAction != -1) {                    MetricsLogger.action(mContext, metricsDockAction,                            runningTask.topActivity.flattenToShortString());                }                if (sSystemServicesProxy.isSystemUser(currentUser)) {                    mImpl.dockTopTask(runningTask.id, dragMode, stackCreateMode, initialBounds);                } else {                    if (mSystemToUserCallbacks != null) {                        IRecentsNonSystemUserCallbacks callbacks =                                mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);                        if (callbacks != null) {                            try {                                callbacks.dockTopTask(runningTask.id, dragMode, stackCreateMode,                                        initialBounds);                            } catch (RemoteException e) {                                Log.e(TAG, "Callback failed", e);                            }                        } else {                            Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);                        }                    }                }                mDraggingInRecentsCurrentUser = currentUser;                return true;            } else {
// 不支持分屏 EventBus.getDefault().send(new ShowUserToastEvent( R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT)); return false; } } else { return false; } }

 

 RecentsImpl.java

public void dockTopTask(int topTaskId, int dragMode,            int stackCreateMode, Rect initialBounds) {        SystemServicesProxy ssp = Recents.getSystemServices();        // Make sure we inform DividerView before we actually start the activity so we can change        // the resize mode already.        if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {            EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));            showRecents(                    false /* triggeredFromAltTab */,                    dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,                    false /* animate */,                    true /* launchedWhileDockingTask*/,                    false /* fromHome */,                    DividerView.INVALID_RECENTS_GROW_TARGET);        }    }

 

 

SystemServicesProxy.java

/** Docks an already resumed task to the side of the screen. */    public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {        if (mIam == null) {            return false;        }        try {            return mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */,                    false /* animate */, initialBounds, true /* moveHomeStackFront */ );        } catch (RemoteException e) {            e.printStackTrace();        }        return false;    }

 

mIam 是 IActivityManager 对象

ActivityManagerService.java

/**     * Moves the input task to the docked stack.     *     * @param taskId Id of task to move.     * @param createMode The mode the docked stack should be created in if it doesn't exist     *                   already. See     *                   {
@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT} * and * {
@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT} * @param toTop If the task and stack should be moved to the top. * @param animate Whether we should play an animation for the moving the task * @param initialBounds If the docked stack gets created, it will use these bounds for the * docked stack. Pass {
@code null} to use default bounds. */ @Override public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean moveHomeStackFront) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()"); synchronized (this) { long ident = Binder.clearCallingIdentity(); try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateState(createMode, initialBounds); final boolean moved = mStackSupervisor.moveTaskToStackLocked( taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack", animate, DEFER_RESUME); if (moved) { if (moveHomeStackFront) { mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack"); } mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } return moved; } finally { Binder.restoreCallingIdentity(ident); } } }

 

ActivityStackSupervisor.java

boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,            String reason, boolean animate, boolean deferResume) {        final TaskRecord task = anyTaskForIdLocked(taskId);        if (task == null) {            Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);            return false;        }        if (task.stack != null && task.stack.mStackId == stackId) {            // You are already in the right stack silly...            Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);            return true;        }        if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {            throw new IllegalArgumentException("moveTaskToStack:"                    + "Attempt to move task " + taskId + " to unsupported freeform stack");        }        final ActivityRecord topActivity = task.getTopActivity();        final int sourceStackId = task.stack != null ? task.stack.mStackId : INVALID_STACK_ID;        final boolean mightReplaceWindow =                StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) && topActivity != null;        if (mightReplaceWindow) {            // We are about to relaunch the activity because its configuration changed due to            // being maximized, i.e. size change. The activity will first remove the old window            // and then add a new one. This call will tell window manager about this, so it can            // preserve the old window until the new one is drawn. This prevents having a gap            // between the removal and addition, in which no window is visible. We also want the            // entrance of the new window to be properly animated.            // Note here we always set the replacing window first, as the flags might be needed            // during the relaunch. If we end up not doing any relaunch, we clear the flags later.            mWindowManager.setReplacingWindow(topActivity.appToken, animate);        }        mWindowManager.deferSurfaceLayout();        final int preferredLaunchStackId = stackId;        boolean kept = true;        try {            final ActivityStack stack = moveTaskToStackUncheckedLocked(                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack");            stackId = stack.mStackId;            if (!animate) {                stack.mNoAnimActivities.add(topActivity);            }            // We might trigger a configuration change. Save the current task bounds for freezing.            mWindowManager.prepareFreezingTaskBounds(stack.mStackId);            // Make sure the task has the appropriate bounds/size for the stack it is in.            if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,                        !mightReplaceWindow, deferResume);            } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {                Rect bounds = task.getLaunchBounds();                if (bounds == null) {                    stack.layoutTaskInStack(task, null);                    bounds = task.mBounds;                }                kept = resizeTaskLocked(task, bounds, RESIZE_MODE_FORCED, !mightReplaceWindow,                        deferResume);            } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,                        !mightReplaceWindow, deferResume);            }        } finally {            mWindowManager.continueSurfaceLayout();        }        if (mightReplaceWindow) {            // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old            // window), we need to clear the replace window settings. Otherwise, we schedule a            // timeout to remove the old window if the replacing window is not coming in time.            mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);        }        if (!deferResume) {            // The task might have already been running and its visibility needs to be synchronized with            // the visibility of the stack / windows.            ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);            resumeFocusedStackTopActivityLocked();        }        handleNonResizableTaskIfNeeded(task, preferredLaunchStackId, stackId);        return (preferredLaunchStackId == stackId);    }

            final ActivityStack stack = moveTaskToStackUncheckedLocked(

                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack");

/**     * Moves the specified task record to the input stack id.     * WARNING: This method performs an unchecked/raw move of the task and     * can leave the system in an unstable state if used incorrectly.     * Use {
@link #moveTaskToStackLocked} to perform safe task movement to a stack. * @param task Task to move. * @param stackId Id of stack to move task to. * @param toTop True if the task should be placed at the top of the stack. * @param forceFocus if focus should be moved to the new stack * @param reason Reason the task is been moved. * @return The stack the task was moved to. */ ActivityStack moveTaskToStackUncheckedLocked( TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) { if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) { throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't " + "support multi-window task=" + task + " to stackId=" + stackId); } final ActivityRecord r = task.topRunningActivityLocked(); final ActivityStack prevStack = task.stack; final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r); final boolean wasResumed = prevStack.mResumedActivity == r; // In some cases the focused stack isn't the front stack. E.g. pinned stack. // Whenever we are moving the top activity from the front stack we want to make sure to move // the stack to the front. final boolean wasFront = isFrontStack(prevStack) && (prevStack.topRunningActivityLocked() == r); if (stackId == DOCKED_STACK_ID && !task.isResizeable()) { // We don't allow moving a unresizeable task to the docked stack since the docked // stack is used for split-screen mode and will cause things like the docked divider to // show up. We instead leave the task in its current stack or move it to the fullscreen // stack if it isn't currently in a stack. stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID; Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack. Moving to stackId=" + stackId + " instead."); } if (stackId == FREEFORM_WORKSPACE_STACK_ID && mService.mUserController.shouldConfirmCredentials(task.userId)) { stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID; Slog.w(TAG, "Can not move locked profile task=" + task + " to freeform stack. Moving to stackId=" + stackId + " instead."); } // Temporarily disable resizeablility of task we are moving. We don't want it to be resized // if a docked stack is created below which will lead to the stack we are moving from and // its resizeable tasks being resized. task.mTemporarilyUnresizable = true; final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); task.mTemporarilyUnresizable = false; mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); stack.addTask(task, toTop, reason); // If the task had focus before (or we're requested to move focus), // move focus to the new stack by moving the stack to the front. stack.moveToFrontAndResumeStateIfNeeded( r, forceFocus || wasFocused || wasFront, wasResumed, reason); return stack; }

 

WindowManagerService.java

public void moveTaskToStack(int taskId, int stackId, boolean toTop) {        synchronized (mWindowMap) {            if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: moving taskId=" + taskId                    + " to stackId=" + stackId + " at " + (toTop ? "top" : "bottom"));            Task task = mTaskIdToTask.get(taskId);            if (task == null) {                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find taskId=" + taskId);                return;            }            TaskStack stack = mStackIdToStack.get(stackId);            if (stack == null) {                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find stackId=" + stackId);                return;            }            task.moveTaskToStack(stack, toTop);            final DisplayContent displayContent = stack.getDisplayContent();            displayContent.layoutNeeded = true;            mWindowPlacerLocked.performSurfacePlacement();        }    }

 

WindowSurfacePlacer.java

/**

 * Positions windows and their surfaces.
 *
 * It sets positions of windows by calculating their frames and then applies this by positioning
 * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
 */
class WindowSurfacePlacer {

final void performSurfacePlacement() {        if (mDeferDepth > 0) {            return;        }        int loopCount = 6;        do {            mTraversalScheduled = false;            performSurfacePlacementLoop();            mService.mH.removeMessages(DO_TRAVERSAL);            loopCount--;        } while (mTraversalScheduled && loopCount > 0);        mWallpaperActionPending = false;    }

 

}

 

转载于:https://www.cnblogs.com/onelikeone/p/7478762.html

你可能感兴趣的文章
我的友情链接
查看>>
判断函数是否存在
查看>>
nginx重新编译添加ngx_cache_purge扩展
查看>>
配置 VirtualBox backend - 每天5分钟玩转 Docker 容器技术(75)
查看>>
第十二集真机实配VLAN和VTP视频演示
查看>>
KVM在线迁移(动态迁移)
查看>>
更改session值后显示在前端页面
查看>>
DNS域名系统(一)
查看>>
定制CentOS 6.3 自动安装盘
查看>>
Connectify+Wireshark捕获手机APP的数据包
查看>>
CentOS 6.5 生产环境编译安装LNMP
查看>>
8.6 “数据库设置”服务器选项
查看>>
两种方法反转单链表
查看>>
二叉树递归前序、中序、后序遍历
查看>>
在VIEW中加载UICollectionView
查看>>
散列桶
查看>>
eclipse修改 服务器默认路径
查看>>
[iOS Animation]-CALayer 视觉效果
查看>>
8 步搭建 Node.js + MongoDB 项目的自动化持续集成
查看>>
windowsserver 2012 R2 创建群集失败
查看>>