From 40fc6de5a7a44b86b459966a4208136c91fb0afb Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Fri, 6 Aug 2021 17:18:00 +0800 Subject: [PATCH] Keeps the intercepted activity on the existing secondary container When intercepting an activity start request, a new split pair was always created and launch the activity to the side of the caller activity. This CL launches the activity on top of the caller activity if the caller activity is already on the secondary container. This is needed for the case that the activity is started into a new Task, or new Task will be escaped from the current host Task and be displayed in fullscreen. However, the interception won't work if the activity is started from another process. Also adding logs for TaskFragment errors. Bug: 194997356 Test: manually, start activity with sample app Change-Id: I268c1dad191cdfdbf48cac84e18f1dfda761b0d3 --- data/etc/services.core.protolog.json | 6 ++ .../extensions/organizer/SplitController.java | 62 ++++++++++++++++++- .../wm/TaskFragmentOrganizerController.java | 3 + 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 8caff23539c31..b49b289d44c0a 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2599,6 +2599,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "743418423": { + "message": "Sending TaskFragment error exception=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + }, "744171317": { "message": " SKIP: %s", "level": "VERBOSE", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java index 802976fbfc6d9..d6c5f95032f36 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java @@ -686,10 +686,24 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final Activity launchingActivity = (Activity) who; + if (!setLaunchingToSideContainer(launchingActivity, intent, options)) { + setLaunchingInSameContainer(launchingActivity, intent, options); + } + + return super.onStartActivity(who, intent, options); + } + + /** + * Returns {@code true} if the activity that is going to be started via the + * {@code intent} should be paired with the {@code launchingActivity} and is set to be + * launched in an empty side container. + */ + private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent, + Bundle options) { final ExtensionSplitPairRule splitPairRule = getSplitRule( launchingActivity.getComponentName(), intent.getComponent(), getSplitRules()); if (splitPairRule == null) { - return super.onStartActivity(who, intent, options); + return false; } // Create a new split with an empty side container @@ -700,8 +714,52 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // dedicated container. options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN, secondaryContainer.getTaskFragmentToken()); + return true; + } - return super.onStartActivity(who, intent, options); + /** + * Checks if the activity that is going to be started via the {@code intent} should be + * paired with the existing top activity which is currently paired with the + * {@code launchingActivity}. If so, set the activity to be launched in the same + * container of the {@code launchingActivity}. + */ + private void setLaunchingInSameContainer(Activity launchingActivity, Intent intent, + Bundle options) { + final TaskFragmentContainer launchingContainer = getContainerWithActivity( + launchingActivity.getActivityToken()); + if (launchingContainer == null) { + return; + } + + final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer); + if (splitContainer == null) { + return; + } + + if (splitContainer.getSecondaryContainer() != launchingContainer) { + return; + } + + // The launching activity is on the secondary container. Retrieve the primary + // activity from the other container. + Activity primaryActivity = + splitContainer.getPrimaryContainer().getTopNonFinishingActivity(); + if (primaryActivity == null) { + return; + } + + final ExtensionSplitPairRule splitPairRule = getSplitRule( + primaryActivity.getComponentName(), intent.getComponent(), getSplitRules()); + if (splitPairRule == null) { + return; + } + + // Amend the request to let the WM know that the activity should be placed in the + // dedicated container. This is necessary for the case that the activity is started + // into a new Task, or new Task will be escaped from the current host Task and be + // displayed in fullscreen. + options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN, + launchingContainer.getTaskFragmentToken()); } } } diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 96860a23d3cf8..690f67c25cfe0 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -199,6 +199,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken, Throwable exception) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, + "Sending TaskFragment error exception=%s", exception.toString()); final Bundle exceptionBundle = putExceptionInBundle(exception); try { organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle); @@ -313,6 +315,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken, Throwable exception) { validateAndGetState(organizer); + Slog.w(TAG, "onTaskFragmentError ", exception); PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer, errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR); mPendingTaskFragmentEvents.add(pendingEvent);