Merge "Check finishing opaque activity for closing TaskFragment"

This commit is contained in:
Chris Li
2023-02-14 03:14:57 +00:00
committed by Android (Google) Code Review
3 changed files with 230 additions and 40 deletions

View File

@@ -904,37 +904,46 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* starting (about to be visible) activity that is fullscreen (opaque).
* @param starting The currently starting activity or null if there is none.
*/
@VisibleForTesting
boolean isTranslucent(ActivityRecord starting) {
boolean isTranslucent(@Nullable ActivityRecord starting) {
if (!isAttached() || isForceHidden() || isForceTranslucent()) {
return true;
}
final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
PooledLambda.__(ActivityRecord.class), starting);
PooledLambda.__(ActivityRecord.class), starting, false /* including*/);
final ActivityRecord opaque = getActivity(p);
p.recycle();
return opaque == null;
}
private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
if (r.finishing) {
// We don't factor in finishing activities when determining translucency since
// they will be gone soon.
return false;
/**
* Whether the TaskFragment should be treated as translucent for the current transition.
* This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks
* finishing activities when the TaskFragment itself is becoming invisible.
*/
boolean isTranslucentForTransition() {
if (!isAttached() || isForceHidden() || isForceTranslucent()) {
return true;
}
// Including finishing Activity if the TaskFragment is becoming invisible in the transition.
final boolean includingFinishing = !isVisibleRequested();
final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
PooledLambda.__(ActivityRecord.class), null /* starting */, includingFinishing);
final ActivityRecord opaque = getActivity(p);
p.recycle();
return opaque == null;
}
private static boolean isOpaqueActivity(@NonNull ActivityRecord r,
@Nullable ActivityRecord starting, boolean includingFinishing) {
if (!r.visibleIgnoringKeyguard && r != starting) {
// Also ignore invisible activities that are not the currently starting
// activity (about to be visible).
return false;
}
if (r.occludesParent()) {
// Root task isn't translucent if it has at least one fullscreen activity
// that is visible.
return true;
}
return false;
// TaskFragment isn't translucent if it has at least one fullscreen activity that is
// visible.
return r.occludesParent(includingFinishing);
}
ActivityRecord getTopNonFinishingActivity() {

View File

@@ -1447,22 +1447,25 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
private static boolean isTranslucent(@NonNull WindowContainer wc) {
final TaskFragment taskFragment = wc.asTaskFragment();
if (taskFragment != null) {
if (taskFragment.isTranslucent(null /* starting */)) {
return true;
}
final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
if (adjacentTaskFragment != null) {
// Treat the TaskFragment as translucent if its adjacent TF is, otherwise everything
// behind two adjacent TaskFragments are occluded.
return adjacentTaskFragment.isTranslucent(null /* starting */);
}
if (taskFragment == null) {
return !wc.fillsParent();
}
// Check containers differently as they are affected by child visibility.
if (taskFragment.isTranslucentForTransition()) {
// TaskFragment doesn't contain occluded ActivityRecord.
return true;
}
final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
if (adjacentTaskFragment != null) {
// When the TaskFragment has an adjacent TaskFragment, sibling behind them should be
// hidden unless any of them are translucent.
return adjacentTaskFragment.isTranslucentForTransition();
} else {
// Non-filling without adjacent is considered as translucent.
return !wc.fillsParent();
}
// TODO(b/172695805): hierarchical check. This is non-trivial because for containers
// it is effected by child visibility but needs to work even
// before visibility is committed. This means refactoring some
// checks to use requested visibility.
return !wc.fillsParent();
}
/**

View File

@@ -704,15 +704,15 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task newTask = createTask(mDisplayContent);
doReturn(false).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
doReturn(false).when(oldTask).isTranslucent(any());
final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
opening.setOccludesParent(false);
opening.setOccludesParent(true);
opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -735,8 +735,8 @@ public class TransitionTests extends WindowTestsBase {
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) == 0);
assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
@@ -745,15 +745,15 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task newTask = createTask(mDisplayContent);
doReturn(true).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
doReturn(false).when(oldTask).isTranslucent(any());
final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
opening.setOccludesParent(false);
opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -776,8 +776,186 @@ public class TransitionTests extends WindowTestsBase {
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) != 0);
assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
public void testOpenOpaqueTaskFragment() {
final Transition transition = createTestTransition(TRANSIT_OPEN);
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task task = createTask(mDisplayContent);
final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
closing.setOccludesParent(true);
closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
opening.setOccludesParent(true);
opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
false /* vis */, true /* exChg */));
changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
true /* vis */, false /* exChg */));
changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
fillChangeMap(changes, openingTaskFragment);
// End states.
closing.setVisibleRequested(false);
opening.setVisibleRequested(true);
final int transit = transition.mType;
int flags = 0;
// Check basic both tasks participating
participants.add(closingTaskFragment);
participants.add(openingTaskFragment);
ArrayList<Transition.ChangeInfo> targets =
Transition.calculateTargets(participants, changes);
TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
public void testOpenTranslucentTaskFragment() {
final Transition transition = createTestTransition(TRANSIT_OPEN);
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task task = createTask(mDisplayContent);
final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
closing.setOccludesParent(true);
closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
opening.setOccludesParent(false);
opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
false /* vis */, true /* exChg */));
changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
true /* vis */, false /* exChg */));
changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
fillChangeMap(changes, openingTaskFragment);
// End states.
closing.setVisibleRequested(false);
opening.setVisibleRequested(true);
final int transit = transition.mType;
int flags = 0;
// Check basic both tasks participating
participants.add(closingTaskFragment);
participants.add(openingTaskFragment);
ArrayList<Transition.ChangeInfo> targets =
Transition.calculateTargets(participants, changes);
TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
public void testCloseOpaqueTaskFragment_withFinishingActivity() {
final Transition transition = createTestTransition(TRANSIT_CLOSE);
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task task = createTask(mDisplayContent);
final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
opening.setOccludesParent(true);
opening.visibleIgnoringKeyguard = true;
final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
closing.setOccludesParent(true);
closing.visibleIgnoringKeyguard = true;
closing.finishing = true;
// Start states.
changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
false /* vis */, true /* exChg */));
changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
true /* vis */, false /* exChg */));
changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
fillChangeMap(changes, openingTaskFragment);
// End states.
closing.setVisibleRequested(false);
opening.setVisibleRequested(true);
final int transit = transition.mType;
int flags = 0;
// Check basic both tasks participating
participants.add(closingTaskFragment);
participants.add(openingTaskFragment);
ArrayList<Transition.ChangeInfo> targets =
Transition.calculateTargets(participants, changes);
TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
public void testCloseTranslucentTaskFragment_withFinishingActivity() {
final Transition transition = createTestTransition(TRANSIT_CLOSE);
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
final Task task = createTask(mDisplayContent);
final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
opening.setOccludesParent(true);
opening.visibleIgnoringKeyguard = true;
final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
closing.setOccludesParent(false);
closing.visibleIgnoringKeyguard = true;
closing.finishing = true;
// Start states.
changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
false /* vis */, true /* exChg */));
changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
true /* vis */, false /* exChg */));
changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
fillChangeMap(changes, openingTaskFragment);
// End states.
closing.setVisibleRequested(false);
opening.setVisibleRequested(true);
final int transit = transition.mType;
int flags = 0;
// Check basic both tasks participating
participants.add(closingTaskFragment);
participants.add(openingTaskFragment);
ArrayList<Transition.ChangeInfo> targets =
Transition.calculateTargets(participants, changes);
TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test