Merge "Don't skip IME animation when backed to Task has no editor focus" into sc-dev

This commit is contained in:
Ming-Shin Lu
2021-03-30 03:10:21 +00:00
committed by Android (Google) Code Review
6 changed files with 69 additions and 24 deletions

View File

@@ -51,8 +51,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
@Override
public void onWindowFocusGained() {
super.onWindowFocusGained();
public void onWindowFocusGained(boolean hasViewFocus) {
super.onWindowFocusGained(hasViewFocus);
getImm().registerImeConsumer(this);
}

View File

@@ -1302,8 +1302,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
/**
* Called when current window gains focus.
*/
public void onWindowFocusGained() {
getSourceConsumer(ITYPE_IME).onWindowFocusGained();
public void onWindowFocusGained(boolean hasViewFocused) {
getSourceConsumer(ITYPE_IME).onWindowFocusGained(hasViewFocused);
}
/**
@@ -1366,8 +1366,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
final InsetsSourceControl imeControl = consumer != null ? consumer.getControl() : null;
// Skip showing animation once that made by system for some reason.
// (e.g. starting window with IME snapshot)
if (imeControl != null && show) {
skipAnim = imeControl.getAndClearSkipAnimationOnce();
if (imeControl != null) {
skipAnim = imeControl.getAndClearSkipAnimationOnce() && show
&& consumer.hasViewFocusWhenWindowFocusGain();
}
}
applyAnimation(types, show, fromIme, skipAnim);

View File

@@ -81,6 +81,11 @@ public class InsetsSourceConsumer {
private final Supplier<Transaction> mTransactionSupplier;
private @Nullable InsetsSourceControl mSourceControl;
private boolean mHasWindowFocus;
/**
* Whether the view has focus returned by {@link #onWindowFocusGained(boolean)}.
*/
private boolean mHasViewFocusWhenWindowFocusGain;
private Rect mPendingFrame;
private Rect mPendingVisibleFrame;
@@ -223,8 +228,9 @@ public class InsetsSourceConsumer {
/**
* Called when current window gains focus
*/
public void onWindowFocusGained() {
public void onWindowFocusGained(boolean hasViewFocus) {
mHasWindowFocus = true;
mHasViewFocusWhenWindowFocusGain = hasViewFocus;
}
/**
@@ -238,6 +244,10 @@ public class InsetsSourceConsumer {
return mHasWindowFocus;
}
boolean hasViewFocusWhenWindowFocusGain() {
return mHasViewFocusWhenWindowFocusGain;
}
boolean applyLocalVisibilityOverride() {
final InsetsSource source = mState.peekSource(mType);
final boolean isVisible = source != null ? source.isVisible() : getDefaultVisibility(mType);

View File

@@ -3344,8 +3344,9 @@ public final class ViewRootImpl implements ViewParent,
}
// TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback
// config changes.
final View focusedView = mView != null ? mView.findFocus() : null;
if (hasWindowFocus) {
mInsetsController.onWindowFocusGained();
mInsetsController.onWindowFocusGained(focusedView != null /* hasViewFocused */);
} else {
mInsetsController.onWindowFocusLost();
}
@@ -3394,8 +3395,7 @@ public final class ViewRootImpl implements ViewParent,
// Note: must be done after the focus change callbacks,
// so all of the view state is set up correctly.
mImeFocusController.onPostWindowFocus(mView != null ? mView.findFocus() : null,
hasWindowFocus, mWindowAttributes);
mImeFocusController.onPostWindowFocus(focusedView, hasWindowFocus, mWindowAttributes);
if (hasWindowFocus) {
// Clear the forward bit. We can just do this directly, since

View File

@@ -97,7 +97,7 @@ public class ImeInsetsSourceConsumerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// test if setVisibility can show IME
mImeConsumer.onWindowFocusGained();
mImeConsumer.onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -116,7 +116,7 @@ public class ImeInsetsSourceConsumerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// Request IME visible before control is available.
mImeConsumer.onWindowFocusGained();
mImeConsumer.onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */);
// set control and verify visibility is applied.
@@ -132,24 +132,58 @@ public class ImeInsetsSourceConsumerTest {
}
@Test
public void testImeGetAndClearSkipAnimationOnce() {
public void testImeGetAndClearSkipAnimationOnce_expectSkip() {
// Expect IME animation will skipped when the IME is visible at first place.
verifyImeGetAndClearSkipAnimationOnce(true /* hasWindowFocus */, true /* hasViewFocus */,
true /* expectSkipAnim */);
}
@Test
public void testImeGetAndClearSkipAnimationOnce_expectNoSkip() {
// Expect IME animation will not skipped if previously no view focused when gained the
// window focus and requesting the IME visible next time.
verifyImeGetAndClearSkipAnimationOnce(true /* hasWindowFocus */, false /* hasViewFocus */,
false /* expectSkipAnim */);
}
private void verifyImeGetAndClearSkipAnimationOnce(boolean hasWindowFocus, boolean hasViewFocus,
boolean expectSkipAnim) {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// Request IME visible before control is available.
mImeConsumer.onWindowFocusGained();
mController.show(WindowInsets.Type.ime(), true /* fromIme */);
mImeConsumer.onWindowFocusGained(hasWindowFocus);
final boolean imeVisible = hasWindowFocus && hasViewFocus;
if (imeVisible) {
mController.show(WindowInsets.Type.ime(), true /* fromIme */);
}
// set control and verify visibility is applied.
InsetsSourceControl control = Mockito.spy(
new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE));
// Simulate IME source control set this flag when the target has starting window.
control.setSkipAnimationOnce(true);
mController.onControlsChanged(new InsetsSourceControl[] { control });
// Verify IME show animation should be triggered when control becomes available and
// the animation will be skipped by getAndClearSkipAnimationOnce invoked.
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
eq(true) /* skipAnim */);
if (imeVisible) {
// Verify IME applyAnimation should be triggered when control becomes available,
// and expect skip animation state after getAndClearSkipAnimationOnce invoked.
mController.onControlsChanged(new InsetsSourceControl[]{ control });
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(false) /* fromIme */,
eq(expectSkipAnim) /* skipAnim */);
}
// If previously hasViewFocus is false, verify when requesting the IME visible next
// time will not skip animation.
if (!hasViewFocus) {
mController.show(WindowInsets.Type.ime(), true);
mController.onControlsChanged(new InsetsSourceControl[]{ control });
// Verify IME show animation should be triggered when control becomes available and
// the animation will be skipped by getAndClearSkipAnimationOnce invoked.
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(true) /* fromIme */,
eq(false) /* skipAnim */);
}
});
}
}

View File

@@ -234,7 +234,7 @@ public class InsetsControllerTest {
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible.
mController.show(Type.ime(), true /* fromIme */);
mController.show(Type.all());
@@ -260,7 +260,7 @@ public class InsetsControllerTest {
InsetsSourceControl ime = createControl(ITYPE_IME);
mController.onControlsChanged(new InsetsSourceControl[] { ime });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true);
mController.show(Type.ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());