Merge "Trigger onTaskAppeared when a task started from recents becomes ready." into rvc-dev am: 1c92e1f789

Change-Id: If4c0b104dadea9164db0baa2bec13511243d50b8
This commit is contained in:
Ming-Shin Lu
2020-04-10 06:34:21 +00:00
committed by Automerger Merge Worker
14 changed files with 186 additions and 31 deletions

View File

@@ -192,6 +192,11 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
Assume.assumeNoException(
new AssertionError("onAnimationCanceled should not be called"));
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
/* no-op */
}
};
recentsSemaphore.tryAcquire();

View File

@@ -114,4 +114,16 @@ interface IRecentsAnimationController {
* animation is cancelled through fail safe mechanism.
*/
void setWillFinishToHome(boolean willFinishToHome);
/**
* Stops controlling a task that is currently controlled by this recents animation.
*
* This method should be called when a task that has been received via {@link #onAnimationStart}
* or {@link #onTaskAppeared} is no longer needed. After calling this method, the task will
* either disappear from the screen, or jump to its final position in case it was the top task.
*
* @param taskId Id of the Task target to remove
* @return {@code true} when target removed successfully, {@code false} otherwise.
*/
boolean removeTask(int taskId);
}

View File

@@ -56,4 +56,10 @@ oneway interface IRecentsAnimationRunner {
void onAnimationStart(in IRecentsAnimationController controller,
in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
in Rect homeContentInsets, in Rect minimizedHomeBounds) = 2;
/**
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
void onTaskAppeared(in RemoteAnimationTarget app) = 3;
}

View File

@@ -883,6 +883,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-242787066": {
"message": "addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s",
"level": "DEBUG",
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/WindowContainer.java"
},
"-198463978": {
"message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
"level": "VERBOSE",
@@ -901,6 +907,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
"-172900257": {
"message": "addTaskToTargets, target: %s",
"level": "DEBUG",
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
"-167822951": {
"message": "Attempted to add starting window to token with already existing starting window",
"level": "WARN",
@@ -1525,6 +1537,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
"854237232": {
"message": "addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s",
"level": "DEBUG",
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/Task.java"
},
"873914452": {
"message": "goodToGo()",
"level": "DEBUG",

View File

@@ -261,6 +261,11 @@ public class ActivityManagerWrapper {
animationHandler.onAnimationCanceled(
taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null);
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) {
animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app));
}
};
}
ActivityTaskManager.getService().startRecentsActivity(intent, receiver, runner);

View File

@@ -109,4 +109,16 @@ public class RecentsAnimationControllerCompat {
Log.e(TAG, "Failed to set overview reached state", e);
}
}
/**
* @see IRecentsAnimationController#removeTask
*/
public boolean removeTask(int taskId) {
try {
return mAnimationController.removeTask(taskId);
} catch (RemoteException e) {
Log.e(TAG, "Failed to remove remote animation target", e);
return false;
}
}
}

View File

