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.
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.int dockSide = WindowManagerProxy.getInstance().getDockSide();
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.