From 606dd80700a7c7bfb15872fe5a8c57e86f504411 Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Mon, 5 Jun 2017 14:06:32 -0700 Subject: [PATCH] Fixes the animation and state when docking a task by drag There was 3 issues in this bug. First the wrong stack id was used to defer and continue updating bounds that broke a lot of the animation. This was fixed by using the recents stack id instead of home. Secondly, the wrong transit was passed into AppTransition.java getting the wrong animation for recents to be docked, defering surface layouts ensures that the correct transition is gained in that transaction. Lastly, remove the starting window for the docked-by-drag-from-recents transition because it was causing the window container to freeze its bounds causing clipping issues and 2 flickers (where it appears over the thumbnail) during the animation. Added a TODO to fix it later. Test: go/wm-smoke Bug: 34099271 Change-Id: Iaf0dffe5c2f5108c9946c9ea23c6e3fd6a49c34d --- .../server/am/ActivityStackSupervisor.java | 126 +++++++++--------- .../wm/AppWindowContainerController.java | 10 +- 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index b55bae91da8d2..53afe78f2ea34 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2364,7 +2364,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void notifyAppTransitionDone() { - continueUpdateBounds(HOME_STACK_ID); + continueUpdateBounds(RECENTS_STACK_ID); for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) { final int taskId = mResizingTasksDuringAnimation.valueAt(i); final TaskRecord task = @@ -5090,73 +5090,79 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D + taskId + " can't be launch in the home/recents stack."); } - if (launchStackId == DOCKED_STACK_ID) { - mWindowManager.setDockedStackCreateState( - activityOptions.getDockCreateMode(), null /* initialBounds */); + mWindowManager.deferSurfaceLayout(); + try { + if (launchStackId == DOCKED_STACK_ID) { + mWindowManager.setDockedStackCreateState( + activityOptions.getDockCreateMode(), null /* initialBounds */); - // Defer updating the stack in which recents is until the app transition is done, to - // not run into issues where we still need to draw the task in recents but the - // docked stack is already created. - deferUpdateBounds(HOME_STACK_ID); - mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false); - } - - task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, - launchStackId); - if (task == null) { - continueUpdateBounds(HOME_STACK_ID); - mWindowManager.executeAppTransition(); - throw new IllegalArgumentException( - "startActivityFromRecentsInner: Task " + taskId + " not found."); - } - - // Since we don't have an actual source record here, we assume that the currently focused - // activity was the source. - final ActivityStack focusedStack = getFocusedStack(); - final ActivityRecord sourceRecord = - focusedStack != null ? focusedStack.topActivity() : null; - - if (launchStackId != INVALID_STACK_ID) { - if (task.getStackId() != launchStackId) { - task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, - DEFER_RESUME, "startActivityFromRecents"); + // Defer updating the stack in which recents is until the app transition is done, to + // not run into issues where we still need to draw the task in recents but the + // docked stack is already created. + deferUpdateBounds(RECENTS_STACK_ID); + mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false); } - } - // If the user must confirm credentials (e.g. when first launching a work app and the - // Work Challenge is present) let startActivityInPackage handle the intercepting. - if (!mService.mUserController.shouldConfirmCredentials(task.userId) - && task.getRootActivity() != null) { - mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */); - mActivityMetricsLogger.notifyActivityLaunching(); - mService.moveTaskToFrontLocked(task.taskId, 0, bOptions); - mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT, - task.getTopActivity()); + task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, + launchStackId); + if (task == null) { + continueUpdateBounds(RECENTS_STACK_ID); + mWindowManager.executeAppTransition(); + throw new IllegalArgumentException( + "startActivityFromRecentsInner: Task " + taskId + " not found."); + } - // If we are launching the task in the docked stack, put it into resizing mode so - // the window renders full-screen with the background filling the void. Also only - // call this at the end to make sure that tasks exists on the window manager side. + // Since we don't have an actual source record here, we assume that the currently + // focused activity was the source. + final ActivityStack focusedStack = getFocusedStack(); + final ActivityRecord sourceRecord = + focusedStack != null ? focusedStack.topActivity() : null; + + if (launchStackId != INVALID_STACK_ID) { + if (task.getStackId() != launchStackId) { + task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, + DEFER_RESUME, "startActivityFromRecents"); + } + } + + // If the user must confirm credentials (e.g. when first launching a work app and the + // Work Challenge is present) let startActivityInPackage handle the intercepting. + if (!mService.mUserController.shouldConfirmCredentials(task.userId) + && task.getRootActivity() != null) { + mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */); + mActivityMetricsLogger.notifyActivityLaunching(); + mService.moveTaskToFrontLocked(task.taskId, 0, bOptions); + mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT, + task.getTopActivity()); + + // If we are launching the task in the docked stack, put it into resizing mode so + // the window renders full-screen with the background filling the void. Also only + // call this at the end to make sure that tasks exists on the window manager side. + if (launchStackId == DOCKED_STACK_ID) { + setResizingDuringAnimation(task); + } + + mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(), + ActivityManager.START_TASK_TO_FRONT, + sourceRecord != null + ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID, + sourceRecord, task.getStack()); + return ActivityManager.START_TASK_TO_FRONT; + } + callingUid = task.mCallingUid; + callingPackage = task.mCallingPackage; + intent = task.intent; + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + userId = task.userId; + int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null, + null, null, 0, 0, bOptions, userId, null, task); if (launchStackId == DOCKED_STACK_ID) { setResizingDuringAnimation(task); } - - mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(), - ActivityManager.START_TASK_TO_FRONT, - sourceRecord != null ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID, - sourceRecord, task.getStack()); - return ActivityManager.START_TASK_TO_FRONT; + return result; + } finally { + mWindowManager.continueSurfaceLayout(); } - callingUid = task.mCallingUid; - callingPackage = task.mCallingPackage; - intent = task.intent; - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - userId = task.userId; - int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null, - null, null, 0, 0, bOptions, userId, null, task); - if (launchStackId == DOCKED_STACK_ID) { - setResizingDuringAnimation(task); - } - return result; } /** diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 66401846c034a..8cfbf68e3b5df 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + +import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; @@ -581,8 +583,12 @@ public class AppWindowContainerController private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) { - if (newTask || !processRunning - || (taskSwitch && !activityCreated)) { + if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) { + // TODO(b/34099271): Remove this statement to add back the starting window and figure + // out why it causes flickering, the starting window appears over the thumbnail while + // the docked from recents transition occurs + return STARTING_WINDOW_TYPE_NONE; + } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) { return STARTING_WINDOW_TYPE_SPLASH_SCREEN; } else if (taskSwitch && allowTaskSnapshot) { return STARTING_WINDOW_TYPE_SNAPSHOT;