Some fixes to shell transitions lifecycle handling

Added a remote transitionfilter for container ordering. This way
launcher animation won't engage if it is appearing behind a
translucent task.

Modify commitVisibility to properly update client visibility
when shell transitions are enabled.

Fixed issue where activity start was deferring sync-engine
readiness even for "delivered-to-top" or cancelled activity
starts. This meant it would wait forever.

Hooked up the "enter animation complete" reporting to shell
transitions.

Removed interference by legacy freeform/maximize animation
logic (which was calling setReady at incorrect times).

Bug: 183993924
Test: atest ActivityLifecycleTests
Change-Id: I1138079b1ae05248cefa211e0597fd6723a8bbba
This commit is contained in:
Evan Rosky
2021-06-03 09:10:20 -07:00
parent f01e33f152
commit 6173c26649
6 changed files with 72 additions and 20 deletions

View File

@@ -18,6 +18,7 @@ package android.window;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
@@ -33,6 +34,18 @@ import android.os.Parcelable;
*/
public final class TransitionFilter implements Parcelable {
/** The associated requirement doesn't care about the z-order. */
public static final int CONTAINER_ORDER_ANY = 0;
/** The associated requirement only matches the top-most (z-order) container. */
public static final int CONTAINER_ORDER_TOP = 1;
/** @hide */
@IntDef(prefix = { "CONTAINER_ORDER_" }, value = {
CONTAINER_ORDER_ANY,
CONTAINER_ORDER_TOP,
})
public @interface ContainerOrder {}
/**
* When non-null: this is a list of transition types that this filter applies to. This filter
* will fail for transitions that aren't one of these types.
@@ -126,6 +139,7 @@ public final class TransitionFilter implements Parcelable {
public static final class Requirement implements Parcelable {
public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
public int[] mModes = null;
public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
public Requirement() {
}
@@ -133,6 +147,7 @@ public final class TransitionFilter implements Parcelable {
private Requirement(Parcel in) {
mActivityType = in.readInt();
mModes = in.createIntArray();
mOrder = in.readInt();
}
/** Go through changes and find if at-least one change matches this filter */
@@ -143,6 +158,9 @@ public final class TransitionFilter implements Parcelable {
// Only look at independent animating windows.
continue;
}
if (mOrder == CONTAINER_ORDER_TOP && i > 0) {
continue;
}
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
if (change.getTaskInfo() == null
|| change.getTaskInfo().getActivityType() != mActivityType) {
@@ -166,7 +184,7 @@ public final class TransitionFilter implements Parcelable {
/** Check if the request matches this filter. It may generate false positives */
boolean matches(@NonNull TransitionRequestInfo request) {
// Can't check modes since the transition hasn't been built at this point.
// Can't check modes/order since the transition hasn't been built at this point.
if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true;
return request.getTriggerTask() != null
&& request.getTriggerTask().getActivityType() == mActivityType;
@@ -177,6 +195,7 @@ public final class TransitionFilter implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mActivityType);
dest.writeIntArray(mModes);
dest.writeInt(mOrder);
}
@NonNull
@@ -209,7 +228,17 @@ public final class TransitionFilter implements Parcelable {
out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i]));
}
}
return out.append("]}").toString();
out.append("]").toString();
out.append(" order=" + containerOrderToString(mOrder));
return out.toString();
}
}
private static String containerOrderToString(int order) {
switch (order) {
case CONTAINER_ORDER_ANY: return "ANY";
case CONTAINER_ORDER_TOP: return "TOP";
}
return "UNKNOWN(" + order + ")";
}
}

View File

