Merge "Better IME transition while switching app with recents (6/N)" into sc-dev
This commit is contained in:
@@ -4107,8 +4107,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
* Callbacks when the given type of {@link WindowContainer} animation finished running in the
|
||||
* hierarchy.
|
||||
*/
|
||||
void onWindowAnimationFinished(int type) {
|
||||
void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
|
||||
if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
|
||||
// Unfreeze the insets state of the frozen target when the animation finished if exists.
|
||||
final Task task = wc.asTask();
|
||||
if (task != null) {
|
||||
task.forAllWindows(w -> {
|
||||
w.clearFrozenInsetsState();
|
||||
}, true /* traverseTopToBottom */);
|
||||
}
|
||||
removeImeSurfaceImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class InsetsStateController {
|
||||
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
|
||||
|
||||
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
|
||||
if (w.isVisible()) {
|
||||
if (w.isReadyToDispatchInsetsState()) {
|
||||
w.notifyInsetsChanged();
|
||||
}
|
||||
};
|
||||
@@ -117,7 +117,8 @@ class InsetsStateController {
|
||||
final @InternalInsetsType int type = provider != null
|
||||
? provider.getSource().getType() : ITYPE_INVALID;
|
||||
return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
|
||||
isAboveIme(target));
|
||||
isAboveIme(target),
|
||||
target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() : mState);
|
||||
}
|
||||
|
||||
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
||||
@@ -132,7 +133,7 @@ class InsetsStateController {
|
||||
final @WindowingMode int windowingMode = token != null
|
||||
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
||||
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
|
||||
return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token));
|
||||
return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token), mState);
|
||||
}
|
||||
|
||||
private boolean isAboveIme(WindowContainer target) {
|
||||
@@ -180,9 +181,8 @@ class InsetsStateController {
|
||||
* @see #getInsetsForWindowMetrics
|
||||
*/
|
||||
private InsetsState getInsetsForTarget(@InternalInsetsType int type,
|
||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
|
||||
InsetsState state = mState;
|
||||
|
||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme,
|
||||
@NonNull InsetsState state) {
|
||||
if (type != ITYPE_INVALID) {
|
||||
state = new InsetsState(state);
|
||||
state.removeSource(type);
|
||||
|
||||
@@ -2684,6 +2684,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
@Nullable ArrayList<WindowContainer> sources) {
|
||||
final Task task = asTask();
|
||||
if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
|
||||
if (AppTransition.isClosingTransitOld(transit)) {
|
||||
// Freezes the insets state when the window is in app exiting transition, to
|
||||
// ensure the exiting window won't receive unexpected insets changes from the
|
||||
// next window.
|
||||
task.forAllWindows(w -> {
|
||||
w.freezeInsetsState();
|
||||
}, true /* traverseTopToBottom */);
|
||||
}
|
||||
mDisplayContent.showImeScreenshot();
|
||||
}
|
||||
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
|
||||
@@ -2831,7 +2839,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
}
|
||||
mSurfaceAnimationSources.clear();
|
||||
if (mDisplayContent != null) {
|
||||
mDisplayContent.onWindowAnimationFinished(type);
|
||||
mDisplayContent.onWindowAnimationFinished(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -713,6 +713,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
private @Nullable InsetsSourceProvider mControllableInsetProvider;
|
||||
private final InsetsState mRequestedInsetsState = new InsetsState();
|
||||
|
||||
/**
|
||||
* Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
|
||||
* (e.g app exiting transition)
|
||||
*/
|
||||
private InsetsState mFrozenInsetsState;
|
||||
|
||||
@Nullable InsetsSourceProvider mPendingPositionChanged;
|
||||
|
||||
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
|
||||
@@ -758,6 +764,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a freeze state for the window to ignore dispatching its insets state to the client.
|
||||
*
|
||||
* Used to keep the insets state for some use cases. (e.g. app exiting transition)
|
||||
*/
|
||||
void freezeInsetsState() {
|
||||
if (mFrozenInsetsState == null) {
|
||||
mFrozenInsetsState = new InsetsState(getInsetsState(), true /* copySources */);
|
||||
}
|
||||
}
|
||||
|
||||
void clearFrozenInsetsState() {
|
||||
mFrozenInsetsState = null;
|
||||
}
|
||||
|
||||
InsetsState getFrozenInsetsState() {
|
||||
return mFrozenInsetsState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the insets state of the window is ready to dispatch to the client when invoking
|
||||
* {@link InsetsStateController#notifyInsetsChanged}.
|
||||
*/
|
||||
boolean isReadyToDispatchInsetsState() {
|
||||
return isVisible() && mFrozenInsetsState == null;
|
||||
}
|
||||
|
||||
void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
|
||||
@Rotation int rotation, boolean requested) {
|
||||
// Invisible windows and the wallpaper do not participate in the seamless rotation animation
|
||||
|
||||
@@ -22,6 +22,8 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
|
||||
@@ -978,6 +980,31 @@ public class WindowContainerTests extends WindowTestsBase {
|
||||
assertEquals(200, listener.mConfiguration.densityDpi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreezeInsetsStateWhenAppTransition() {
|
||||
final Task stack = createTaskStackOnDisplay(mDisplayContent);
|
||||
final Task task = createTaskInStack(stack, 0 /* userId */);
|
||||
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
|
||||
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
|
||||
task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
|
||||
spyOn(win);
|
||||
doReturn(true).when(task).okToAnimate();
|
||||
ArrayList<WindowContainer> sources = new ArrayList<>();
|
||||
sources.add(activity);
|
||||
|
||||
// Simulate the task applying the exit transition, verify the main window of the task
|
||||
// will be set the frozen insets state.
|
||||
task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
|
||||
false /* isVoiceInteraction */, sources);
|
||||
verify(win).freezeInsetsState();
|
||||
|
||||
// Simulate the task transition finished, verify the frozen insets state of the window
|
||||
// will be reset.
|
||||
task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
|
||||
task.mSurfaceAnimator.getAnimation());
|
||||
verify(win).clearFrozenInsetsState();
|
||||
}
|
||||
|
||||
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
|
||||
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
|
||||
private final int mLayer;
|
||||
|
||||
@@ -810,4 +810,27 @@ public class WindowStateTests extends WindowTestsBase {
|
||||
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFreezeInsetsState() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
spyOn(app);
|
||||
doReturn(true).when(app).isVisible();
|
||||
|
||||
// Set freezing the insets state to make the window ignore to dispatch insets changed.
|
||||
final InsetsState expectedState = new InsetsState(app.getInsetsState(),
|
||||
true /* copySources */);
|
||||
app.freezeInsetsState();
|
||||
assertEquals(expectedState, app.getFrozenInsetsState());
|
||||
assertFalse(app.isReadyToDispatchInsetsState());
|
||||
assertEquals(expectedState, app.getInsetsState());
|
||||
mDisplayContent.getInsetsStateController().notifyInsetsChanged();
|
||||
verify(app, never()).notifyInsetsChanged();
|
||||
|
||||
// Unfreeze the insets state to make the window can dispatch insets changed.
|
||||
app.clearFrozenInsetsState();
|
||||
assertTrue(app.isReadyToDispatchInsetsState());
|
||||
mDisplayContent.getInsetsStateController().notifyInsetsChanged();
|
||||
verify(app).notifyInsetsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user