java安卓如何多窗口_Android 7.1 SystemUI--Multi-Window多窗口模式

PhoneStatusBar.java

private View.OnLongClickListener mRecentsLongClickListener = newView.OnLongClickListener() {

@Overridepublic booleanonLongClick(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;

}

};

@Overrideprotected void toggleSplitScreenMode(int metricsDockAction, intmetricsUndockAction) {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(newUndockingTaskEvent());if (metricsUndockAction != -1) {

MetricsLogger.action(mContext, metricsUndockAction);

}

}

}

Recents.java

@Overridepublic boolean dockTopTask(int dragMode, intstackCreateMode, Rect initialBounds,intmetricsDockAction) {//Ensure the device has been provisioned before allowing the user to interact with//recents

if (!isUserSetup()) {return false;

}

Point realSize= newPoint();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(newShowUserToastEvent(

R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT));return false;

}

}else{return false;

}

}

RecentsImpl.java

public void dockTopTask(int topTaskId, intdragMode,intstackCreateMode, 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(newDockedTopTaskEvent(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, intcreateMode, 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.

*

*@paramtaskId Id of task to move.

*@paramcreateMode The mode the docked stack should be created in if it doesn't exist

* already. See

* {@linkandroid.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT}

* and

* {@linkandroid.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT}

*@paramtoTop If the task and stack should be moved to the top.

*@paramanimate Whether we should play an animation for the moving the task

*@paraminitialBounds If the docked stack gets created, it will use these bounds for the

* docked stack. Pass {@codenull} to use default bounds.*/@Overridepublic boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, booleananimate,

Rect initialBounds,booleanmoveHomeStackFront) {

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

}returnmoved;

}finally{

Binder.restoreCallingIdentity(ident);

}

}

}

ActivityStackSupervisor.java

boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, booleanforceFocus,

String reason,boolean animate, booleandeferResume) {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.

*@paramtask Task to move.

*@paramstackId Id of stack to move task to.

*@paramtoTop True if the task should be placed at the top of the stack.

*@paramforceFocus if focus should be moved to the new stack

*@paramreason Reason the task is been moved.

*@returnThe stack the task was moved to.*/ActivityStack moveTaskToStackUncheckedLocked(

TaskRecord task,int stackId, boolean toTop, booleanforceFocus, 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);returnstack;

}

WindowManagerService.java

public void moveTaskToStack(int taskId, int stackId, booleantoTop) {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 voidperformSurfacePlacement() {if (mDeferDepth > 0) {return;

}int loopCount = 6;do{

mTraversalScheduled= false;

performSurfacePlacementLoop();

mService.mH.removeMessages(DO_TRAVERSAL);

loopCount--;

}while (mTraversalScheduled && loopCount > 0);

mWallpaperActionPending= false;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值