summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Wei Sheng Shih <wilsonshih@google.com> 2023-12-06 10:14:30 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-12-06 10:14:30 +0000
commitc1eff37d21f21096cb0f2ea53c55474d53f4308a (patch)
treefda22413614f8f3d73a0a31ef2ebb435a5feb905
parentb5fca8403047015923807cf94b9049002d1930f2 (diff)
parentb3c1f2da8005249c5c3e91c49fd0bce01be1b447 (diff)
Merge "Support to close two TaskFragments in predict back animation" into main
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java102
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java104
2 files changed, 176 insertions, 30 deletions
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index be7b8559e39e..c5902c965b43 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -395,7 +395,8 @@ class BackNavigationController {
*
* @return false if unable to predict what will happen
*/
- private static boolean getAnimatablePrevActivities(@NonNull Task currentTask,
+ @VisibleForTesting
+ static boolean getAnimatablePrevActivities(@NonNull Task currentTask,
@NonNull ActivityRecord currentActivity,
@NonNull ArrayList<ActivityRecord> outPrevActivities) {
if (currentActivity.mAtmService
@@ -413,45 +414,86 @@ class BackNavigationController {
// Searching previous
final ActivityRecord prevActivity = currentTask.getActivity((below) -> !below.finishing,
currentActivity, false /*includeBoundary*/, true /*traverseTopToBottom*/);
- if (prevActivity == null) {
- // No previous activity in this task, can still predict if previous task exists.
- return true;
- }
- if (currentTask.getActivity((above) -> !above.finishing, currentActivity,
- false /*includeBoundary*/, false /*traverseTopToBottom*/) != null) {
- // another activity is above this activity, don't know what will happen
- return false;
- }
final TaskFragment currTF = currentActivity.getTaskFragment();
- final TaskFragment prevTF = prevActivity.getTaskFragment();
- if (currTF != prevTF && prevTF != null) {
- final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment();
- if (prevTFAdjacent != null) {
- if (prevTFAdjacent == currTF) {
- outPrevActivities.clear();
- // No more activity in task, so it can predict if previous task exists.
- // Otherwise, unable to predict what will happen when app receive
- // back key, skip animation.
- return currentTask.getActivity((below) -> !below.finishing, prevActivity,
+ if (currTF != null && currTF.asTask() == null) {
+ // The currentActivity is embedded, search for the candidate previous activities.
+ if (prevActivity != null && currTF.hasChild(prevActivity)) {
+ // PrevActivity is under the same task fragment, that's it.
+ outPrevActivities.add(prevActivity);
+ return true;
+ }
+ if (currTF.getAdjacentTaskFragment() != null) {
+ // The two TFs are adjacent (visually displayed side-by-side), search if any
+ // activity below the lowest one
+ // If companion, those two TF will be closed together.
+ if (currTF.getCompanionTaskFragment() != null) {
+ final WindowContainer commonParent = currTF.getParent();
+ final TaskFragment adjacentTF = currTF.getAdjacentTaskFragment();
+ final TaskFragment lowerTF = commonParent.mChildren.indexOf(currTF)
+ < commonParent.mChildren.indexOf(adjacentTF)
+ ? currTF : adjacentTF;
+ final ActivityRecord lowerActivity = lowerTF.getTopNonFinishingActivity();
+ // TODO (b/274997067) close currTF + companionTF, open next activities if any.
+ // Allow to predict next task if no more activity in task. Or return previous
+ // activities for cross-activity animation.
+ return currentTask.getActivity((below) -> !below.finishing, lowerActivity,
false /*includeBoundary*/, true /*traverseTopToBottom*/) == null;
- } else {
- final ActivityRecord prevActivityAdjacent =
- prevTFAdjacent.getTopNonFinishingActivity();
- if (prevActivityAdjacent != null) {
- outPrevActivities.add(prevActivityAdjacent);
- } else {
- // Don't know what will happen.
- outPrevActivities.clear();
- return false;
- }
}
+ // Unable to predict if no companion, it can only close current activity and make
+ // prev Activity full screened.
+ return false;
+ } else if (currTF.getCompanionTaskFragment() != null) {
+ // TF is isStacked, search bottom activity from companion TF.
+ //
+ // Sample hierarchy: search for underPrevious if any.
+ // Current TF
+ // Companion TF (bottomActivityInCompanion)
+ // Bottom Activity not inside companion TF (underPrevious)
+ final TaskFragment companionTF = currTF.getCompanionTaskFragment();
+ // find bottom activity in Companion TF.
+ final ActivityRecord bottomActivityInCompanion = companionTF.getActivity(
+ (below) -> !below.finishing, false /* traverseTopToBottom */);
+ final ActivityRecord underPrevious = currentTask.getActivity(
+ (below) -> !below.finishing, bottomActivityInCompanion,
+ false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ if (underPrevious != null) {
+ outPrevActivities.add(underPrevious);
+ addPreviousAdjacentActivityIfExist(underPrevious, outPrevActivities);
+ }
+ return true;
}
}
+
+ if (prevActivity == null) {
+ // No previous activity in this Task nor TaskFragment, it can still predict if previous
+ // task exists.
+ return true;
+ }
+ // Add possible adjacent activity if prevActivity is embedded
+ addPreviousAdjacentActivityIfExist(prevActivity, outPrevActivities);
outPrevActivities.add(prevActivity);
return true;
}
+ private static void addPreviousAdjacentActivityIfExist(@NonNull ActivityRecord prevActivity,
+ @NonNull ArrayList<ActivityRecord> outPrevActivities) {
+ final TaskFragment prevTF = prevActivity.getTaskFragment();
+ if (prevTF == null || prevTF.asTask() != null) {
+ return;
+ }
+
+ final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment();
+ if (prevTFAdjacent == null || prevTFAdjacent.asTask() != null) {
+ return;
+ }
+ final ActivityRecord prevActivityAdjacent =
+ prevTFAdjacent.getTopNonFinishingActivity();
+ if (prevActivityAdjacent != null) {
+ outPrevActivities.add(prevActivityAdjacent);
+ }
+ }
+
private static void findAdjacentActivityIfExist(@NonNull ActivityRecord mainActivity,
@NonNull ArrayList<ActivityRecord> outList) {
final TaskFragment mainTF = mainActivity.getTaskFragment();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index afea8114d508..4d4d397585b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -242,6 +242,110 @@ public class BackNavigationControllerTests extends WindowTestsBase {
}
@Test
+ public void backTypeCrossActivityInTaskFragment() {
+ final Task task = createTask(mDefaultDisplay);
+ final TaskFragment tf1 = createTaskFragmentWithActivity(task);
+ final TaskFragment tf2 = createTaskFragmentWithActivity(task);
+ final ArrayList<ActivityRecord> outPrevActivities = new ArrayList<>();
+
+ ActivityRecord prevAr = tf1.getTopMostActivity();
+ ActivityRecord topAr = tf2.getTopMostActivity();
+ boolean predictable;
+
+ // Stacked + no Companion => predict for previous activity.
+ // TF2
+ // TF1
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ outPrevActivities.clear();
+
+ // Stacked + companion => predict for previous task
+ tf2.setCompanionTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ tf2.setCompanionTaskFragment(null);
+
+ // Adjacent + no companion => unable to predict
+ // TF1 | TF2
+ tf1.setAdjacentTaskFragment(tf2);
+ tf2.setAdjacentTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertFalse(predictable);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, prevAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertFalse(predictable);
+
+ // Adjacent + companion => predict for previous task
+ tf1.setCompanionTaskFragment(tf2);
+ tf2.setCompanionTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, prevAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ // reset
+ tf1.setAdjacentTaskFragment(null);
+ tf2.setAdjacentTaskFragment(null);
+ tf1.setCompanionTaskFragment(null);
+ tf2.setCompanionTaskFragment(null);
+
+ final TaskFragment tf3 = new TaskFragmentBuilder(mAtm)
+ .createActivityCount(2)
+ .setParentTask(task)
+ .build();
+ topAr = tf3.getTopMostActivity();
+ prevAr = tf3.getBottomMostActivity();
+ // Stacked => predict for previous activity.
+ // TF3
+ // TF2
+ // TF1
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ // reset
+ outPrevActivities.clear();
+
+ // Adjacent => predict for previous activity.
+ // TF2 | TF3
+ // TF1
+ tf2.setAdjacentTaskFragment(tf3);
+ tf3.setAdjacentTaskFragment(tf2);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ // reset
+ outPrevActivities.clear();
+ tf2.setAdjacentTaskFragment(null);
+ tf3.setAdjacentTaskFragment(null);
+
+ final TaskFragment tf4 = createTaskFragmentWithActivity(task);
+ // Stacked + companion => predict for previous activity below companion.
+ // Tf4
+ // TF3
+ // TF2
+ // TF1
+ tf4.setCompanionTaskFragment(tf3);
+ tf3.setCompanionTaskFragment(tf4);
+ topAr = tf4.getTopMostActivity();
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(tf2.getTopMostActivity()));
+ assertTrue(predictable);
+ }
+
+ @Test
public void backTypeDialogCloseWhenBackFromDialog() {
DialogCloseTestCase testCase = createTopTaskWithActivityAndDialog();
IOnBackInvokedCallback callback = withSystemCallback(testCase.task);