Loading core/java/android/window/flags/windowing_frontend.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,16 @@ flag { } } } } flag { name: "apply_lifecycle_on_pip_change" namespace: "windowing_frontend" description: "Make pip activity lifecyle change with windowing mode" bug: "333452456" metadata { purpose: PURPOSE_BUGFIX } } flag { flag { name: "blast_sync_notification_shade_on_display_switch" name: "blast_sync_notification_shade_on_display_switch" namespace: "windowing_frontend" namespace: "windowing_frontend" Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +25 −9 Original line number Original line Diff line number Diff line Loading @@ -878,15 +878,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final int childWindowingMode = c.getActivityWindowingMode(); final int childWindowingMode = c.getActivityWindowingMode(); if (!ActivityTaskManagerService.isPip2ExperimentEnabled() if (!ActivityTaskManagerService.isPip2ExperimentEnabled() && tr.getWindowingMode() == WINDOWING_MODE_PINNED && tr.getWindowingMode() == WINDOWING_MODE_PINNED) { && (childWindowingMode == WINDOWING_MODE_PINNED if (childWindowingMode == WINDOWING_MODE_PINNED || childWindowingMode == WINDOWING_MODE_UNDEFINED)) { || childWindowingMode == WINDOWING_MODE_UNDEFINED) { // If setActivityWindowingMode requested to match its pinned task's windowing mode, // If setActivityWindowingMode requested to match its pinned task's windowing mode, // remove any inconsistency checking timeout callbacks for PiP. // remove any inconsistency checking timeout callbacks for PiP. Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " + "abort PiP callbacks scheduled if needed; task_win_mode=" + "abort PiP callbacks scheduled if needed; task_win_mode=" + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); } else if (shouldApplyLifecycleEffectOnPipChange()) { // This is leaving PiP: task is pinned mode and activity changes to non-pip mode. // Then the activity can be resumed because it becomes focusable. effects |= TRANSACT_EFFECTS_LIFECYCLE; } } } if (childWindowingMode > -1) { if (childWindowingMode > -1) { tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); Loading @@ -911,6 +916,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (canEnterPip) { if (canEnterPip) { canEnterPip = mService.mActivityClientController canEnterPip = mService.mActivityClientController .requestPictureInPictureMode(activity); .requestPictureInPictureMode(activity); if (canEnterPip && shouldApplyLifecycleEffectOnPipChange()) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } } } if (!canEnterPip) { if (!canEnterPip) { // Restore the flag to its previous state when the activity cannot enter PIP. // Restore the flag to its previous state when the activity cannot enter PIP. Loading @@ -922,6 +930,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; return effects; } } // TODO(b/333452456): For testing on local easier. Remove after the use case is gone. @VisibleForTesting static boolean shouldApplyLifecycleEffectOnPipChange() { return android.os.SystemProperties.getBoolean( "persist.wm.debug.apply_lifecycle_on_pip_change", false) || com.android.window.flags.Flags.applyLifecycleOnPipChange(); } private int applyDisplayAreaChanges(DisplayArea displayArea, private int applyDisplayAreaChanges(DisplayArea displayArea, WindowContainerTransaction.Change c) { WindowContainerTransaction.Change c) { final int[] effects = new int[1]; final int[] effects = new int[1]; Loading services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +25 −10 Original line number Original line Diff line number Diff line Loading @@ -1725,26 +1725,41 @@ public class WindowOrganizerTests extends WindowTestsBase { assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); } } @SuppressWarnings("GuardedBy") @Test @Test public void testResumeTopsWhenLeavingPinned() { public void testResumeTopsWhenLeavingPinned() { final ActivityRecord record = makePipableActivity(); final ActivityRecord home = new ActivityBuilder(mAtm).setTask( final Task rootTask = record.getRootTask(); mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask()).build(); final Task homeTask = home.getTask(); final ActivityRecord pipActivity = makePipableActivity(); clearInvocations(mWm.mAtmService.mRootWindowContainer); final WindowContainerTransaction t = new WindowContainerTransaction(); final WindowContainerTransaction t = new WindowContainerTransaction(); WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken(); t.setWindowingMode(pipActivity.getTask().mRemoteToken.toWindowContainerToken(), t.setWindowingMode(wct, WINDOWING_MODE_PINNED); WINDOWING_MODE_PINNED); clearInvocations(homeTask); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); if (WindowOrganizerController.shouldApplyLifecycleEffectOnPipChange()) { verify(homeTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } else { verify(homeTask, never()).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } // Undo the effect of legacy logic in RootWindowContainer#moveActivityToPinnedRootTask. if (pipActivity.mWaitForEnteringPinnedMode) { pipActivity.mWaitForEnteringPinnedMode = false; pipActivity.setWindowingMode(WINDOWING_MODE_UNDEFINED); } assertFalse(pipActivity.isFocusable()); clearInvocations(mWm.mAtmService.mRootWindowContainer); // The token for the PIP root task may have changed when the task entered PIP mode, so do // The token for the PIP root task may have changed when the task entered PIP mode, so do // not reuse the one from above. // not reuse the one from above. final WindowContainerToken newToken = final Task pipTask = pipActivity.getTask(); record.getRootTask().mRemoteToken.toWindowContainerToken(); final WindowContainerToken newToken = pipTask.mRemoteToken.toWindowContainerToken(); t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); clearInvocations(pipTask); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); assertTrue(pipActivity.isFocusable()); verify(pipTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } } @Test @Test Loading Loading
core/java/android/window/flags/windowing_frontend.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,16 @@ flag { } } } } flag { name: "apply_lifecycle_on_pip_change" namespace: "windowing_frontend" description: "Make pip activity lifecyle change with windowing mode" bug: "333452456" metadata { purpose: PURPOSE_BUGFIX } } flag { flag { name: "blast_sync_notification_shade_on_display_switch" name: "blast_sync_notification_shade_on_display_switch" namespace: "windowing_frontend" namespace: "windowing_frontend" Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +25 −9 Original line number Original line Diff line number Diff line Loading @@ -878,15 +878,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final int childWindowingMode = c.getActivityWindowingMode(); final int childWindowingMode = c.getActivityWindowingMode(); if (!ActivityTaskManagerService.isPip2ExperimentEnabled() if (!ActivityTaskManagerService.isPip2ExperimentEnabled() && tr.getWindowingMode() == WINDOWING_MODE_PINNED && tr.getWindowingMode() == WINDOWING_MODE_PINNED) { && (childWindowingMode == WINDOWING_MODE_PINNED if (childWindowingMode == WINDOWING_MODE_PINNED || childWindowingMode == WINDOWING_MODE_UNDEFINED)) { || childWindowingMode == WINDOWING_MODE_UNDEFINED) { // If setActivityWindowingMode requested to match its pinned task's windowing mode, // If setActivityWindowingMode requested to match its pinned task's windowing mode, // remove any inconsistency checking timeout callbacks for PiP. // remove any inconsistency checking timeout callbacks for PiP. Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " Slog.d(TAG, "Task and activity windowing modes match, so remove any timeout " + "abort PiP callbacks scheduled if needed; task_win_mode=" + "abort PiP callbacks scheduled if needed; task_win_mode=" + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); + tr.getWindowingMode() + ", activity_win_mode=" + childWindowingMode); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); mService.mRootWindowContainer.removeAllMaybeAbortPipEnterRunnable(); } else if (shouldApplyLifecycleEffectOnPipChange()) { // This is leaving PiP: task is pinned mode and activity changes to non-pip mode. // Then the activity can be resumed because it becomes focusable. effects |= TRANSACT_EFFECTS_LIFECYCLE; } } } if (childWindowingMode > -1) { if (childWindowingMode > -1) { tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); tr.forAllActivities(a -> { a.setWindowingMode(childWindowingMode); }); Loading @@ -911,6 +916,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (canEnterPip) { if (canEnterPip) { canEnterPip = mService.mActivityClientController canEnterPip = mService.mActivityClientController .requestPictureInPictureMode(activity); .requestPictureInPictureMode(activity); if (canEnterPip && shouldApplyLifecycleEffectOnPipChange()) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } } } if (!canEnterPip) { if (!canEnterPip) { // Restore the flag to its previous state when the activity cannot enter PIP. // Restore the flag to its previous state when the activity cannot enter PIP. Loading @@ -922,6 +930,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; return effects; } } // TODO(b/333452456): For testing on local easier. Remove after the use case is gone. @VisibleForTesting static boolean shouldApplyLifecycleEffectOnPipChange() { return android.os.SystemProperties.getBoolean( "persist.wm.debug.apply_lifecycle_on_pip_change", false) || com.android.window.flags.Flags.applyLifecycleOnPipChange(); } private int applyDisplayAreaChanges(DisplayArea displayArea, private int applyDisplayAreaChanges(DisplayArea displayArea, WindowContainerTransaction.Change c) { WindowContainerTransaction.Change c) { final int[] effects = new int[1]; final int[] effects = new int[1]; Loading
services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +25 −10 Original line number Original line Diff line number Diff line Loading @@ -1725,26 +1725,41 @@ public class WindowOrganizerTests extends WindowTestsBase { assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); } } @SuppressWarnings("GuardedBy") @Test @Test public void testResumeTopsWhenLeavingPinned() { public void testResumeTopsWhenLeavingPinned() { final ActivityRecord record = makePipableActivity(); final ActivityRecord home = new ActivityBuilder(mAtm).setTask( final Task rootTask = record.getRootTask(); mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask()).build(); final Task homeTask = home.getTask(); final ActivityRecord pipActivity = makePipableActivity(); clearInvocations(mWm.mAtmService.mRootWindowContainer); final WindowContainerTransaction t = new WindowContainerTransaction(); final WindowContainerTransaction t = new WindowContainerTransaction(); WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken(); t.setWindowingMode(pipActivity.getTask().mRemoteToken.toWindowContainerToken(), t.setWindowingMode(wct, WINDOWING_MODE_PINNED); WINDOWING_MODE_PINNED); clearInvocations(homeTask); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); if (WindowOrganizerController.shouldApplyLifecycleEffectOnPipChange()) { verify(homeTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } else { verify(homeTask, never()).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } // Undo the effect of legacy logic in RootWindowContainer#moveActivityToPinnedRootTask. if (pipActivity.mWaitForEnteringPinnedMode) { pipActivity.mWaitForEnteringPinnedMode = false; pipActivity.setWindowingMode(WINDOWING_MODE_UNDEFINED); } assertFalse(pipActivity.isFocusable()); clearInvocations(mWm.mAtmService.mRootWindowContainer); // The token for the PIP root task may have changed when the task entered PIP mode, so do // The token for the PIP root task may have changed when the task entered PIP mode, so do // not reuse the one from above. // not reuse the one from above. final WindowContainerToken newToken = final Task pipTask = pipActivity.getTask(); record.getRootTask().mRemoteToken.toWindowContainerToken(); final WindowContainerToken newToken = pipTask.mRemoteToken.toWindowContainerToken(); t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); clearInvocations(pipTask); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); assertTrue(pipActivity.isFocusable()); verify(pipTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); } } @Test @Test Loading