diff options
| author | 2022-06-16 18:09:33 -0400 | |
|---|---|---|
| committer | 2022-06-21 15:29:40 -0400 | |
| commit | fde796bc6a88e96905ff3fc1a8a68d0d3a37b677 (patch) | |
| tree | e73c1ffdb68211a3a19603b5ecff00c3dc4d2969 | |
| parent | fd8aa55ee36b8a6201eb6303ef2d3acbfc392226 (diff) | |
2/2 Making bouncer shift on double tap when user chooser is visible
This change adds nice animation when bouncer/security swap sides with user chooser view.
The main changes are:
- extracting security animation code to SidedSecurityMode superclass and adding listener to security alpha during animation so that user chooser view can synchronize its alpha along with it.
- user switcher mode doesn't use gravity anymore to position views horizontally, now it uses X translation, just like one handed mode
Bouncer animation doesn't change at all compared to one handed mode and user chooser: fades out when bouncer fades out, shifts to the destination position and then fades in when bouncer fades in.
Bug: 220872694
Test: KeyguardSecurityContainerTest + open bouncer with user chooser on the side, double tap on the other side of the bouncer, see views swap positions with nice animation
Change-Id: I6ed2d2a6006063f63a8f9edf6da47abbfb7efb45
3 files changed, 239 insertions, 169 deletions
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index 77f1803523a8..acf3e4dcf02a 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -102,12 +102,13 @@ screen. --> <item name="half_opened_bouncer_height_ratio" type="dimen" format="float">0.0</item> - <!-- The actual amount of translation that is applied to the bouncer when it animates from one - side of the screen to the other in one-handed mode. Note that it will always translate from - the side of the screen to the other (it will "jump" closer to the destination while the - opacity is zero), but this controls how much motion will actually be applied to it while - animating. Larger values will cause it to move "faster" while fading out/in. --> - <dimen name="one_handed_bouncer_move_animation_translation">120dp</dimen> + <!-- The actual amount of translation that is applied to the security when it animates from one + side of the screen to the other in one-handed or user switcher mode. Note that it will + always translate from the side of the screen to the other (it will "jump" closer to the + destination while the opacity is zero), but this controls how much motion will actually be + applied to it while animating. Larger values will cause it to move "faster" while + fading out/in. --> + <dimen name="security_shift_animation_translation">120dp</dimen> <dimen name="bouncer_user_switcher_header_text_size">20sp</dimen> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 11519bf38516..8fb622a8c55e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -94,6 +94,7 @@ import com.android.systemui.util.settings.GlobalSettings; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; public class KeyguardSecurityContainer extends FrameLayout { static final int USER_TYPE_PRIMARY = 1; @@ -128,12 +129,12 @@ public class KeyguardSecurityContainer extends FrameLayout { private static final long IME_DISAPPEAR_DURATION_MS = 125; - // The duration of the animation to switch bouncer sides. - private static final long BOUNCER_HANDEDNESS_ANIMATION_DURATION_MS = 500; + // The duration of the animation to switch security sides. + private static final long SECURITY_SHIFT_ANIMATION_DURATION_MS = 500; - // How much of the switch sides animation should be dedicated to fading the bouncer out. The + // How much of the switch sides animation should be dedicated to fading the security out. The // remainder will fade it back in again. - private static final float BOUNCER_HANDEDNESS_ANIMATION_FADE_OUT_PROPORTION = 0.2f; + private static final float SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION = 0.2f; @VisibleForTesting KeyguardSecurityViewFlipper mSecurityViewFlipper; @@ -796,12 +797,16 @@ public class KeyguardSecurityContainer extends FrameLayout { * screen devices */ abstract static class SidedSecurityMode implements ViewMode { + @Nullable private ValueAnimator mRunningSecurityShiftAnimator; + private KeyguardSecurityViewFlipper mViewFlipper; private ViewGroup mView; private GlobalSettings mGlobalSettings; private int mDefaultSideSetting; - public void init(ViewGroup v, GlobalSettings globalSettings, boolean leftAlignedByDefault) { + public void init(ViewGroup v, KeyguardSecurityViewFlipper viewFlipper, + GlobalSettings globalSettings, boolean leftAlignedByDefault) { mView = v; + mViewFlipper = viewFlipper; mGlobalSettings = globalSettings; mDefaultSideSetting = leftAlignedByDefault ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT @@ -841,6 +846,127 @@ public class KeyguardSecurityContainer extends FrameLayout { protected abstract void updateSecurityViewLocation(boolean leftAlign, boolean animate); + protected void translateSecurityViewLocation(boolean leftAlign, boolean animate) { + translateSecurityViewLocation(leftAlign, animate, i -> {}); + } + + /** + * Moves the inner security view to the correct location with animation. This is triggered + * when the user double taps on the side of the screen that is not currently occupied by + * the security view. + */ + protected void translateSecurityViewLocation(boolean leftAlign, boolean animate, + Consumer<Float> securityAlphaListener) { + if (mRunningSecurityShiftAnimator != null) { + mRunningSecurityShiftAnimator.cancel(); + mRunningSecurityShiftAnimator = null; + } + + int targetTranslation = leftAlign + ? 0 : mView.getMeasuredWidth() - mViewFlipper.getWidth(); + + if (animate) { + // This animation is a bit fun to implement. The bouncer needs to move, and fade + // in/out at the same time. The issue is, the bouncer should only move a short + // amount (120dp or so), but obviously needs to go from one side of the screen to + // the other. This needs a pretty custom animation. + // + // This works as follows. It uses a ValueAnimation to simply drive the animation + // progress. This animator is responsible for both the translation of the bouncer, + // and the current fade. It will fade the bouncer out while also moving it along the + // 120dp path. Once the bouncer is fully faded out though, it will "snap" the + // bouncer closer to its destination, then fade it back in again. The effect is that + // the bouncer will move from 0 -> X while fading out, then + // (destination - X) -> destination while fading back in again. + // TODO(b/208250221): Make this animation properly abortable. + Interpolator positionInterpolator = AnimationUtils.loadInterpolator( + mView.getContext(), android.R.interpolator.fast_out_extra_slow_in); + Interpolator fadeOutInterpolator = Interpolators.FAST_OUT_LINEAR_IN; + Interpolator fadeInInterpolator = Interpolators.LINEAR_OUT_SLOW_IN; + + mRunningSecurityShiftAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); + mRunningSecurityShiftAnimator.setDuration(SECURITY_SHIFT_ANIMATION_DURATION_MS); + mRunningSecurityShiftAnimator.setInterpolator(Interpolators.LINEAR); + + int initialTranslation = (int) mViewFlipper.getTranslationX(); + int totalTranslation = (int) mView.getResources().getDimension( + R.dimen.security_shift_animation_translation); + + final boolean shouldRestoreLayerType = mViewFlipper.hasOverlappingRendering() + && mViewFlipper.getLayerType() != View.LAYER_TYPE_HARDWARE; + if (shouldRestoreLayerType) { + mViewFlipper.setLayerType(View.LAYER_TYPE_HARDWARE, /* paint= */null); + } + + float initialAlpha = mViewFlipper.getAlpha(); + + mRunningSecurityShiftAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mRunningSecurityShiftAnimator = null; + } + }); + mRunningSecurityShiftAnimator.addUpdateListener(animation -> { + float switchPoint = SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION; + boolean isFadingOut = animation.getAnimatedFraction() < switchPoint; + + int currentTranslation = (int) (positionInterpolator.getInterpolation( + animation.getAnimatedFraction()) * totalTranslation); + int translationRemaining = totalTranslation - currentTranslation; + + // Flip the sign if we're going from right to left. + if (leftAlign) { + currentTranslation = -currentTranslation; + translationRemaining = -translationRemaining; + } + + float opacity; + if (isFadingOut) { + // The bouncer fades out over the first X%. + float fadeOutFraction = MathUtils.constrainedMap( + /* rangeMin= */1.0f, + /* rangeMax= */0.0f, + /* valueMin= */0.0f, + /* valueMax= */switchPoint, + animation.getAnimatedFraction()); + opacity = fadeOutInterpolator.getInterpolation(fadeOutFraction); + + // When fading out, the alpha needs to start from the initial opacity of the + // view flipper, otherwise we get a weird bit of jank as it ramps back to + // 100%. + mViewFlipper.setAlpha(opacity * initialAlpha); + + // Animate away from the source. + mViewFlipper.setTranslationX(initialTranslation + currentTranslation); + } else { + // And in again over the remaining (100-X)%. + float fadeInFraction = MathUtils.constrainedMap( + /* rangeMin= */0.0f, + /* rangeMax= */1.0f, + /* valueMin= */switchPoint, + /* valueMax= */1.0f, + animation.getAnimatedFraction()); + + opacity = fadeInInterpolator.getInterpolation(fadeInFraction); + mViewFlipper.setAlpha(opacity); + + // Fading back in, animate towards the destination. + mViewFlipper.setTranslationX(targetTranslation - translationRemaining); + } + securityAlphaListener.accept(opacity); + + if (animation.getAnimatedFraction() == 1.0f && shouldRestoreLayerType) { + mViewFlipper.setLayerType(View.LAYER_TYPE_NONE, /* paint= */null); + } + }); + + mRunningSecurityShiftAnimator.start(); + } else { + mViewFlipper.setTranslationX(targetTranslation); + } + } + + boolean isLeftAligned() { return mGlobalSettings.getInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE, mDefaultSideSetting) @@ -899,12 +1025,15 @@ public class KeyguardSecurityContainer extends FrameLayout { private UserSwitcherController.UserSwitchCallback mUserSwitchCallback = this::setupUserSwitcher; + private float mAnimationLastAlpha = 1f; + private boolean mAnimationWaitsToShift = true; + @Override public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings, @NonNull KeyguardSecurityViewFlipper viewFlipper, @NonNull FalsingManager falsingManager, @NonNull UserSwitcherController userSwitcherController) { - init(v, globalSettings, /* leftAlignedByDefault= */false); + init(v, viewFlipper, globalSettings, /* leftAlignedByDefault= */false); mView = v; mViewFlipper = viewFlipper; mFalsingManager = falsingManager; @@ -918,9 +1047,7 @@ public class KeyguardSecurityContainer extends FrameLayout { true); mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher); } - updateSecurityViewLocation(); - mUserSwitcher = mView.findViewById(R.id.user_switcher_header); setupUserSwitcher(); mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback); @@ -1120,22 +1247,61 @@ public class KeyguardSecurityContainer extends FrameLayout { } public void updateSecurityViewLocation(boolean leftAlign, boolean animate) { - int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans); + setYTranslation(); + setGravity(); + setXTranslation(leftAlign, animate); + } + private void setXTranslation(boolean leftAlign, boolean animate) { + if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + mUserSwitcherViewGroup.setTranslationX(0); + mViewFlipper.setTranslationX(0); + } else { + int switcherTargetTranslation = leftAlign + ? mView.getMeasuredWidth() - mViewFlipper.getWidth() : 0; + if (animate) { + mAnimationWaitsToShift = true; + mAnimationLastAlpha = 1f; + translateSecurityViewLocation(leftAlign, animate, securityAlpha -> { + // During the animation security view fades out - alpha goes from 1 to + // (almost) 0 - and then fades in - alpha grows back to 1. + // If new alpha is bigger than previous one it means we're at inflection + // point and alpha is zero or almost zero. That's when we want to do + // translation of user switcher, so that it's not visible to the user. + boolean fullyFadeOut = securityAlpha == 0.0f + || securityAlpha > mAnimationLastAlpha; + if (fullyFadeOut && mAnimationWaitsToShift) { + mUserSwitcherViewGroup.setTranslationX(switcherTargetTranslation); + mAnimationWaitsToShift = false; + } + mUserSwitcherViewGroup.setAlpha(securityAlpha); + mAnimationLastAlpha = securityAlpha; + }); + } else { + translateSecurityViewLocation(leftAlign, animate); + mUserSwitcherViewGroup.setTranslationX(switcherTargetTranslation); + } + } + + } + + private void setGravity() { if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - updateViewGravity(mViewFlipper, Gravity.CENTER_HORIZONTAL); updateViewGravity(mUserSwitcherViewGroup, Gravity.CENTER_HORIZONTAL); + updateViewGravity(mViewFlipper, Gravity.CENTER_HORIZONTAL); + } else { + // horizontal gravity is the same because we translate these views anyway + updateViewGravity(mViewFlipper, Gravity.LEFT | Gravity.BOTTOM); + updateViewGravity(mUserSwitcherViewGroup, Gravity.LEFT | Gravity.CENTER_VERTICAL); + } + } + private void setYTranslation() { + int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans); + if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { mUserSwitcherViewGroup.setTranslationY(yTrans); mViewFlipper.setTranslationY(-yTrans); } else { - int securityHorizontalGravity = leftAlign ? Gravity.LEFT : Gravity.RIGHT; - int userSwitcherHorizontalGravity = - securityHorizontalGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT; - updateViewGravity(mViewFlipper, securityHorizontalGravity | Gravity.BOTTOM); - updateViewGravity(mUserSwitcherViewGroup, - userSwitcherHorizontalGravity | Gravity.CENTER_VERTICAL); - // Attempt to reposition a bit higher to make up for this frame being a bit lower // on the device mUserSwitcherViewGroup.setTranslationY(-yTrans); @@ -1155,7 +1321,6 @@ public class KeyguardSecurityContainer extends FrameLayout { * between alternate sides of the display. */ static class OneHandedViewMode extends SidedSecurityMode { - @Nullable private ValueAnimator mRunningOneHandedAnimator; private ViewGroup mView; private KeyguardSecurityViewFlipper mViewFlipper; @@ -1164,7 +1329,7 @@ public class KeyguardSecurityContainer extends FrameLayout { @NonNull KeyguardSecurityViewFlipper viewFlipper, @NonNull FalsingManager falsingManager, @NonNull UserSwitcherController userSwitcherController) { - init(v, globalSettings, /* leftAlignedByDefault= */true); + init(v, viewFlipper, globalSettings, /* leftAlignedByDefault= */true); mView = v; mViewFlipper = viewFlipper; @@ -1205,117 +1370,8 @@ public class KeyguardSecurityContainer extends FrameLayout { updateSecurityViewLocation(isLeftAligned(), /* animate= */false); } - /** - * Moves the inner security view to the correct location (in one handed mode) with - * animation. This is triggered when the user double taps on the side of the screen that is - * not currently occupied by the security view. - */ protected void updateSecurityViewLocation(boolean leftAlign, boolean animate) { - if (mRunningOneHandedAnimator != null) { - mRunningOneHandedAnimator.cancel(); - mRunningOneHandedAnimator = null; - } - - int targetTranslation = leftAlign - ? 0 : (int) (mView.getMeasuredWidth() - mViewFlipper.getWidth()); - - if (animate) { - // This animation is a bit fun to implement. The bouncer needs to move, and fade - // in/out at the same time. The issue is, the bouncer should only move a short - // amount (120dp or so), but obviously needs to go from one side of the screen to - // the other. This needs a pretty custom animation. - // - // This works as follows. It uses a ValueAnimation to simply drive the animation - // progress. This animator is responsible for both the translation of the bouncer, - // and the current fade. It will fade the bouncer out while also moving it along the - // 120dp path. Once the bouncer is fully faded out though, it will "snap" the - // bouncer closer to its destination, then fade it back in again. The effect is that - // the bouncer will move from 0 -> X while fading out, then - // (destination - X) -> destination while fading back in again. - // TODO(b/208250221): Make this animation properly abortable. - Interpolator positionInterpolator = AnimationUtils.loadInterpolator( - mView.getContext(), android.R.interpolator.fast_out_extra_slow_in); - Interpolator fadeOutInterpolator = Interpolators.FAST_OUT_LINEAR_IN; - Interpolator fadeInInterpolator = Interpolators.LINEAR_OUT_SLOW_IN; - - mRunningOneHandedAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - mRunningOneHandedAnimator.setDuration(BOUNCER_HANDEDNESS_ANIMATION_DURATION_MS); - mRunningOneHandedAnimator.setInterpolator(Interpolators.LINEAR); - - int initialTranslation = (int) mViewFlipper.getTranslationX(); - int totalTranslation = (int) mView.getResources().getDimension( - R.dimen.one_handed_bouncer_move_animation_translation); - - final boolean shouldRestoreLayerType = mViewFlipper.hasOverlappingRendering() - && mViewFlipper.getLayerType() != View.LAYER_TYPE_HARDWARE; - if (shouldRestoreLayerType) { - mViewFlipper.setLayerType(View.LAYER_TYPE_HARDWARE, /* paint= */null); - } - - float initialAlpha = mViewFlipper.getAlpha(); - - mRunningOneHandedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mRunningOneHandedAnimator = null; - } - }); - mRunningOneHandedAnimator.addUpdateListener(animation -> { - float switchPoint = BOUNCER_HANDEDNESS_ANIMATION_FADE_OUT_PROPORTION; - boolean isFadingOut = animation.getAnimatedFraction() < switchPoint; - - int currentTranslation = (int) (positionInterpolator.getInterpolation( - animation.getAnimatedFraction()) * totalTranslation); - int translationRemaining = totalTranslation - currentTranslation; - - // Flip the sign if we're going from right to left. - if (leftAlign) { - currentTranslation = -currentTranslation; - translationRemaining = -translationRemaining; - } - - if (isFadingOut) { - // The bouncer fades out over the first X%. - float fadeOutFraction = MathUtils.constrainedMap( - /* rangeMin= */1.0f, - /* rangeMax= */0.0f, - /* valueMin= */0.0f, - /* valueMax= */switchPoint, - animation.getAnimatedFraction()); - float opacity = fadeOutInterpolator.getInterpolation(fadeOutFraction); - - // When fading out, the alpha needs to start from the initial opacity of the - // view flipper, otherwise we get a weird bit of jank as it ramps back to - // 100%. - mViewFlipper.setAlpha(opacity * initialAlpha); - - // Animate away from the source. - mViewFlipper.setTranslationX(initialTranslation + currentTranslation); - } else { - // And in again over the remaining (100-X)%. - float fadeInFraction = MathUtils.constrainedMap( - /* rangeMin= */0.0f, - /* rangeMax= */1.0f, - /* valueMin= */switchPoint, - /* valueMax= */1.0f, - animation.getAnimatedFraction()); - - float opacity = fadeInInterpolator.getInterpolation(fadeInFraction); - mViewFlipper.setAlpha(opacity); - - // Fading back in, animate towards the destination. - mViewFlipper.setTranslationX(targetTranslation - translationRemaining); - } - - if (animation.getAnimatedFraction() == 1.0f && shouldRestoreLayerType) { - mViewFlipper.setLayerType(View.LAYER_TYPE_NONE, /* paint= */null); - } - }); - - mRunningOneHandedAnimator.start(); - } else { - mViewFlipper.setTranslationX(targetTranslation); - } + translateSecurityViewLocation(leftAlign, animate); } } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 1b9662ccae0c..f2ac0c7a7736 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE; import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; import static android.provider.Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT; @@ -46,7 +48,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; -import android.view.WindowInsetsController; import android.widget.FrameLayout; import androidx.test.filters.SmallTest; @@ -85,8 +86,6 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { public MockitoRule mRule = MockitoJUnit.rule(); @Mock - private WindowInsetsController mWindowInsetsController; - @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; @Mock private GlobalSettings mGlobalSettings; @@ -110,7 +109,6 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mSecurityViewFlipperLayoutParams = new FrameLayout.LayoutParams( MATCH_PARENT, MATCH_PARENT); - when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams); mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; @@ -221,7 +219,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mKeyguardSecurityContainer.getWidth() - 1f); verify(mGlobalSettings).putInt(ONE_HANDED_KEYGUARD_SIDE, ONE_HANDED_KEYGUARD_SIDE_RIGHT); - verify(mSecurityViewFlipper).setTranslationX( + assertSecurityTranslationX( mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth()); mKeyguardSecurityContainer.updatePositionByTouchX(1f); @@ -243,43 +241,43 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { } @Test - public void testUserSwitcherModeViewGravityLandscape() { + public void testUserSwitcherModeViewPositionLandscape() { // GIVEN one user has been setup and in landscape when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(1)); - Configuration config = new Configuration(); - config.orientation = Configuration.ORIENTATION_LANDSCAPE; - when(getContext().getResources().getConfiguration()).thenReturn(config); + Configuration landscapeConfig = configuration(ORIENTATION_LANDSCAPE); + when(getContext().getResources().getConfiguration()).thenReturn(landscapeConfig); // WHEN UserSwitcherViewMode is initialized and config has changed setupUserSwitcher(); - reset(mSecurityViewFlipper); - when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams); - mKeyguardSecurityContainer.onConfigurationChanged(config); + mKeyguardSecurityContainer.onConfigurationChanged(landscapeConfig); // THEN views are oriented side by side - verify(mSecurityViewFlipper).setLayoutParams(mLayoutCaptor.capture()); - assertThat(mLayoutCaptor.getValue().gravity).isEqualTo(Gravity.RIGHT | Gravity.BOTTOM); + assertSecurityGravity(Gravity.LEFT | Gravity.BOTTOM); assertUserSwitcherGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + assertSecurityTranslationX( + mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth()); + assertUserSwitcherTranslationX(0f); + } @Test public void testUserSwitcherModeViewGravityPortrait() { // GIVEN one user has been setup and in landscape when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(1)); - Configuration config = new Configuration(); - config.orientation = Configuration.ORIENTATION_PORTRAIT; - when(getContext().getResources().getConfiguration()).thenReturn(config); + Configuration portraitConfig = configuration(ORIENTATION_PORTRAIT); + when(getContext().getResources().getConfiguration()).thenReturn(portraitConfig); // WHEN UserSwitcherViewMode is initialized and config has changed setupUserSwitcher(); reset(mSecurityViewFlipper); when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams); - mKeyguardSecurityContainer.onConfigurationChanged(config); + mKeyguardSecurityContainer.onConfigurationChanged(portraitConfig); // THEN views are both centered horizontally - verify(mSecurityViewFlipper).setLayoutParams(mLayoutCaptor.capture()); - assertThat(mLayoutCaptor.getValue().gravity).isEqualTo(Gravity.CENTER_HORIZONTAL); + assertSecurityGravity(Gravity.CENTER_HORIZONTAL); assertUserSwitcherGravity(Gravity.CENTER_HORIZONTAL); + assertSecurityTranslationX(0); + assertUserSwitcherTranslationX(0); } @Test @@ -315,14 +313,16 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { setupUserSwitcher(); setViewWidth(VIEW_WIDTH); + // security is on the right side by default assertThat(mKeyguardSecurityContainer.isTouchOnTheOtherSideOfSecurity( touchEventLeftSide())).isTrue(); assertThat(mKeyguardSecurityContainer.isTouchOnTheOtherSideOfSecurity( touchEventRightSide())).isFalse(); - mKeyguardSecurityContainer.handleDoubleTap(touchEventLeftSide()); - // settings should be updated, we need to keep the mock updated as well + // move security to the left side when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_LEFT); + mKeyguardSecurityContainer.onConfigurationChanged(new Configuration()); + assertThat(mKeyguardSecurityContainer.isTouchOnTheOtherSideOfSecurity( touchEventLeftSide())).isFalse(); assertThat(mKeyguardSecurityContainer.isTouchOnTheOtherSideOfSecurity( @@ -331,23 +331,33 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Test public void testSecuritySwitchesSidesInLandscapeUserSwitcherMode() { - Configuration config = new Configuration(); - config.orientation = Configuration.ORIENTATION_LANDSCAPE; - when(getContext().getResources().getConfiguration()).thenReturn(config); + when(getContext().getResources().getConfiguration()) + .thenReturn(configuration(ORIENTATION_LANDSCAPE)); setupUserSwitcher(); - // check default position - assertSecurityGravity(Gravity.RIGHT | Gravity.BOTTOM); - assertUserSwitcherGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); - reset(mSecurityViewFlipper); - when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams); - // change setting so configuration change triggers position change + // switch sides when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_LEFT); mKeyguardSecurityContainer.onConfigurationChanged(new Configuration()); - // check position after switching - assertSecurityGravity(Gravity.LEFT | Gravity.BOTTOM); - assertUserSwitcherGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); + assertSecurityTranslationX(0); + assertUserSwitcherTranslationX( + mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth()); + } + + private Configuration configuration(@Configuration.Orientation int orientation) { + Configuration config = new Configuration(); + config.orientation = orientation; + return config; + } + + private void assertSecurityTranslationX(float translation) { + verify(mSecurityViewFlipper).setTranslationX(translation); + } + + private void assertUserSwitcherTranslationX(float translation) { + ViewGroup userSwitcher = mKeyguardSecurityContainer.findViewById( + R.id.keyguard_bouncer_user_switcher); + assertThat(userSwitcher.getTranslationX()).isEqualTo(translation); } private void assertUserSwitcherGravity(@Gravity.GravityFlags int gravity) { @@ -391,6 +401,9 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT); mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER, mGlobalSettings, mFalsingManager, mUserSwitcherController); + // reset mSecurityViewFlipper so setup doesn't influence test verifications + reset(mSecurityViewFlipper); + when(mSecurityViewFlipper.getLayoutParams()).thenReturn(mSecurityViewFlipperLayoutParams); } private ArrayList<UserRecord> buildUserRecords(int count) { |