@@ -17,10 +17,12 @@
package com.android.systemui.shared.system;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionFilter.CONTAINER_ORDER_TOP;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -163,9 +165,13 @@ public class RemoteTransitionCompat implements Parcelable {
mFilter = new TransitionFilter();
}
mFilter.mRequirements =
new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(),
new TransitionFilter.Requirement()};
mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
mFilter.mRequirements[0].mOrder = CONTAINER_ORDER_TOP;
mFilter.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD;
mFilter.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
}
/**

View File

@@ -4817,9 +4817,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* this has become invisible.
*/
private void postApplyAnimation(boolean visible) {
final boolean usingShellTransitions =
mAtmService.getTransitionController().getTransitionPlayer() != null;
final boolean delayed = isAnimating(PARENTS | CHILDREN,
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
if (!delayed) {
if (!delayed && !usingShellTransitions) {
// We aren't delayed anything, but exiting windows rely on the animation finished
// callback being called in case the ActivityRecord was pretending to be delayed,
// which we might have done because we were in closing/opening apps list.
@@ -4838,7 +4840,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// updated.
// If we're becoming invisible, update the client visibility if we are not running an
// animation. Otherwise, we'll update client visibility in onAnimationFinished.
if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)
|| usingShellTransitions) {
setClientVisible(visible);
}

View File

@@ -1586,7 +1586,8 @@ class ActivityStarter {
statusBar.collapsePanels();
}
}
if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT;
if (started) {
// The activity is started new rather than just brought forward, so record
// it as an existence change.
mService.getTransitionController().collectExistenceChange(r);
@@ -1594,7 +1595,7 @@ class ActivityStarter {
if (newTransition != null) {
mService.getTransitionController().requestStartTransition(newTransition,
mTargetTask, remoteTransition);
} else {
} else if (started) {
// Make the collecting transition wait until this request is ready.
mService.getTransitionController().setReady(false);
}

View File

@@ -297,21 +297,27 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
// Commit all going-invisible containers
boolean activitiesWentInvisible = false;
for (int i = 0; i < mParticipants.size(); ++i) {
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
if (ar != null && !ar.isVisibleRequested()) {
// If activity is capable of entering PiP, give it a chance to enter it now.
if (ar.getDeferHidingClient() && ar.getTask() != null) {
mController.mAtm.mTaskSupervisor.mUserLeaving = true;
ar.getTaskFragment().startPausing(false /* uiSleeping */, null /* resuming */,
"finishTransition");
mController.mAtm.mTaskSupervisor.mUserLeaving = false;
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
ar.commitVisibility(false /* visible */, false /* performLayout */);
}
if (ar != null) {
if (!ar.isVisibleRequested()) {
// If activity is capable of entering PiP, give it a chance to enter it now.
if (ar.getDeferHidingClient() && ar.getTask() != null) {
mController.mAtm.mTaskSupervisor.mUserLeaving = true;
ar.getTaskFragment().startPausing(false /* uiSleeping */,
null /* resuming */, "finishTransition");
mController.mAtm.mTaskSupervisor.mUserLeaving = false;
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
ar.commitVisibility(false /* visible */, false /* performLayout */);
activitiesWentInvisible = true;
}
if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) {
// Legacy dispatch relies on this (for now).
ar.mEnteringAnimation = ar.isVisibleRequested();
}
mController.dispatchLegacyAppTransitionFinished(ar);
}
final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
@@ -321,6 +327,12 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
wt.commitVisibility(false /* visible */);
}
}
if (activitiesWentInvisible) {
// Always schedule stop processing when transition finishes because activities don't
// stop while they are in a transition thus their stop could still be pending.
mController.mAtm.mTaskSupervisor
.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
}
legacyRestoreNavigationBarFromApp();
}

View File

@@ -1806,7 +1806,8 @@ public class WindowManagerService extends IWindowManager.Stub
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
// Check if we need to prepare a transition for replacing window first.
if (activity != null && activity.isVisible()
if (mAtmService.getTransitionController().getTransitionPlayer() == null
&& activity != null && activity.isVisible()
&& !prepareWindowReplacementTransition(activity)) {
// If not, check if need to set up a dummy transition during display freeze
// so that the unfreeze wait for the apps to draw. This might be needed if