@@ -32,4 +32,10 @@ public interface RecentsAnimationListener {
* Called when the animation into Recents was canceled. This call is made on the binder thread.
*/
void onAnimationCanceled(ThumbnailData thumbnailData);
/**
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
void onTaskAppeared(RemoteAnimationTargetCompat app);
}

View File

@@ -403,11 +403,18 @@ public class AppTransition implements Dump {
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
}
boolean isNextAppTransitionOpenCrossProfileApps() {
return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
}
boolean isNextAppTransitionCustomFromRecents() {
final RecentTasks recentTasks = mService.mAtmService.getRecentTasks();
final String recentsPackageName =
(recentTasks != null) ? recentTasks.getRecentsComponent().getPackageName() : null;
return mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM
&& mNextAppTransitionPackage.equals(recentsPackageName);
}
/**
* @return true if and only if we are currently fetching app transition specs from the future
* passed into {@link #overridePendingAppTransitionMultiThumbFuture}

View File

@@ -442,10 +442,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// Always prepare an app transition since we rely on the transition callbacks to cleanup
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
controller.setCancelOnNextTransitionStart();
} else {
// Just cancel directly to unleash from launcher when the next launching task is the
// current top task.
mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "stackOrderChanged");
}
}

View File

@@ -43,6 +43,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
@@ -99,6 +100,8 @@ public class RecentsAnimationController implements DeathRecipient {
private IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
private final IntArray mPendingNewTaskTargets = new IntArray(0);
private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
new ArrayList<>();
private final int mDisplayId;
@@ -220,6 +223,10 @@ public class RecentsAnimationController implements DeathRecipient {
if (mCanceled) {
return;
}
// Remove all new task targets.
for (int i = mPendingNewTaskTargets.size() - 1; i >= 0; i--) {
removeTaskInternal(mPendingNewTaskTargets.get(i));
}
}
// Note, the callback will handle its own synchronization, do not lock on WM lock
@@ -310,6 +317,18 @@ public class RecentsAnimationController implements DeathRecipient {
mWillFinishToHome = willFinishToHome;
}
}
@Override
public boolean removeTask(int taskId) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
return removeTaskInternal(taskId);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
};
/**
@@ -405,11 +424,17 @@ public class RecentsAnimationController implements DeathRecipient {
@VisibleForTesting
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
return addAnimation(task, isRecentTaskInvisible, null /* finishedCallback */);
}
@VisibleForTesting
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible,
OnAnimationFinishedCallback finishedCallback) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
isRecentTaskInvisible);
task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */,
ANIMATION_TYPE_RECENTS);
ANIMATION_TYPE_RECENTS, finishedCallback);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
return taskAdapter;
@@ -489,6 +514,49 @@ public class RecentsAnimationController implements DeathRecipient {
}
}
void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) {
if (mRunner != null) {
final RemoteAnimationTarget target = createTaskRemoteAnimation(task, finishedCallback);
if (target == null) return;
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target);
try {
mRunner.onTaskAppeared(target);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to report task appeared", e);
}
}
}
private RemoteAnimationTarget createTaskRemoteAnimation(Task task,
OnAnimationFinishedCallback finishedCallback) {
final SparseBooleanArray recentTaskIds =
mService.mAtmService.getRecentTasks().getRecentTaskIds();
TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
!recentTaskIds.get(task.mTaskId), finishedCallback);
mPendingNewTaskTargets.add(task.mTaskId);
return adapter.createRemoteAnimationTarget();
}
private boolean removeTaskInternal(int taskId) {
boolean result = false;
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
// Only allows when task target has became visible to user, to prevent
// the flickering during remove animation and task visible.
final TaskAnimationAdapter target = mPendingAnimations.get(i);
if (target.mTask.mTaskId == taskId && target.mTask.isOnTop()) {
removeAnimation(target);
final int taskIndex = mPendingNewTaskTargets.indexOf(taskId);
if (taskIndex != -1) {
mPendingNewTaskTargets.remove(taskIndex);
}
result = true;
break;
}
}
return result;
}
private RemoteAnimationTarget[] createAppAnimations() {
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {

View File

@@ -66,6 +66,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT;
import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER;
import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES;
@@ -1514,6 +1515,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Updates the extra information of the intent.
if (fromHomeKey) {
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
}
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.

View File

@@ -86,6 +86,8 @@ import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK;
@@ -135,6 +137,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
@@ -3401,6 +3404,24 @@ class Task extends WindowContainer<WindowContainer> {
}
}
@Override
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
int transit, boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback finishedCallback) {
final RecentsAnimationController control = mWmService.getRecentsAnimationController();
if (control != null && enter
&& getDisplayContent().mAppTransition.isNextAppTransitionCustomFromRecents()) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s",
control, asTask(), AppTransition.appTransitionToString(transit));
// We let the transition to be controlled by RecentsAnimation, and callback task's
// RemoteAnimationTarget for remote runner to animate.
control.addTaskToTargets(getRootTask(), finishedCallback);
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
}
}
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);

View File

@@ -2076,8 +2076,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @see #getAnimationAdapter
*/
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
boolean isVoiceInteraction, @Nullable OnAnimationFinishedCallback finishedCallback) {
if (mWmService.mDisableTransitionAnimation) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: transition animation is disabled or skipped. "
@@ -2092,22 +2091,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
if (okToAnimate()) {
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
transit, enter, isVoiceInteraction);
AnimationAdapter adapter = adapters.first;
AnimationAdapter thumbnailAdapter = adapters.second;
if (adapter != null) {
startAnimation(getPendingTransaction(), adapter, !isVisible(),
ANIMATION_TYPE_APP_TRANSITION, animationFinishedCallback);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
if (thumbnailAdapter != null) {
mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION,
(type, anim) -> { });
}
}
applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
} else {
cancelAnimation();
}
@@ -2201,6 +2185,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return resultAdapters;
}
protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
int transit, boolean isVoiceInteraction,
@Nullable OnAnimationFinishedCallback finishedCallback) {
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
transit, enter, isVoiceInteraction);
AnimationAdapter adapter = adapters.first;
AnimationAdapter thumbnailAdapter = adapters.second;
if (adapter != null) {
startAnimation(getPendingTransaction(), adapter, !isVisible(),
ANIMATION_TYPE_APP_TRANSITION, finishedCallback);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
if (thumbnailAdapter != null) {
mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
}
}
}
final SurfaceAnimationRunner getSurfaceAnimationRunner() {
return mWmService.mSurfaceAnimationRunner;
}

View File

@@ -238,9 +238,6 @@ public class RecentsAnimationTest extends ActivityTestsBase {
assertTrue(targetActivity.mLaunchTaskBehind);
anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome");
// The current top activity is not the recents so the animation should be canceled.
verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any() /* reason */);
// The test uses mocked RecentsAnimationController so we have to invoke the callback
// manually to simulate the flow.
@@ -279,10 +276,6 @@ public class RecentsAnimationTest extends ActivityTestsBase {
fullscreenStack.moveToFront("Activity start");
// Ensure that the recents animation was canceled by cancelAnimationSynchronously().
verify(mService.mWindowManager, times(1)).cancelRecentsAnimation(
eq(REORDER_KEEP_IN_PLACE), any());
// Assume recents animation already started, set a state that cancel recents animation
// with screenshot.
doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();