Merge "Don't skip IME animation when backed to Task has no editor focus" into sc-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user