[Shell Transition] Schedule another transition to update visibility.
Activity could call setTranslucent during a transition playing, if the task of an activity was in transition and that activity should become invisible, it would be defer until transition finish. However, since the activity wasn't participant the running transition, there won't do commitVisibility for it after transition finish. To correct the visibility status, trigger another transition so the activities which visibility changed can be collect and commit. Bug: 246518648 Test: atest testConvertTranslucentOnTranslucentActivity Test: atest testConvertTranslucentOnNonTopTranslucentActivity Change-Id: Ic1cda79da37162cca2a1a3fbc73311cc325b3874
This commit is contained in:
committed by
Wei Sheng Shih
parent
cee1239a5a
commit
66e601fb13
@@ -132,8 +132,11 @@ public final class TransitionInfo implements Parcelable {
|
||||
*/
|
||||
public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14;
|
||||
|
||||
/** This change happened underneath something else. */
|
||||
public static final int FLAG_IS_OCCLUDED = 1 << 15;
|
||||
|
||||
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
|
||||
public static final int FLAG_FIRST_CUSTOM = 1 << 15;
|
||||
public static final int FLAG_FIRST_CUSTOM = 1 << 16;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "FLAG_" }, value = {
|
||||
@@ -153,6 +156,7 @@ public final class TransitionInfo implements Parcelable {
|
||||
FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
|
||||
FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
|
||||
FLAG_IS_BEHIND_STARTING_WINDOW,
|
||||
FLAG_IS_OCCLUDED,
|
||||
FLAG_FIRST_CUSTOM
|
||||
})
|
||||
public @interface ChangeFlags {}
|
||||
@@ -362,6 +366,9 @@ public final class TransitionInfo implements Parcelable {
|
||||
if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) {
|
||||
sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW");
|
||||
}
|
||||
if ((flags & FLAG_IS_OCCLUDED) != 0) {
|
||||
sb.append(sb.length() == 0 ? "" : "|").append("IS_OCCLUDED");
|
||||
}
|
||||
if ((flags & FLAG_FIRST_CUSTOM) != 0) {
|
||||
sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
import static android.view.WindowManager.fixScale;
|
||||
import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
|
||||
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
|
||||
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
|
||||
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
|
||||
@@ -441,32 +442,35 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
return;
|
||||
}
|
||||
|
||||
// apply transfer starting window directly if there is no other task change. Since this
|
||||
// is an activity->activity situation, we can detect it by selecting transitions with only
|
||||
// 2 changes where neither are tasks and one is a starting-window recipient.
|
||||
final int changeSize = info.getChanges().size();
|
||||
if (changeSize == 2) {
|
||||
boolean nonTaskChange = true;
|
||||
boolean transferStartingWindow = false;
|
||||
for (int i = changeSize - 1; i >= 0; --i) {
|
||||
final TransitionInfo.Change change = info.getChanges().get(i);
|
||||
if (change.getTaskInfo() != null) {
|
||||
nonTaskChange = false;
|
||||
break;
|
||||
}
|
||||
if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
|
||||
transferStartingWindow = true;
|
||||
}
|
||||
}
|
||||
if (nonTaskChange && transferStartingWindow) {
|
||||
t.apply();
|
||||
finishT.apply();
|
||||
// Treat this as an abort since we are bypassing any merge logic and effectively
|
||||
// finishing immediately.
|
||||
onAbort(transitionToken);
|
||||
return;
|
||||
boolean taskChange = false;
|
||||
boolean transferStartingWindow = false;
|
||||
boolean allOccluded = changeSize > 0;
|
||||
for (int i = changeSize - 1; i >= 0; --i) {
|
||||
final TransitionInfo.Change change = info.getChanges().get(i);
|
||||
taskChange |= change.getTaskInfo() != null;
|
||||
transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
|
||||
if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
|
||||
allOccluded = false;
|
||||
}
|
||||
}
|
||||
// There does not need animation when:
|
||||
// A. Transfer starting window. Apply transfer starting window directly if there is no other
|
||||
// task change. Since this is an activity->activity situation, we can detect it by selecting
|
||||
// transitions with only 2 changes where neither are tasks and one is a starting-window
|
||||
// recipient.
|
||||
if (!taskChange && transferStartingWindow && changeSize == 2
|
||||
// B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
|
||||
// changes are underneath another change.
|
||||
|| ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
|
||||
&& allOccluded)) {
|
||||
t.apply();
|
||||
finishT.apply();
|
||||
// Treat this as an abort since we are bypassing any merge logic and effectively
|
||||
// finishing immediately.
|
||||
onAbort(transitionToken);
|
||||
return;
|
||||
}
|
||||
|
||||
final ActiveTransition active = mActiveTransitions.get(activeIdx);
|
||||
active.mInfo = info;
|
||||
|
||||
@@ -27,6 +27,8 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||
import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
|
||||
@@ -707,7 +709,26 @@ class ActivityClientController extends IActivityClientController.Stub {
|
||||
try {
|
||||
synchronized (mGlobalLock) {
|
||||
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
|
||||
return r != null && r.setOccludesParent(true);
|
||||
// Create a transition if the activity is playing in case the below activity didn't
|
||||
// commit invisible. That's because if any activity below this one has changed its
|
||||
// visibility while playing transition, there won't able to commit visibility until
|
||||
// the running transition finish.
|
||||
final Transition transition = r != null
|
||||
&& r.mTransitionController.inPlayingTransition(r)
|
||||
? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null;
|
||||
if (transition != null) {
|
||||
r.mTransitionController.requestStartTransition(transition, null /*startTask */,
|
||||
null /* remoteTransition */, null /* displayChange */);
|
||||
}
|
||||
final boolean changed = r != null && r.setOccludesParent(true);
|
||||
if (transition != null) {
|
||||
if (changed) {
|
||||
r.mTransitionController.setReady(r.getDisplayContent());
|
||||
} else {
|
||||
transition.abort();
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
@@ -728,7 +749,25 @@ class ActivityClientController extends IActivityClientController.Stub {
|
||||
if (under != null) {
|
||||
under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
|
||||
}
|
||||
return r.setOccludesParent(false);
|
||||
// Create a transition if the activity is playing in case the current activity
|
||||
// didn't commit invisible. That's because if this activity has changed its
|
||||
// visibility while playing transition, there won't able to commit visibility until
|
||||
// the running transition finish.
|
||||
final Transition transition = r.mTransitionController.inPlayingTransition(r)
|
||||
? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null;
|
||||
if (transition != null) {
|
||||
r.mTransitionController.requestStartTransition(transition, null /*startTask */,
|
||||
null /* remoteTransition */, null /* displayChange */);
|
||||
}
|
||||
final boolean changed = r.setOccludesParent(false);
|
||||
if (transition != null) {
|
||||
if (changed) {
|
||||
r.mTransitionController.setReady(r.getDisplayContent());
|
||||
} else {
|
||||
transition.abort();
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
|
||||
@@ -120,6 +120,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_UNSET;
|
||||
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
|
||||
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
|
||||
@@ -658,7 +660,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
|
||||
new WindowState.UpdateReportedVisibilityResults();
|
||||
|
||||
boolean mUseTransferredAnimation;
|
||||
int mTransitionChangeFlags;
|
||||
|
||||
/** Whether we need to setup the animation to animate only within the letterbox. */
|
||||
private boolean mNeedsLetterboxedAnimation;
|
||||
@@ -4395,10 +4397,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// When transferring an animation, we no longer need to apply an animation to
|
||||
// the token we transfer the animation over. Thus, set this flag to indicate
|
||||
// we've transferred the animation.
|
||||
mUseTransferredAnimation = true;
|
||||
mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
} else if (mTransitionController.getTransitionPlayer() != null) {
|
||||
// In the new transit system, just set this every time we transfer the window
|
||||
mUseTransferredAnimation = true;
|
||||
mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
}
|
||||
// Post cleanup after the visibility and animation are transferred.
|
||||
fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
|
||||
@@ -5247,6 +5249,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
|
||||
// If in a transition, defer commits for activities that are going invisible
|
||||
if (!visible && inTransition()) {
|
||||
if (mTransitionController.inPlayingTransition(this)
|
||||
&& mTransitionController.isCollecting(this)) {
|
||||
mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// If we are preparing an app transition, then delay changing
|
||||
@@ -5297,7 +5303,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
@Override
|
||||
boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter,
|
||||
boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
|
||||
if (mUseTransferredAnimation) {
|
||||
if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
|
||||
return false;
|
||||
}
|
||||
// If it was set to true, reset the last request to force the transition.
|
||||
@@ -5370,7 +5376,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
mWmService.mWindowPlacerLocked.performSurfacePlacement();
|
||||
}
|
||||
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
|
||||
mUseTransferredAnimation = false;
|
||||
mTransitionChangeFlags = 0;
|
||||
|
||||
postApplyAnimation(visible, fromTransition);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
|
||||
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
|
||||
import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
|
||||
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
|
||||
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
|
||||
import static android.window.TransitionInfo.FLAG_WILL_IME_SHOWN;
|
||||
|
||||
@@ -1879,12 +1878,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
|
||||
final ActivityRecord record = wc.asActivityRecord();
|
||||
if (record != null) {
|
||||
parentTask = record.getTask();
|
||||
if (record.mUseTransferredAnimation) {
|
||||
flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||
}
|
||||
if (record.mVoiceInteraction) {
|
||||
flags |= FLAG_IS_VOICE_INTERACTION;
|
||||
}
|
||||
flags |= record.mTransitionChangeFlags;
|
||||
}
|
||||
final TaskFragment taskFragment = wc.asTaskFragment();
|
||||
if (taskFragment != null && task == null) {
|
||||
|
||||
Reference in New Issue
Block a user