Merge "Keep visible requested for transient hide activities" into udc-dev
This commit is contained in:
@@ -1680,6 +1680,11 @@ class ActivityStarter {
|
||||
targetTask.removeImmediately("bulky-task");
|
||||
return START_ABORTED;
|
||||
}
|
||||
// When running transient transition, the transient launch target should keep on top.
|
||||
// So disallow the transient hide activity to move itself to front, e.g. trampoline.
|
||||
if (!mAvoidMoveToFront && r.mTransitionController.isTransientHide(targetTask)) {
|
||||
mAvoidMoveToFront = true;
|
||||
}
|
||||
mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());
|
||||
}
|
||||
|
||||
@@ -1796,7 +1801,7 @@ class ActivityStarter {
|
||||
// root-task to the will not update the focused root-task. If starting the new
|
||||
// activity now allows the task root-task to be focusable, then ensure that we
|
||||
// now update the focused root-task accordingly.
|
||||
if (mTargetRootTask.isTopActivityFocusable()
|
||||
if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
|
||||
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
|
||||
mTargetRootTask.moveToFront("startActivityInner");
|
||||
}
|
||||
|
||||
@@ -1012,6 +1012,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
if (isTopActivityLaunchedBehind()) {
|
||||
return TASK_FRAGMENT_VISIBILITY_VISIBLE;
|
||||
}
|
||||
final Task thisTask = asTask();
|
||||
if (thisTask != null && mTransitionController.isTransientHide(thisTask)) {
|
||||
return TASK_FRAGMENT_VISIBILITY_VISIBLE;
|
||||
}
|
||||
|
||||
boolean gotTranslucentFullscreen = false;
|
||||
boolean gotTranslucentAdjacent = false;
|
||||
|
||||
@@ -194,6 +194,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
*/
|
||||
private ArrayMap<ActivityRecord, Task> mTransientLaunches = null;
|
||||
|
||||
/**
|
||||
* The tasks that may be occluded by the transient activity. Assume the task stack is
|
||||
* [Home, A(opaque), B(opaque), C(translucent)] (bottom to top), then A is the restore-below
|
||||
* task, and [B, C] are the transient-hide tasks.
|
||||
*/
|
||||
private ArrayList<Task> mTransientHideTasks;
|
||||
|
||||
/** Custom activity-level animation options and callbacks. */
|
||||
private TransitionInfo.AnimationOptions mOverrideOptions;
|
||||
private IRemoteCallback mClientAnimationStartCallback = null;
|
||||
@@ -265,35 +272,51 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
void setTransientLaunch(@NonNull ActivityRecord activity, @Nullable Task restoreBelow) {
|
||||
if (mTransientLaunches == null) {
|
||||
mTransientLaunches = new ArrayMap<>();
|
||||
mTransientHideTasks = new ArrayList<>();
|
||||
}
|
||||
mTransientLaunches.put(activity, restoreBelow);
|
||||
setTransientLaunchToChanges(activity);
|
||||
|
||||
if (restoreBelow != null) {
|
||||
final ChangeInfo info = mChanges.get(restoreBelow);
|
||||
if (info != null) {
|
||||
info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
|
||||
// Collect all visible activities which can be occluded by the transient activity to
|
||||
// make sure they are in the participants so their visibilities can be updated when
|
||||
// finishing transition.
|
||||
((WindowContainer<?>) restoreBelow.getParent()).forAllTasks(t -> {
|
||||
if (t.isVisibleRequested() && !t.isAlwaysOnTop()
|
||||
&& !t.getWindowConfiguration().tasksAreFloating()) {
|
||||
if (t.isRootTask()) {
|
||||
mTransientHideTasks.add(t);
|
||||
}
|
||||
if (t.isLeafTask()) {
|
||||
t.forAllActivities(r -> {
|
||||
if (r.isVisibleRequested()) {
|
||||
collect(r);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return t == restoreBelow;
|
||||
});
|
||||
// Add FLAG_ABOVE_TRANSIENT_LAUNCH to the tree of transient-hide tasks,
|
||||
// so ChangeInfo#hasChanged() can return true to report the transition info.
|
||||
for (int i = mChanges.size() - 1; i >= 0; --i) {
|
||||
final WindowContainer<?> wc = mChanges.keyAt(i);
|
||||
if (wc.asTaskFragment() == null && wc.asActivityRecord() == null) continue;
|
||||
if (isInTransientHide(wc)) {
|
||||
mChanges.valueAt(i).mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
|
||||
+ "transient-launch", mSyncId, activity);
|
||||
}
|
||||
|
||||
boolean isTransientHide(@NonNull Task task) {
|
||||
if (mTransientLaunches == null) return false;
|
||||
for (int i = 0; i < mTransientLaunches.size(); ++i) {
|
||||
if (mTransientLaunches.valueAt(i) == task) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return whether `wc` is a descendent of a transient-hide window. */
|
||||
boolean isInTransientHide(@NonNull WindowContainer wc) {
|
||||
if (mTransientLaunches == null) return false;
|
||||
for (int i = 0; i < mTransientLaunches.size(); ++i) {
|
||||
if (wc.isDescendantOf(mTransientLaunches.valueAt(i))) {
|
||||
if (mTransientHideTasks == null) return false;
|
||||
for (int i = mTransientHideTasks.size() - 1; i >= 0; --i) {
|
||||
final Task task = mTransientHideTasks.get(i);
|
||||
if (wc == task || wc.isDescendantOf(task)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -816,6 +839,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
}
|
||||
mController.mFinishingTransition = this;
|
||||
|
||||
if (mTransientHideTasks != null && !mTransientHideTasks.isEmpty()) {
|
||||
// The transient hide tasks could be occluded now, e.g. returning to home. So trigger
|
||||
// the update to make the activities in the tasks invisible-requested, then the next
|
||||
// step can continue to commit the visibility.
|
||||
mController.mAtm.mRootWindowContainer.ensureActivitiesVisible(null /* starting */,
|
||||
0 /* configChanges */, true /* preserveWindows */);
|
||||
}
|
||||
|
||||
boolean hasParticipatedDisplay = false;
|
||||
boolean hasVisibleTransientLaunch = false;
|
||||
// Commit all going-invisible containers
|
||||
@@ -1175,14 +1206,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
|
||||
// Record windowtokens (activity/wallpaper) that are expected to be visible after the
|
||||
// transition animation. This will be used in finishTransition to prevent prematurely
|
||||
// committing visibility.
|
||||
for (int i = mParticipants.size() - 1; i >= 0; --i) {
|
||||
final WindowContainer wc = mParticipants.valueAt(i);
|
||||
if (wc.asWindowToken() == null || !wc.isVisibleRequested()) continue;
|
||||
// don't include transient launches, though, since those are only temporarily visible.
|
||||
if (mTransientLaunches != null && wc.asActivityRecord() != null
|
||||
&& mTransientLaunches.containsKey(wc.asActivityRecord())) continue;
|
||||
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
|
||||
// committing visibility. Skip transient launches since those are only temporarily visible.
|
||||
if (mTransientLaunches == null) {
|
||||
for (int i = mParticipants.size() - 1; i >= 0; --i) {
|
||||
final WindowContainer wc = mParticipants.valueAt(i);
|
||||
if (wc.asWindowToken() == null || !wc.isVisibleRequested()) continue;
|
||||
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
|
||||
}
|
||||
}
|
||||
|
||||
// Take task snapshots before the animation so that we can capture IME before it gets
|
||||
|
||||
@@ -366,11 +366,11 @@ class TransitionController {
|
||||
}
|
||||
|
||||
boolean isTransientHide(@NonNull Task task) {
|
||||
if (mCollectingTransition != null && mCollectingTransition.isTransientHide(task)) {
|
||||
if (mCollectingTransition != null && mCollectingTransition.isInTransientHide(task)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
|
||||
if (mPlayingTransitions.get(i).isTransientHide(task)) return true;
|
||||
if (mPlayingTransitions.get(i).isInTransientHide(task)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
|
||||
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
|
||||
import static android.window.TransitionInfo.isIndependent;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
@@ -54,6 +55,7 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -1400,7 +1402,13 @@ public class TransitionTests extends WindowTestsBase {
|
||||
closeTransition.collectExistenceChange(activity1);
|
||||
closeTransition.collectExistenceChange(task2);
|
||||
closeTransition.collectExistenceChange(activity2);
|
||||
closeTransition.setTransientLaunch(activity2, null /* restoreBelow */);
|
||||
closeTransition.setTransientLaunch(activity2, task1);
|
||||
final Transition.ChangeInfo task1ChangeInfo = closeTransition.mChanges.get(task1);
|
||||
assertNotNull(task1ChangeInfo);
|
||||
assertTrue(task1ChangeInfo.hasChanged());
|
||||
final Transition.ChangeInfo activity1ChangeInfo = closeTransition.mChanges.get(activity1);
|
||||
assertNotNull(activity1ChangeInfo);
|
||||
assertTrue(activity1ChangeInfo.hasChanged());
|
||||
|
||||
activity1.setVisibleRequested(false);
|
||||
activity2.setVisibleRequested(true);
|
||||
@@ -1416,6 +1424,8 @@ public class TransitionTests extends WindowTestsBase {
|
||||
verify(snapshotController, times(0)).recordSnapshot(eq(task1), eq(false));
|
||||
|
||||
enteringAnimReports.clear();
|
||||
doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(),
|
||||
anyInt(), anyBoolean(), anyBoolean());
|
||||
final boolean[] wasInFinishingTransition = { false };
|
||||
controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener() {
|
||||
@Override
|
||||
@@ -1430,7 +1440,11 @@ public class TransitionTests extends WindowTestsBase {
|
||||
assertTrue(wasInFinishingTransition[0]);
|
||||
assertNull(controller.mFinishingTransition);
|
||||
|
||||
assertTrue(activity2.isVisible());
|
||||
assertEquals(ActivityTaskManagerService.APP_SWITCH_DISALLOW, mAtm.getBalAppSwitchesState());
|
||||
// Because task1 is occluded by task2, finishTransition should make activity1 invisible.
|
||||
assertFalse(activity1.isVisibleRequested());
|
||||
assertFalse(activity1.isVisible());
|
||||
assertFalse(activity1.app.hasActivityInVisibleTask());
|
||||
|
||||
verify(snapshotController, times(1)).recordSnapshot(eq(task1), eq(false));
|
||||
|
||||
Reference in New Issue
Block a user