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
|
* Callbacks when the given type of {@link WindowContainer} animation finished running in the
|
||||||
* hierarchy.
|
* hierarchy.
|
||||||
*/
|
*/
|
||||||
void onWindowAnimationFinished(int type) {
|
void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
|
||||||
if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
|
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();
|
removeImeSurfaceImmediately();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class InsetsStateController {
|
|||||||
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
|
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
|
||||||
|
|
||||||
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
|
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
|
||||||
if (w.isVisible()) {
|
if (w.isReadyToDispatchInsetsState()) {
|
||||||
w.notifyInsetsChanged();
|
w.notifyInsetsChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -117,7 +117,8 @@ class InsetsStateController {
|
|||||||
final @InternalInsetsType int type = provider != null
|
final @InternalInsetsType int type = provider != null
|
||||||
? provider.getSource().getType() : ITYPE_INVALID;
|
? provider.getSource().getType() : ITYPE_INVALID;
|
||||||
return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
|
return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
|
||||||
isAboveIme(target));
|
isAboveIme(target),
|
||||||
|
target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() : mState);
|
||||||
}
|
}
|
||||||
|
|
||||||
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
||||||
@@ -132,7 +133,7 @@ class InsetsStateController {
|
|||||||
final @WindowingMode int windowingMode = token != null
|
final @WindowingMode int windowingMode = token != null
|
||||||
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
||||||
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
|
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) {
|
private boolean isAboveIme(WindowContainer target) {
|
||||||
@@ -180,9 +181,8 @@ class InsetsStateController {
|
|||||||
* @see #getInsetsForWindowMetrics
|
* @see #getInsetsForWindowMetrics
|
||||||
*/
|
*/
|
||||||
private InsetsState getInsetsForTarget(@InternalInsetsType int type,
|
private InsetsState getInsetsForTarget(@InternalInsetsType int type,
|
||||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
|
@WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme,
|
||||||
InsetsState state = mState;
|
@NonNull InsetsState state) {
|
||||||
|
|
||||||
if (type != ITYPE_INVALID) {
|
if (type != ITYPE_INVALID) {
|
||||||
state = new InsetsState(state);
|
state = new InsetsState(state);
|
||||||
state.removeSource(type);
|
state.removeSource(type);
|
||||||
|
|||||||
@@ -2684,6 +2684,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
|||||||
@Nullable ArrayList<WindowContainer> sources) {
|
@Nullable ArrayList<WindowContainer> sources) {
|
||||||
final Task task = asTask();
|
final Task task = asTask();
|
||||||
if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
|
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();
|
mDisplayContent.showImeScreenshot();
|
||||||
}
|
}
|
||||||
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
|
final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
|
||||||
@@ -2831,7 +2839,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
|||||||
}
|
}
|
||||||
mSurfaceAnimationSources.clear();
|
mSurfaceAnimationSources.clear();
|
||||||
if (mDisplayContent != null) {
|
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 @Nullable InsetsSourceProvider mControllableInsetProvider;
|
||||||
private final InsetsState mRequestedInsetsState = new InsetsState();
|
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;
|
@Nullable InsetsSourceProvider mPendingPositionChanged;
|
||||||
|
|
||||||
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
|
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,
|
void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
|
||||||
@Rotation int rotation, boolean requested) {
|
@Rotation int rotation, boolean requested) {
|
||||||
// Invisible windows and the wallpaper do not participate in the seamless rotation animation
|
// 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_UNSET;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
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_OLD_TASK_OPEN;
|
||||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||||
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
|
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
|
||||||
@@ -978,6 +980,31 @@ public class WindowContainerTests extends WindowTestsBase {
|
|||||||
assertEquals(200, listener.mConfiguration.densityDpi);
|
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 */
|
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
|
||||||
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
|
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
|
||||||
private final int mLayer;
|
private final int mLayer;
|
||||||
|
|||||||
@@ -810,4 +810,27 @@ public class WindowStateTests extends WindowTestsBase {
|
|||||||
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||||
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
|
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