Set TaskFragment surface window crop
We don't want the child window to show outside of the TaskFragment. Bug: 201261613 Bug: 196173550 Test: atest WmTests:TaskFragmentTest Change-Id: I8350c5c57a79be9b2c7804847ebb1a5ffc4af015
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user