Merge "Fix ActivityEmbedding animation flicker" into tm-qpr-dev
This commit is contained in:
@@ -288,6 +288,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
@Nullable
|
||||
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.
|
||||
* 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
|
||||
public void onConfigurationChanged(Configuration newParentConfig) {
|
||||
// Task will animate differently.
|
||||
if (mTaskFragmentOrganizer != null) {
|
||||
mTmpPrevBounds.set(getBounds());
|
||||
}
|
||||
|
||||
super.onConfigurationChanged(newParentConfig);
|
||||
|
||||
final boolean shouldStartChangeTransition = shouldStartChangeTransition(mTmpPrevBounds);
|
||||
if (shouldStartChangeTransition) {
|
||||
initializeChangeTransition(mTmpPrevBounds);
|
||||
}
|
||||
if (mTaskFragmentOrganizer != null) {
|
||||
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.
|
||||
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();
|
||||
}
|
||||
updateOrganizedTaskFragmentSurface();
|
||||
}
|
||||
|
||||
sendTaskFragmentInfoChanged();
|
||||
}
|
||||
|
||||
void deferOrganizedTaskFragmentSurfaceUpdate() {
|
||||
mDelayOrganizedTaskFragmentSurfaceUpdate = true;
|
||||
}
|
||||
|
||||
void continueOrganizedTaskFragmentSurfaceUpdate() {
|
||||
mDelayOrganizedTaskFragmentSurfaceUpdate = false;
|
||||
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();
|
||||
updateSurfacePosition(t);
|
||||
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. */
|
||||
private boolean shouldStartChangeTransition(Rect startBounds) {
|
||||
boolean shouldStartChangeTransition(Rect startBounds) {
|
||||
if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
|
||||
return false;
|
||||
}
|
||||
@@ -2375,7 +2387,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
void setSurfaceControl(SurfaceControl sc) {
|
||||
super.setSurfaceControl(sc);
|
||||
if (mTaskFragmentOrganizer != null) {
|
||||
updateOrganizedTaskFragmentSurface();
|
||||
updateOrganizedTaskFragmentSurfaceUnchecked();
|
||||
// If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
|
||||
// emit the callbacks now.
|
||||
sendTaskFragmentAppeared();
|
||||
|
||||
@@ -147,6 +147,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
@VisibleForTesting
|
||||
final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
|
||||
|
||||
private final Rect mTmpBounds = new Rect();
|
||||
|
||||
WindowOrganizerController(ActivityTaskManagerService atm) {
|
||||
mService = atm;
|
||||
mGlobalLock = atm.mGlobalLock;
|
||||
@@ -711,7 +713,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
|
||||
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
|
||||
int effects = 0;
|
||||
int effects = applyChanges(tr, c, null /* errorCallbackToken */);
|
||||
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
|
||||
|
||||
if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
|
||||
@@ -772,6 +774,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
private int applyDisplayAreaChanges(DisplayArea displayArea,
|
||||
WindowContainerTransaction.Change c) {
|
||||
final int[] effects = new int[1];
|
||||
effects[0] = applyChanges(displayArea, c, null /* errorCallbackToken */);
|
||||
|
||||
if ((c.getChangeMask()
|
||||
& WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
|
||||
@@ -792,6 +795,27 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
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,
|
||||
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
|
||||
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
|
||||
@@ -1457,20 +1481,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
private int applyWindowContainerChange(WindowContainer wc,
|
||||
WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
|
||||
sanitizeWindowContainer(wc);
|
||||
if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbeddedTaskFragmentInPip()) {
|
||||
// No override from organizer for embedded TaskFragment in a PIP Task.
|
||||
return 0;
|
||||
if (wc.asDisplayArea() != null) {
|
||||
return applyDisplayAreaChanges(wc.asDisplayArea(), c);
|
||||
} 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
|
||||
|
||||
@@ -1537,10 +1537,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
mWmService.makeWindowFreezingScreenIfNeededLocked(this);
|
||||
|
||||
// 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
|
||||
// redrawn; to do that, we need to go through the process of getting informed by the
|
||||
// application when it has finished drawing.
|
||||
if (getOrientationChanging() || dragResizingChanged) {
|
||||
// or we're resizing an embedded Activity, then we need to hold off on unfreezing the
|
||||
// display until this window has been redrawn; to do that, we need to go through the
|
||||
// process of getting informed by the application when it has finished drawing.
|
||||
if (getOrientationChanging() || dragResizingChanged
|
||||
|| isEmbeddedActivityResizeChanged()) {
|
||||
if (dragResizingChanged) {
|
||||
ProtoLog.v(WM_DEBUG_RESIZE,
|
||||
"Resize start waiting for draw, "
|
||||
@@ -4147,6 +4148,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
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() {
|
||||
return mDragResizing != computeDragResizing();
|
||||
}
|
||||
|
||||
@@ -118,10 +118,13 @@ public class TaskFragmentTest extends WindowTestsBase {
|
||||
doReturn(true).when(mTaskFragment).isVisibleRequested();
|
||||
|
||||
clearInvocations(mTransaction);
|
||||
mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
|
||||
mTaskFragment.setBounds(endBounds);
|
||||
assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds));
|
||||
mTaskFragment.initializeChangeTransition(startBounds);
|
||||
mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
|
||||
|
||||
// Surface reset when prepare transition.
|
||||
verify(mTaskFragment).initializeChangeTransition(startBounds);
|
||||
verify(mTransaction).setPosition(mLeash, 0, 0);
|
||||
verify(mTransaction).setWindowCrop(mLeash, 0, 0);
|
||||
|
||||
@@ -166,7 +169,7 @@ public class TaskFragmentTest extends WindowTestsBase {
|
||||
|
||||
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.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.TaskFragmentOrganizer;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -797,6 +799,39 @@ public class WindowStateTests extends WindowTestsBase {
|
||||
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
|
||||
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
|
||||
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
|
||||
|
||||
Reference in New Issue
Block a user