diff options
| author | 2022-05-03 02:23:27 +0000 | |
|---|---|---|
| committer | 2022-05-03 02:23:27 +0000 | |
| commit | 963dc4e957a39a868ee62992c9f90257e5efcbdf (patch) | |
| tree | a71bbc37df3d5f40be9a6ff62c318edf64131e10 | |
| parent | 36db8e049735c280fa8cd4b86cfd73f5fdb96f42 (diff) | |
| parent | 6725f73a88438e0413d78707b4334aecaef389ea (diff) | |
Merge "Notify organizer about TaskFragment parent windowing mode change" into tm-dev am: 6725f73a88
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18032087
Change-Id: Ic004a0cc8ed861e591934a68dc90759dd6433198
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
8 files changed, 207 insertions, 23 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 81caf7786cf5..3ff531573f1f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -133,8 +133,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { // Create or resize the launching TaskFragment. if (mFragmentInfos.containsKey(launchingFragmentToken)) { resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds); - wct.setWindowingMode(mFragmentInfos.get(launchingFragmentToken).getToken(), - windowingMode); + updateWindowingMode(wct, launchingFragmentToken, windowingMode); } else { createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken, launchingFragmentBounds, windowingMode, launchingActivity); @@ -157,7 +156,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */); - setWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); + updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); } /** @@ -260,7 +259,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds); } - private void setWindowingMode(WindowContainerTransaction wct, IBinder fragmentToken, + void updateWindowingMode(WindowContainerTransaction wct, IBinder fragmentToken, @WindowingMode int windowingMode) { if (!mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index b370e59ac7c8..54d9c55f75c3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -17,6 +17,7 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior; @@ -179,6 +180,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // Enter PIP. // All overrides will be cleanup. container.setLastRequestedBounds(null /* bounds */); + container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); cleanupForEnterPip(wct, container); } else if (wasInPip) { // Exit PIP. diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index d8423499730f..06c1d4ec8d32 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -30,7 +30,6 @@ import android.util.LayoutDirection; import android.view.View; import android.view.WindowInsets; import android.view.WindowMetrics; -import android.window.TaskFragmentCreationParams; import android.window.WindowContainerTransaction; import androidx.annotation.IntDef; @@ -122,7 +121,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(), primaryActivity.getActivityToken(), secondaryRectBounds, windowingMode); - secondaryContainer.setLastRequestedBounds(secondaryRectBounds); // Set adjacent to each other so that the containers below will be invisible. setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule); @@ -198,18 +196,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { container = mController.newContainer(activity, taskId); final int windowingMode = mController.getTaskContainer(taskId) .getWindowingModeForSplitTaskFragment(bounds); - final TaskFragmentCreationParams fragmentOptions = - createFragmentOptions( - container.getTaskFragmentToken(), - activity.getActivityToken(), - bounds, - windowingMode); - wct.createTaskFragment(fragmentOptions); - + createTaskFragment(wct, container.getTaskFragmentToken(), activity.getActivityToken(), + bounds, windowingMode); wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(), activity.getActivityToken()); - - container.setLastRequestedBounds(bounds); } else { resizeTaskFragmentIfRegistered(wct, container, bounds); final int windowingMode = mController.getTaskContainer(taskId) @@ -262,9 +252,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); } applyTransaction(wct); - - primaryContainer.setLastRequestedBounds(primaryRectBounds); - secondaryContainer.setLastRequestedBounds(secondaryRectBounds); } /** @@ -346,8 +333,22 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull TaskFragmentContainer container, @WindowingMode int windowingMode) { if (container.getInfo() != null) { - wct.setWindowingMode(container.getInfo().getToken(), windowingMode); + updateWindowingMode(wct, container.getTaskFragmentToken(), windowingMode); + } + } + + @Override + void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, + @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) { + final TaskFragmentContainer container = mController.getContainer(fragmentToken); + if (container == null) { + throw new IllegalStateException( + "Creating a task fragment that is not registered with controller."); } + + container.setLastRequestedBounds(bounds); + container.setLastRequestedWindowingMode(windowingMode); + super.createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode); } @Override @@ -368,6 +369,24 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { super.resizeTaskFragment(wct, fragmentToken, bounds); } + @Override + void updateWindowingMode(@NonNull WindowContainerTransaction wct, + @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) { + final TaskFragmentContainer container = mController.getContainer(fragmentToken); + if (container == null) { + throw new IllegalStateException("Setting windowing mode for a task fragment that is" + + " not registered with controller."); + } + + if (container.isLastRequestedWindowingModeEqual(windowingMode)) { + // Return early if the windowing mode were already requested + return; + } + + container.setLastRequestedWindowingMode(windowingMode); + super.updateWindowingMode(wct, fragmentToken, windowingMode); + } + boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) { final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer()); return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule()); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java index 3c0762d81494..a70755560eb1 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java @@ -106,7 +106,7 @@ class TaskContainer { int getWindowingModeForSplitTaskFragment(@Nullable Rect taskFragmentBounds) { // Only set to multi-windowing mode if the pair are showing side-by-side. Otherwise, it // will be set to UNDEFINED which will then inherit the Task windowing mode. - if (taskFragmentBounds == null || taskFragmentBounds.isEmpty()) { + if (taskFragmentBounds == null || taskFragmentBounds.isEmpty() || isInPictureInPicture()) { return WINDOWING_MODE_UNDEFINED; } // We use WINDOWING_MODE_MULTI_WINDOW when the Task is fullscreen. diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index 871f545d203a..fe422bf37a69 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -17,11 +17,13 @@ package androidx.window.extensions.embedding; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityThread; +import android.app.WindowConfiguration.WindowingMode; import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; @@ -73,6 +75,12 @@ class TaskFragmentContainer { private final Rect mLastRequestedBounds = new Rect(); /** + * Windowing mode that was requested last via {@link android.window.WindowContainerTransaction}. + */ + @WindowingMode + private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED; + + /** * Creates a container with an existing activity that will be re-parented to it in a window * container transaction. */ @@ -300,6 +308,20 @@ class TaskFragmentContainer { } } + /** + * Checks if last requested windowing mode is equal to the provided value. + */ + boolean isLastRequestedWindowingModeEqual(@WindowingMode int windowingMode) { + return mLastRequestedWindowingMode == windowingMode; + } + + /** + * Updates the last requested windowing mode. + */ + void setLastRequestedWindowingMode(@WindowingMode int windowingModes) { + mLastRequestedWindowingMode = windowingModes; + } + /** Gets the parent leaf Task id. */ int getTaskId() { return mTaskId; diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java new file mode 100644 index 000000000000..906e9904566f --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.window.extensions.embedding; + +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; + +import android.app.Activity; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.window.TaskFragmentInfo; +import android.window.WindowContainerTransaction; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link SplitPresenter}. + * + * Build/Install/Run: + * atest WMJetpackUnitTests:SplitPresenterTest + */ +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SplitPresenterTest { + private static final int TASK_ID = 10; + private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200); + + @Mock + private Activity mActivity; + @Mock + private Resources mActivityResources; + @Mock + private TaskFragmentInfo mTaskFragmentInfo; + @Mock + private WindowContainerTransaction mTransaction; + private SplitController mController; + private SplitPresenter mPresenter; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new SplitController(); + mPresenter = mController.mPresenter; + spyOn(mController); + spyOn(mPresenter); + final Configuration activityConfig = new Configuration(); + activityConfig.windowConfiguration.setBounds(TASK_BOUNDS); + activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS); + doReturn(mActivityResources).when(mActivity).getResources(); + doReturn(activityConfig).when(mActivityResources).getConfiguration(); + } + + @Test + public void testCreateTaskFragment() { + final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + mPresenter.createTaskFragment(mTransaction, container.getTaskFragmentToken(), + mActivity.getActivityToken(), TASK_BOUNDS, WINDOWING_MODE_MULTI_WINDOW); + + assertTrue(container.areLastRequestedBoundsEqual(TASK_BOUNDS)); + assertTrue(container.isLastRequestedWindowingModeEqual(WINDOWING_MODE_MULTI_WINDOW)); + verify(mTransaction).createTaskFragment(any()); + } + + @Test + public void testResizeTaskFragment() { + final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + mPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), mTaskFragmentInfo); + mPresenter.resizeTaskFragment(mTransaction, container.getTaskFragmentToken(), TASK_BOUNDS); + + assertTrue(container.areLastRequestedBoundsEqual(TASK_BOUNDS)); + verify(mTransaction).setBounds(any(), eq(TASK_BOUNDS)); + + // No request to set the same bounds. + clearInvocations(mTransaction); + mPresenter.resizeTaskFragment(mTransaction, container.getTaskFragmentToken(), TASK_BOUNDS); + + verify(mTransaction, never()).setBounds(any(), any()); + } + + @Test + public void testUpdateWindowingMode() { + final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + mPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), mTaskFragmentInfo); + mPresenter.updateWindowingMode(mTransaction, container.getTaskFragmentToken(), + WINDOWING_MODE_MULTI_WINDOW); + + assertTrue(container.isLastRequestedWindowingModeEqual(WINDOWING_MODE_MULTI_WINDOW)); + verify(mTransaction).setWindowingMode(any(), eq(WINDOWING_MODE_MULTI_WINDOW)); + + // No request to set the same windowing mode. + clearInvocations(mTransaction); + mPresenter.updateWindowingMode(mTransaction, container.getTaskFragmentToken(), + WINDOWING_MODE_MULTI_WINDOW); + + verify(mTransaction, never()).setWindowingMode(any(), anyInt()); + + } +} diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index eaf25260405a..6a7873998723 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -197,7 +197,9 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr final Task parent = tf.getParent().asTask(); final Configuration parentConfig = parent.getConfiguration(); final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf); - if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) { + if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig) + && parentConfig.windowConfiguration.getWindowingMode() + == lastParentConfig.windowConfiguration.getWindowingMode()) { return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 7a704742fba2..24d04da49e54 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -202,9 +202,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any()); - // Trigger callback if the info is changed. + // Trigger callback if the size is changed. parentConfig.smallestScreenWidthDp = 100; + mController.onTaskFragmentParentInfoChanged( + mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); + verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); + + // Trigger callback if the windowing mode is changed. + clearInvocations(mOrganizer); + parentConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED); mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); |