diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index a580663cfa91c..9f32c03d1de4a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -185,8 +185,8 @@ public abstract class KeyguardAbsKeyInputViewController { + if (controller.isCancelled()) { + return; + } + Insets shownInsets = controller.getShownStateInsets(); + Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, + (int) (-shownInsets.bottom / 4 + * anim.getAnimatedFraction()))); + controller.setInsetsAndAlpha(insets, + (float) animation.getAnimatedValue(), + anim.getAnimatedFraction()); + }); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + controller.finish(false); + runOnFinishImeAnimationRunnable(); + finishRunnable.run(); + } + }); + anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); + anim.start(); + } + + @Override + public void onFinished( + @NonNull WindowInsetsAnimationController controller) { + } + + @Override + public void onCancelled( + @Nullable WindowInsetsAnimationController controller) { + } + }); + return true; + } + + + @Override + public void animateForIme(float interpolatedFraction, boolean appearingAnim) { animate().cancel(); - setAlpha(Math.max(interpolatedFraction, getAlpha())); + setAlpha(appearingAnim + ? Math.max(interpolatedFraction, getAlpha()) + : 1 - interpolatedFraction); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 57b8cf09556e3..e45dd8baa1d84 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -189,23 +189,22 @@ public class KeyguardPasswordViewController return; } if (wasDisabled) { - mInputMethodManager.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); + showInput(); } } @Override public void onResume(int reason) { super.onResume(reason); - - mPasswordEntry.requestFocus(); if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { showInput(); } } private void showInput() { - mPasswordEntry.post(() -> { - if (mPasswordEntry.isFocused() && mView.isShown()) { + mView.post(() -> { + if (mView.isShown()) { + mPasswordEntry.requestFocus(); mInputMethodManager.showSoftInput( mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); } @@ -214,7 +213,18 @@ public class KeyguardPasswordViewController @Override public void onPause() { - super.onPause(); + if (!mPasswordEntry.isVisibleToUser()) { + // Reset all states directly and then hide IME when the screen turned off. + super.onPause(); + } else { + // In order not to break the IME hide animation by resetting states too early after + // the password checked, make sure resetting states after the IME hiding animation + // finished. + mView.setOnFinishImeAnimationRunnable(() -> { + mPasswordEntry.clearFocus(); + super.onPause(); + }); + } mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index eaf8516ac1527..4887767b99224 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -23,11 +23,9 @@ import static java.lang.Integer.max; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; -import android.graphics.Insets; import android.graphics.Rect; import android.provider.Settings; import android.util.AttributeSet; @@ -42,12 +40,9 @@ import android.view.ViewConfiguration; import android.view.ViewPropertyAnimator; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; -import android.view.WindowInsetsAnimationControlListener; -import android.view.WindowInsetsAnimationController; import android.view.WindowManager; import android.widget.FrameLayout; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.dynamicanimation.animation.DynamicAnimation; @@ -130,6 +125,9 @@ public class KeyguardSecurityContainer extends FrameLayout { WindowInsetsAnimation.Bounds bounds) { if (!mDisappearAnimRunning) { beginJankInstrument(InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_APPEAR); + } else { + beginJankInstrument( + InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR); } mSecurityViewFlipper.getBoundsOnScreen(mFinalBounds); return bounds; @@ -138,25 +136,28 @@ public class KeyguardSecurityContainer extends FrameLayout { @Override public WindowInsets onProgress(WindowInsets windowInsets, List list) { - if (mDisappearAnimRunning) { - mSecurityViewFlipper.setTranslationY( - mInitialBounds.bottom - mFinalBounds.bottom); - } else { - int translationY = 0; - float interpolatedFraction = 1f; - for (WindowInsetsAnimation animation : list) { - if ((animation.getTypeMask() & WindowInsets.Type.ime()) == 0) { - continue; - } - interpolatedFraction = animation.getInterpolatedFraction(); - - final int paddingBottom = (int) MathUtils.lerp( - mInitialBounds.bottom - mFinalBounds.bottom, 0, - interpolatedFraction); - translationY += paddingBottom; + float start = mDisappearAnimRunning + ? -(mFinalBounds.bottom - mInitialBounds.bottom) + : mInitialBounds.bottom - mFinalBounds.bottom; + float end = mDisappearAnimRunning + ? -((mFinalBounds.bottom - mInitialBounds.bottom) * 0.75f) + : 0f; + int translationY = 0; + float interpolatedFraction = 1f; + for (WindowInsetsAnimation animation : list) { + if ((animation.getTypeMask() & WindowInsets.Type.ime()) == 0) { + continue; } - mSecurityViewFlipper.animateForIme(translationY, interpolatedFraction); + interpolatedFraction = animation.getInterpolatedFraction(); + + final int paddingBottom = (int) MathUtils.lerp( + start, end, + interpolatedFraction); + translationY += paddingBottom; } + mSecurityViewFlipper.animateForIme(translationY, interpolatedFraction, + !mDisappearAnimRunning); + return windowInsets; } @@ -164,7 +165,10 @@ public class KeyguardSecurityContainer extends FrameLayout { public void onEnd(WindowInsetsAnimation animation) { if (!mDisappearAnimRunning) { endJankInstrument(InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_APPEAR); - mSecurityViewFlipper.animateForIme(0, /* interpolatedFraction */ 1f); + mSecurityViewFlipper.animateForIme(0, /* interpolatedFraction */ 1f, + true /* appearingAnim */); + } else { + endJankInstrument(InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR); } } }; @@ -522,63 +526,6 @@ public class KeyguardSecurityContainer extends FrameLayout { public void startDisappearAnimation(SecurityMode securitySelection) { mDisappearAnimRunning = true; - if (securitySelection == SecurityMode.Password) { - mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(), - IME_DISAPPEAR_DURATION_MS, - Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() { - - - @Override - public void onReady(@NonNull WindowInsetsAnimationController controller, - int types) { - ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f); - anim.addUpdateListener(animation -> { - if (controller.isCancelled()) { - return; - } - Insets shownInsets = controller.getShownStateInsets(); - Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, - (int) (-shownInsets.bottom / 4 - * anim.getAnimatedFraction()))); - controller.setInsetsAndAlpha(insets, - (float) animation.getAnimatedValue(), - anim.getAnimatedFraction()); - }); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - beginJankInstrument( - InteractionJankMonitor - .CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR); - } - - @Override - public void onAnimationEnd(Animator animation) { - endJankInstrument( - InteractionJankMonitor - .CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR); - controller.finish(false); - } - }); - anim.setDuration(IME_DISAPPEAR_DURATION_MS); - anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); - anim.start(); - } - - @Override - public void onFinished( - @NonNull WindowInsetsAnimationController controller) { - mDisappearAnimRunning = false; - } - - @Override - public void onCancelled( - @Nullable WindowInsetsAnimationController controller) { - cancelJankInstrument( - InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR); - } - }); - } } private void beginJankInstrument(int cuj) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java index 75ef4b32dfdaa..e01e17dc60061 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java @@ -87,10 +87,10 @@ public class KeyguardSecurityViewFlipper extends ViewFlipper { * Translate the entire view, and optionally inform the wrapped view of the progress * so it can animate with the parent. */ - public void animateForIme(int translationY, float interpolatedFraction) { + public void animateForIme(int translationY, float interpolatedFraction, boolean appearingAnim) { super.setTranslationY(translationY); KeyguardInputView v = getSecurityView(); - if (v != null) v.animateForIme(interpolatedFraction); + if (v != null) v.animateForIme(interpolatedFraction, appearingAnim); } @Override diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 49ba646420a36..62722778384ba 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -16,13 +16,19 @@ package com.android.keyguard; +import static android.view.WindowInsets.Type.ime; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.res.Resources; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.WindowInsetsController; @@ -33,6 +39,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.FalsingManager; @@ -84,18 +91,34 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Mock private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; @Mock + private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory; + @Mock + private KeyguardMessageArea mKeyguardMessageArea; + @Mock private ConfigurationController mConfigurationController; @Mock private KeyguardViewController mKeyguardViewController; private FalsingManager mFalsingManager = new FalsingManagerFake(); private KeyguardSecurityContainerController mKeyguardSecurityContainerController; + private KeyguardPasswordViewController mKeyguardPasswordViewController; + private KeyguardPasswordView mKeyguardPasswordView; @Before public void setup() { when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class))) .thenReturn(mAdminSecondaryLockScreenController); when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); + mKeyguardPasswordView = spy(new KeyguardPasswordView(getContext())); + when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper); + when(mKeyguardPasswordView.findViewById(R.id.keyguard_message_area)) + .thenReturn(mKeyguardMessageArea); + when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController); + mKeyguardPasswordViewController = new KeyguardPasswordViewController( + (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor, + SecurityMode.Password, mLockPatternUtils, null, + mKeyguardMessageAreaControllerFactory, null, null, null, mock(Resources.class), + null); mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory( mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, @@ -125,14 +148,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { public void startDisappearAnimation_animatesKeyboard() { when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn( SecurityMode.Password); - when(mInputViewController.getSecurityMode()).thenReturn( - SecurityMode.Password); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) - .thenReturn(mInputViewController); - mKeyguardSecurityContainerController.showPrimarySecurityScreen(false /* turningOff */); + .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); + mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); mKeyguardSecurityContainerController.startDisappearAnimation(null); - verify(mInputViewController).startDisappearAnimation(eq(null)); + verify(mWindowInsetsController).controlWindowInsetsAnimation( + eq(ime()), anyLong(), any(), any(), any()); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 1783fa4112b88..104318e0f4aef 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -19,9 +19,6 @@ package com.android.keyguard; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -89,13 +86,6 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } - @Test - public void startDisappearAnimation_animatesKeyboard() { - mKeyguardSecurityContainer.startDisappearAnimation(SecurityMode.Password); - verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(), - any(), any()); - } - @Test public void onMeasure_usesFullWidthWithoutOneHandedMode() { setUpKeyguard(