Merge "Fix ActivityEmbedding animation flicker" into tm-qpr-dev
This commit is contained in:
@@ -288,6 +288,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final IBinder mFragmentToken;
|
private final IBinder mFragmentToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a
|
||||||
|
* configuration change.
|
||||||
|
*/
|
||||||
|
private boolean mDelayOrganizedTaskFragmentSurfaceUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to delay the last activity of TaskFragment being immediately removed while finishing.
|
* Whether to delay the last activity of TaskFragment being immediately removed while finishing.
|
||||||
* This should only be set on a embedded TaskFragment, where the organizer can have the
|
* This should only be set on a embedded TaskFragment, where the organizer can have the
|
||||||
@@ -2273,35 +2279,41 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newParentConfig) {
|
public void onConfigurationChanged(Configuration newParentConfig) {
|
||||||
// Task will animate differently.
|
|
||||||
if (mTaskFragmentOrganizer != null) {
|
|
||||||
mTmpPrevBounds.set(getBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onConfigurationChanged(newParentConfig);
|
super.onConfigurationChanged(newParentConfig);
|
||||||
|
|
||||||
final boolean shouldStartChangeTransition = shouldStartChangeTransition(mTmpPrevBounds);
|
|
||||||
if (shouldStartChangeTransition) {
|
|
||||||
initializeChangeTransition(mTmpPrevBounds);
|
|
||||||
}
|
|
||||||
if (mTaskFragmentOrganizer != null) {
|
if (mTaskFragmentOrganizer != null) {
|
||||||
if (mTransitionController.isShellTransitionsEnabled()
|
updateOrganizedTaskFragmentSurface();
|
||||||
&& !mTransitionController.isCollecting(this)) {
|
|
||||||
// TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
|
|
||||||
// update the surface here if it is not collected by Shell transition.
|
|
||||||
updateOrganizedTaskFragmentSurface();
|
|
||||||
} else if (!mTransitionController.isShellTransitionsEnabled()
|
|
||||||
&& !shouldStartChangeTransition) {
|
|
||||||
// Update the surface here instead of in the organizer so that we can make sure
|
|
||||||
// it can be synced with the surface freezer for legacy app transition.
|
|
||||||
updateOrganizedTaskFragmentSurface();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTaskFragmentInfoChanged();
|
sendTaskFragmentInfoChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deferOrganizedTaskFragmentSurfaceUpdate() {
|
||||||
|
mDelayOrganizedTaskFragmentSurfaceUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void continueOrganizedTaskFragmentSurfaceUpdate() {
|
||||||
|
mDelayOrganizedTaskFragmentSurfaceUpdate = false;
|
||||||
|
updateOrganizedTaskFragmentSurface();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateOrganizedTaskFragmentSurface() {
|
private void updateOrganizedTaskFragmentSurface() {
|
||||||
|
if (mDelayOrganizedTaskFragmentSurfaceUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mTransitionController.isShellTransitionsEnabled()
|
||||||
|
&& !mTransitionController.isCollecting(this)) {
|
||||||
|
// TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
|
||||||
|
// update the surface here if it is not collected by Shell transition.
|
||||||
|
updateOrganizedTaskFragmentSurfaceUnchecked();
|
||||||
|
} else if (!mTransitionController.isShellTransitionsEnabled() && !isAnimating()) {
|
||||||
|
// Update the surface here instead of in the organizer so that we can make sure
|
||||||
|
// it can be synced with the surface freezer for legacy app transition.
|
||||||
|
updateOrganizedTaskFragmentSurfaceUnchecked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOrganizedTaskFragmentSurfaceUnchecked() {
|
||||||
final SurfaceControl.Transaction t = getSyncTransaction();
|
final SurfaceControl.Transaction t = getSyncTransaction();
|
||||||
updateSurfacePosition(t);
|
updateSurfacePosition(t);
|
||||||
updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
|
updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
|
||||||
@@ -2355,7 +2367,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
|
/** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
|
||||||
private boolean shouldStartChangeTransition(Rect startBounds) {
|
boolean shouldStartChangeTransition(Rect startBounds) {
|
||||||
if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
|
if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2375,7 +2387,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
void setSurfaceControl(SurfaceControl sc) {
|
void setSurfaceControl(SurfaceControl sc) {
|
||||||
super.setSurfaceControl(sc);
|
super.setSurfaceControl(sc);
|
||||||
if (mTaskFragmentOrganizer != null) {
|
if (mTaskFragmentOrganizer != null) {
|
||||||
updateOrganizedTaskFragmentSurface();
|
updateOrganizedTaskFragmentSurfaceUnchecked();
|
||||||
// If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
|
// If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
|
||||||
// emit the callbacks now.
|
// emit the callbacks now.
|
||||||
sendTaskFragmentAppeared();
|
sendTaskFragmentAppeared();
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
|
final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
|
||||||
|
|
||||||
|
private final Rect mTmpBounds = new Rect();
|
||||||
|
|
||||||
WindowOrganizerController(ActivityTaskManagerService atm) {
|
WindowOrganizerController(ActivityTaskManagerService atm) {
|
||||||
mService = atm;
|
mService = atm;
|
||||||
mGlobalLock = atm.mGlobalLock;
|
mGlobalLock = atm.mGlobalLock;
|
||||||
@@ -711,7 +713,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
|
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
|
||||||
int effects = 0;
|
int effects = applyChanges(tr, c, null /* errorCallbackToken */);
|
||||||
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
|
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
|
||||||
|
|
||||||
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
|
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
|
||||||
@@ -772,6 +774,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
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];
|
||||||
|
effects[0] = applyChanges(displayArea, c, null /* errorCallbackToken */);
|
||||||
|
|
||||||
if ((c.getChangeMask()
|
if ((c.getChangeMask()
|
||||||
& WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
|
& WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
|
||||||
@@ -792,6 +795,27 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
return effects[0];
|
return effects[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int applyTaskFragmentChanges(@NonNull TaskFragment taskFragment,
|
||||||
|
@NonNull WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
|
||||||
|
if (taskFragment.isEmbeddedTaskFragmentInPip()) {
|
||||||
|
// No override from organizer for embedded TaskFragment in a PIP Task.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the TaskFragment is resized, we may want to create a change transition for it, for
|
||||||
|
// which we want to defer the surface update until we determine whether or not to start
|
||||||
|
// change transition.
|
||||||
|
mTmpBounds.set(taskFragment.getBounds());
|
||||||
|
taskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
|
||||||
|
final int effects = applyChanges(taskFragment, c, errorCallbackToken);
|
||||||
|
if (taskFragment.shouldStartChangeTransition(mTmpBounds)) {
|
||||||
|
taskFragment.initializeChangeTransition(mTmpBounds);
|
||||||
|
}
|
||||||
|
taskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
|
||||||
|
mTmpBounds.set(0, 0, 0, 0);
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
|
||||||
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
|
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
|
||||||
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
|
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
|
||||||
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
|
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
|
||||||
@@ -1457,20 +1481,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
private int applyWindowContainerChange(WindowContainer wc,
|
private int applyWindowContainerChange(WindowContainer wc,
|
||||||
WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
|
WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
|
||||||
sanitizeWindowContainer(wc);
|
sanitizeWindowContainer(wc);
|
||||||
if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbeddedTaskFragmentInPip()) {
|
if (wc.asDisplayArea() != null) {
|
||||||
// No override from organizer for embedded TaskFragment in a PIP Task.
|
return applyDisplayAreaChanges(wc.asDisplayArea(), c);
|
||||||
return 0;
|
} else if (wc.asTask() != null) {
|
||||||
|
return applyTaskChanges(wc.asTask(), c);
|
||||||
|
} else if (wc.asTaskFragment() != null) {
|
||||||
|
return applyTaskFragmentChanges(wc.asTaskFragment(), c, errorCallbackToken);
|
||||||
|
} else {
|
||||||
|
return applyChanges(wc, c, errorCallbackToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
int effects = applyChanges(wc, c, errorCallbackToken);
|
|
||||||
|
|
||||||
if (wc instanceof DisplayArea) {
|
|
||||||
effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
|
|
||||||
} else if (wc instanceof Task) {
|
|
||||||
effects |= applyTaskChanges(wc.asTask(), c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return effects;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1537,10 +1537,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
mWmService.makeWindowFreezingScreenIfNeededLocked(this);
|
mWmService.makeWindowFreezingScreenIfNeededLocked(this);
|
||||||
|
|
||||||
// If the orientation is changing, or we're starting or ending a drag resizing action,
|
// If the orientation is changing, or we're starting or ending a drag resizing action,
|
||||||
// then we need to hold off on unfreezing the display until this window has been
|
// or we're resizing an embedded Activity, then we need to hold off on unfreezing the
|
||||||
// redrawn; to do that, we need to go through the process of getting informed by the
|
// display until this window has been redrawn; to do that, we need to go through the
|
||||||
// application when it has finished drawing.
|
// process of getting informed by the application when it has finished drawing.
|
||||||
if (getOrientationChanging() || dragResizingChanged) {
|
if (getOrientationChanging() || dragResizingChanged
|
||||||
|
|| isEmbeddedActivityResizeChanged()) {
|
||||||
if (dragResizingChanged) {
|
if (dragResizingChanged) {
|
||||||
ProtoLog.v(WM_DEBUG_RESIZE,
|
ProtoLog.v(WM_DEBUG_RESIZE,
|
||||||
"Resize start waiting for draw, "
|
"Resize start waiting for draw, "
|
||||||
@@ -4147,6 +4148,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
return mActivityRecord == null || mActivityRecord.isFullyTransparentBarAllowed(frame);
|
return mActivityRecord == null || mActivityRecord.isFullyTransparentBarAllowed(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this window belongs to a resizing embedded activity.
|
||||||
|
*/
|
||||||
|
private boolean isEmbeddedActivityResizeChanged() {
|
||||||
|
if (mActivityRecord == null || !isVisibleRequested()) {
|
||||||
|
// No need to update if the window is in the background.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TaskFragment embeddedTaskFragment = mActivityRecord.getOrganizedTaskFragment();
|
||||||
|
return embeddedTaskFragment != null
|
||||||
|
&& mDisplayContent.mChangingContainers.contains(embeddedTaskFragment);
|
||||||
|
}
|
||||||
|
|
||||||
boolean isDragResizeChanged() {
|
boolean isDragResizeChanged() {
|
||||||
return mDragResizing != computeDragResizing();
|
return mDragResizing != computeDragResizing();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,10 +118,13 @@ public class TaskFragmentTest extends WindowTestsBase {
|
|||||||
doReturn(true).when(mTaskFragment).isVisibleRequested();
|
doReturn(true).when(mTaskFragment).isVisibleRequested();
|
||||||
|
|
||||||
clearInvocations(mTransaction);
|
clearInvocations(mTransaction);
|
||||||
|
mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
|
||||||
mTaskFragment.setBounds(endBounds);
|
mTaskFragment.setBounds(endBounds);
|
||||||
|
assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds));
|
||||||
|
mTaskFragment.initializeChangeTransition(startBounds);
|
||||||
|
mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
|
||||||
|
|
||||||
// Surface reset when prepare transition.
|
// Surface reset when prepare transition.
|
||||||
verify(mTaskFragment).initializeChangeTransition(startBounds);
|
|
||||||
verify(mTransaction).setPosition(mLeash, 0, 0);
|
verify(mTransaction).setPosition(mLeash, 0, 0);
|
||||||
verify(mTransaction).setWindowCrop(mLeash, 0, 0);
|
verify(mTransaction).setWindowCrop(mLeash, 0, 0);
|
||||||
|
|
||||||
@@ -166,7 +169,7 @@ public class TaskFragmentTest extends WindowTestsBase {
|
|||||||
|
|
||||||
mTaskFragment.setBounds(endBounds);
|
mTaskFragment.setBounds(endBounds);
|
||||||
|
|
||||||
verify(mTaskFragment, never()).initializeChangeTransition(any());
|
assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ import android.view.InsetsState;
|
|||||||
import android.view.InsetsVisibilities;
|
import android.view.InsetsVisibilities;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import android.window.ITaskFragmentOrganizer;
|
||||||
|
import android.window.TaskFragmentOrganizer;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -797,6 +799,39 @@ public class WindowStateTests extends WindowTestsBase {
|
|||||||
assertThat(mWm.mResizingWindows).doesNotContain(win);
|
assertThat(mWm.mResizingWindows).doesNotContain(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmbeddedActivityResizing_clearAllDrawn() {
|
||||||
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
|
mAtm.mTaskFragmentOrganizerController.registerOrganizer(
|
||||||
|
ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
|
||||||
|
final Task task = createTask(mDisplayContent);
|
||||||
|
final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
|
final ActivityRecord embeddedActivity = embeddedTf.getTopMostActivity();
|
||||||
|
final WindowState win = createWindow(null /* parent */, TYPE_APPLICATION, embeddedActivity,
|
||||||
|
"App window");
|
||||||
|
doReturn(true).when(embeddedActivity).isVisible();
|
||||||
|
embeddedActivity.mVisibleRequested = true;
|
||||||
|
makeWindowVisible(win);
|
||||||
|
win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
|
||||||
|
// Set the bounds twice:
|
||||||
|
// 1. To make sure there is no orientation change after #reportResized, which can also cause
|
||||||
|
// #clearAllDrawn.
|
||||||
|
// 2. Make #isLastConfigReportedToClient to be false after #reportResized, so it can process
|
||||||
|
// to check if we need redraw.
|
||||||
|
embeddedTf.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||||
|
embeddedTf.setBounds(0, 0, 1000, 2000);
|
||||||
|
win.reportResized();
|
||||||
|
embeddedTf.setBounds(500, 0, 1000, 2000);
|
||||||
|
|
||||||
|
// Clear all drawn when the embedded TaskFragment is in mDisplayContent.mChangingContainers.
|
||||||
|
win.updateResizingWindowIfNeeded();
|
||||||
|
verify(embeddedActivity, never()).clearAllDrawn();
|
||||||
|
|
||||||
|
mDisplayContent.mChangingContainers.add(embeddedTf);
|
||||||
|
win.updateResizingWindowIfNeeded();
|
||||||
|
verify(embeddedActivity).clearAllDrawn();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
|
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
|
||||||
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
|
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
|
||||||
|
|||||||
Reference in New Issue
Block a user