summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/Task.java1
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java62
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java105
4 files changed, 163 insertions, 7 deletions
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c5362d38c613..d89d212bab1f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -480,7 +480,6 @@ class Task extends TaskFragment {
private Dimmer mDimmer = new Dimmer(this);
private final Rect mTmpDimBoundsRect = new Rect();
- private final Point mLastSurfaceSize = new Point();
/** @see #setCanAffectSystemUiFlags */
private boolean mCanAffectSystemUiFlags = true;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index fce279d8b805..2b5a8203d33b 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -240,6 +240,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
private int mTaskFragmentOrganizerPid = ActivityRecord.INVALID_PID;
+ final Point mLastSurfaceSize = new Point();
+
private final Rect mTmpInsets = new Rect();
private final Rect mTmpBounds = new Rect();
private final Rect mTmpFullBounds = new Rect();
@@ -1654,6 +1656,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
+ @Override
void onChildPositionChanged(WindowContainer child) {
super.onChildPositionChanged(child);
@@ -2049,14 +2052,58 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (shouldStartChangeTransition(mTmpPrevBounds)) {
initializeChangeTransition(mTmpPrevBounds);
} else if (mTaskFragmentOrganizer != null) {
- // Update the surface position here instead of in the organizer so that we can make sure
+ // Update the surface here instead of in the organizer so that we can make sure
// it can be synced with the surface freezer.
- updateSurfacePosition(getSyncTransaction());
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ updateSurfacePosition(t);
+ updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
}
sendTaskFragmentInfoChanged();
}
+ /** Updates the surface size so that the sub windows cannot be shown out of bounds. */
+ private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t,
+ boolean forceUpdate) {
+ if (mTaskFragmentOrganizer == null) {
+ // We only want to update for organized TaskFragment. Task will handle itself.
+ return;
+ }
+ if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) {
+ return;
+ }
+
+ final Rect bounds = getBounds();
+ final int width = bounds.width();
+ final int height = bounds.height();
+ if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
+ return;
+ }
+ t.setWindowCrop(mSurfaceControl, width, height);
+ mLastSurfaceSize.set(width, height);
+ }
+
+ @Override
+ public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
+ super.onAnimationLeashCreated(t, leash);
+ // Reset surface bounds for animation. It will be taken care by the animation leash, and
+ // reset again onAnimationLeashLost.
+ if (mTaskFragmentOrganizer != null
+ && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) {
+ t.setWindowCrop(mSurfaceControl, 0, 0);
+ mLastSurfaceSize.set(0, 0);
+ }
+ }
+
+ @Override
+ public void onAnimationLeashLost(SurfaceControl.Transaction t) {
+ super.onAnimationLeashLost(t);
+ // Update the surface bounds after animation.
+ if (mTaskFragmentOrganizer != null) {
+ updateOrganizedTaskFragmentSurfaceSize(t, true /* forceUpdate */);
+ }
+ }
+
/** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
private boolean shouldStartChangeTransition(Rect startBounds) {
if (mWmService.mDisableTransitionAnimation
@@ -2075,9 +2122,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
@Override
void setSurfaceControl(SurfaceControl sc) {
super.setSurfaceControl(sc);
- // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
- // emit the callbacks now.
- sendTaskFragmentAppeared();
+ if (mTaskFragmentOrganizer != null) {
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ updateSurfacePosition(t);
+ updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+ // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
+ // emit the callbacks now.
+ sendTaskFragmentAppeared();
+ }
}
void sendTaskFragmentInfoChanged() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 2a8fa1086799..0bc3712d7946 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3159,7 +3159,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
void updateSurfacePosition(Transaction t) {
- if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) {
+ if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) {
return;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
new file mode 100644
index 000000000000..cb209abf6aa9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 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 com.android.server.wm;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.Mockito.clearInvocations;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizer;
+
+import androidx.test.filters.MediumTest;
+
+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 TaskFragment}.
+ *
+ * Build/Install/Run:
+ * atest WmTests:TaskFragmentTest
+ */
+@MediumTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class TaskFragmentTest extends WindowTestsBase {
+
+ private TaskFragmentOrganizer mOrganizer;
+ private TaskFragment mTaskFragment;
+ private SurfaceControl mLeash;
+ @Mock
+ private SurfaceControl.Transaction mTransaction;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mOrganizer = new TaskFragmentOrganizer(Runnable::run);
+ final ITaskFragmentOrganizer iOrganizer =
+ ITaskFragmentOrganizer.Stub.asInterface(mOrganizer.getOrganizerToken().asBinder());
+ mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController
+ .registerOrganizer(iOrganizer);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .setOrganizer(mOrganizer)
+ .build();
+ mLeash = mTaskFragment.getSurfaceControl();
+ spyOn(mTaskFragment);
+ doReturn(mTransaction).when(mTaskFragment).getSyncTransaction();
+ doReturn(mTransaction).when(mTaskFragment).getPendingTransaction();
+ }
+
+ @Test
+ public void testOnConfigurationChanged_updateSurface() {
+ final Rect bounds = new Rect(100, 100, 1100, 1100);
+ mTaskFragment.setBounds(bounds);
+
+ verify(mTransaction).setPosition(mLeash, 100, 100);
+ verify(mTransaction).setWindowCrop(mLeash, 1000, 1000);
+ }
+
+ @Test
+ public void testStartChangeTransition_resetSurface() {
+ final Rect startBounds = new Rect(0, 0, 1000, 1000);
+ final Rect endBounds = new Rect(500, 500, 1000, 1000);
+ mTaskFragment.setBounds(startBounds);
+ doReturn(true).when(mTaskFragment).isVisible();
+
+ clearInvocations(mTransaction);
+ mTaskFragment.setBounds(endBounds);
+
+ // Surface reset when prepare transition.
+ verify(mTaskFragment).initializeChangeTransition(startBounds);
+ verify(mTransaction).setPosition(mLeash, 0, 0);
+ verify(mTransaction).setWindowCrop(mLeash, 0, 0);
+
+ clearInvocations(mTransaction);
+ mTaskFragment.mSurfaceFreezer.unfreeze(mTransaction);
+
+ // Update surface after animation.
+ verify(mTransaction).setPosition(mLeash, 500, 500);
+ verify(mTransaction).setWindowCrop(mLeash, 500, 500);
+ }
+}