From 59c5d8101edc1192dfb04c73747aa210f28d3ea4 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Tue, 11 Jul 2023 16:20:01 -0700 Subject: Ensure onStop before onPictureInPictureModeChanged We have a CTS test case PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss that ensures onStop is always sent before onPictureInPictureModeChanged. The test itself does not simulate what user typically does and it's broken with the shell transition. Apps like YouTube may rely on such order so they can choose if they should, for instance, stop the playback when the PiP is removed. Fixing this by forcefully send onStop before setWindowingMode (which in turn results a configuration change). Video: http://recall/-/aaaaaabFQoRHlzixHdtY/eEEfu9mca0dzLyzC8jBcxb Bug: 290413333 Test: manually, see also the video Test: atest PinnedStackTests Change-Id: I0f94d4c26f7b3ccc1df6be97a0238f995438dffd --- .../core/java/com/android/server/wm/ActivityTaskSupervisor.java | 7 +++++-- .../core/java/com/android/server/wm/WindowOrganizerController.java | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 738797b809a5..50948e1cdec4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -2186,7 +2186,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { * Processes the activities to be stopped or destroyed. This should be called when the resumed * activities are idle or drawn. */ - private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity, + void processStoppingAndFinishingActivities(ActivityRecord launchedActivity, boolean processPausingActivities, String reason) { // Stop any activities that are scheduled to do so but have been waiting for the transition // animation to finish. @@ -2194,7 +2194,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { ArrayList readyToStopActivities = null; for (int i = 0; i < mStoppingActivities.size(); i++) { final ActivityRecord s = mStoppingActivities.get(i); - final boolean animating = s.isInTransition(); + // Activity in a force hidden task should not be counted as animating, i.e., we want to + // send onStop before any configuration change when removing pip transition is ongoing. + final boolean animating = s.isInTransition() + && s.getTask() != null && !s.getTask().isForceHidden(); displaySwapping |= s.isDisplaySleepingAndSwapping(); ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b " + "finishing=%s", s, s.nowVisible, animating, s.finishing); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index d1b00a38701d..e6c64030847a 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -568,6 +568,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } if (forceHiddenForPip) { wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); + // When removing pip, make sure that onStop is sent to the app ahead of + // onPictureInPictureModeChanged. + // See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss + wc.asTask().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + wc.asTask().mTaskSupervisor.processStoppingAndFinishingActivities( + null /* launchedActivity */, false /* processPausingActivities */, + "force-stop-on-removing-pip"); } int containerEffect = applyWindowContainerChange(wc, entry.getValue(), -- cgit v1.2.3-59-g8ed1b