AN ANALYSIS OF Android N SCREENING PROCESS

Keywords: Java Attribute Android Windows

On Android N, Google created a split-screen effect, that is, after entering the application, press Recents long and enter the split-screen state.

                                

The left side is the application that enters the split screen, the middle area is the line that can slide, and the right side is the list of recents.

The following is a complete interaction map into the sub-screen:

Following is a step-by-step detailed introduction:

It was introduced in the last article. Navigation bar button adds display and event binding The process analysis records are not discussed here. Next, I will analyze the changes of the interface step by step according to the user's operation.

1. Enter the split-screen scene analysis:

The user presses the receive key for a long time, starting with the response to the long press event. The code is as follows:

    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);
            }
        }
    }

This code is located in: framework/base/packages/SystemUI/src/.../PhoneStatusBar.java

This section first determines whether mRecents are empty, mRecents is Recents.class, as explained in BaseStatusBar.java.

Judging the current split-screen state, you can get the split-screen state through this code, and judge whether it is in the split-screen state, if it is not, then the value obtained is Windows Manager.DOCKED_INVALID.

int dockSide = WindowManagerProxy.getInstance().getDockSide();
We analyze the process of entering the split screen, and the value we get is Windows Manager.DOCKED_INVALID. The Recents.dockTopTask(...) method is called.

2. We've got the split-screen status, so let's start processing.

    @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;
        }
    }

Code location: framework/base/packages/System/.../Recents.java

Four parameter values are passed in:

int dragMode:NavigationBarGestureHelper.DRAG_MODE_NONE
int stackCreateMode :ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
Rect initialBounds:null
int metricsDockAction:MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS

Because the initial bounds are null, they give him a value, which is the size of the screen. For example, the current screen resolution is 1920*1200, so the initial bounds is (0,0,1920,1200), that is, the full screen size.

Get information about the task that is currently running. This task is an application that is running when you press receive for a long time. It can also be an application that will be the focus.

We need to make sure that we get the task properly, otherwise we will not be able to process the task information later.

To determine whether the stackid of the current task is a homestack, it is necessary to specify that on Android N, the system defaults to five kinds of Activity Systems: ___________

stack name stack_id
homestack 0
fullscreenstack 1
freeformstack 2
dcokstack 3
pinstack 4

Two applications are recorded in the home stack: launcher and System UI, which explains why we can't get into the split screen by pressing the receive key for a long time in the lacunher interface. Why add this judgment I will explain later.

runningTask.isDockable is an attribute. Only when this attribute is true can an application enter the split screen. If not, a toast pops up to remind users that they cannot enter the split screen. For example, if we want to enter the split screen in a camera application, we can't. In practical development, some applications do not want to let it into the sub-screen. They can modify the isDockable attribute, which is controlled by the canGoInDockedStack() method in TaskRecord.java (mResizeMode is 2 in the application that can enter the sub-screen, and mResizeMode value is 0 in the application that cannot enter the sub-screen).

The following judgement is whether it is a System User, and if so, execute dockTopTask(...) in RecentsImpl, or else it is RecentsImplProxy.dockTopTask(...). However, if you execute RecentsImplProxy.dockTopTask(.)), the method in Recents will also be called.








Posted by microbluechip on Sun, 21 Apr 2019 11:18:34 -0700