Loading packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +30 −69 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.view.WindowInsetsAnimation; import android.view.WindowManager; import android.widget.FrameLayout; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; Loading Loading @@ -104,7 +103,6 @@ public class KeyguardSecurityContainer extends FrameLayout { private boolean mIsSecurityViewLeftAligned = true; private boolean mOneHandedMode = false; private SecurityMode mSecurityMode = SecurityMode.Invalid; private ViewPropertyAnimator mRunningOneHandedAnimator; private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = Loading Loading @@ -248,66 +246,47 @@ public class KeyguardSecurityContainer extends FrameLayout { } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { mSecurityMode = securityMode; mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); updateLayoutForSecurityMode(securityMode); } void updateLayoutForSecurityMode(SecurityMode securityMode) { mSecurityMode = securityMode; mOneHandedMode = canUseOneHandedBouncer(); if (mOneHandedMode) { mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext); } /** * Sets whether this security container is in one handed mode. If so, it will measure its * child SecurityViewFlipper in one half of the screen, and move it when tapping on the opposite * side of the screen. */ public void setOneHandedMode(boolean oneHandedMode) { mOneHandedMode = oneHandedMode; updateSecurityViewGravity(); updateSecurityViewLocation(false); } /** Update keyguard position based on a tapped X coordinate. */ public void updateKeyguardPosition(float x) { if (mOneHandedMode) { moveBouncerForXCoordinate(x, /* animate= */false); } } /** Return whether the one-handed keyguard should be enabled. */ private boolean canUseOneHandedBouncer() { // Is it enabled? if (!getResources().getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) { return false; } if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) { return false; /** Returns whether this security container is in one-handed mode. */ public boolean isOneHandedMode() { return mOneHandedMode; } return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); /** * When in one-handed mode, sets if the inner SecurityViewFlipper should be aligned to the * left-hand side of the screen or not, and whether to animate when moving between the two. */ public void setOneHandedModeLeftAligned(boolean leftAligned, boolean animate) { mIsSecurityViewLeftAligned = leftAligned; updateSecurityViewLocation(animate); } /** Read whether the one-handed keyguard should be on the left/right from settings. */ private boolean isOneHandedKeyguardLeftAligned(Context context) { try { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.ONE_HANDED_KEYGUARD_SIDE) == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; } catch (Settings.SettingNotFoundException ex) { return true; } /** Returns whether the inner SecurityViewFlipper is left-aligned when in one-handed mode. */ public boolean isOneHandedModeLeftAligned() { return mIsSecurityViewLeftAligned; } private void updateSecurityViewGravity() { View securityView = findKeyguardSecurityView(); if (securityView == null) { if (mSecurityViewFlipper == null) { return; } FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams(); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSecurityViewFlipper.getLayoutParams(); if (mOneHandedMode) { lp.gravity = Gravity.LEFT | Gravity.BOTTOM; Loading @@ -315,7 +294,7 @@ public class KeyguardSecurityContainer extends FrameLayout { lp.gravity = Gravity.CENTER_HORIZONTAL; } securityView.setLayoutParams(lp); mSecurityViewFlipper.setLayoutParams(lp); } /** Loading @@ -324,14 +303,12 @@ public class KeyguardSecurityContainer extends FrameLayout { * by the security view . */ private void updateSecurityViewLocation(boolean animate) { View securityView = findKeyguardSecurityView(); if (securityView == null) { if (mSecurityViewFlipper == null) { return; } if (!mOneHandedMode) { securityView.setTranslationX(0); mSecurityViewFlipper.setTranslationX(0); return; } Loading @@ -343,7 +320,8 @@ public class KeyguardSecurityContainer extends FrameLayout { int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f); if (animate) { mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation); mRunningOneHandedAnimator = mSecurityViewFlipper.animate().translationX(targetTranslation); mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() { @Override Loading @@ -355,27 +333,10 @@ public class KeyguardSecurityContainer extends FrameLayout { mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); mRunningOneHandedAnimator.start(); } else { securityView.setTranslationX(targetTranslation); mSecurityViewFlipper.setTranslationX(targetTranslation); } } @Nullable private KeyguardSecurityViewFlipper findKeyguardSecurityView() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (isKeyguardSecurityView(child)) { return (KeyguardSecurityViewFlipper) child; } } return null; } private boolean isKeyguardSecurityView(View view) { return view instanceof KeyguardSecurityViewFlipper; } public void onPause() { if (mAlertDialog != null) { mAlertDialog.dismiss(); Loading Loading @@ -635,7 +596,7 @@ public class KeyguardSecurityContainer extends FrameLayout { for (int i = 0; i < getChildCount(); i++) { final View view = getChildAt(i); if (view.getVisibility() != GONE) { if (mOneHandedMode && isKeyguardSecurityView(view)) { if (mOneHandedMode && view == mSecurityViewFlipper) { measureChildWithMargins(view, halfWidthMeasureSpec, 0, heightMeasureSpec, 0); } else { Loading packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +66 −7 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.metrics.LogMaker; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.Slog; import android.view.MotionEvent; Loading @@ -49,6 +50,8 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; Loading @@ -74,12 +77,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final SecurityCallback mSecurityCallback; private final ConfigurationController mConfigurationController; private final FalsingCollector mFalsingCollector; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { @VisibleForTesting final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { private MotionEvent mTouchDown; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Loading @@ -91,6 +96,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard // Do just a bit of our own falsing. People should only be tapping on the input, not // swiping. if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { // If we're in one handed mode, the user can tap on the opposite side of the screen // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps // to move the bouncer to each screen side can end up closing it instead). if (mView.isOneHandedMode()) { if ((mView.isOneHandedModeLeftAligned() && ev.getX() > mView.getWidth() / 2f) || (!mView.isOneHandedModeLeftAligned() && ev.getX() <= mView.getWidth() / 2f)) { mFalsingCollector.avoidGesture(); } } if (mTouchDown != null) { mTouchDown.recycle(); mTouchDown = null; Loading Loading @@ -202,7 +218,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard KeyguardStateController keyguardStateController, SecurityCallback securityCallback, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController) { ConfigurationController configurationController, FalsingCollector falsingCollector) { super(view); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = keyguardUpdateMonitor; Loading @@ -216,6 +233,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardSecurityCallback); mConfigurationController = configurationController; mLastOrientation = getResources().getConfiguration().orientation; mFalsingCollector = falsingCollector; } @Override Loading Loading @@ -440,13 +458,49 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); mSecurityViewFlipperController.show(newView); mView.updateLayoutForSecurityMode(securityMode); configureOneHandedMode(); } mSecurityCallback.onSecurityModeChanged( securityMode, newView != null && newView.needsInput()); } /** Read whether the one-handed keyguard should be on the left/right from settings. */ private boolean isOneHandedKeyguardLeftAligned() { try { return Settings.Global.getInt(mView.getContext().getContentResolver(), Settings.Global.ONE_HANDED_KEYGUARD_SIDE) == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; } catch (Settings.SettingNotFoundException ex) { return true; } } private boolean canUseOneHandedBouncer() { // Is it enabled? if (!getResources().getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) { return false; } if (!KeyguardSecurityModel.isSecurityViewOneHanded(mCurrentSecurityMode)) { return false; } return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); } private void configureOneHandedMode() { boolean oneHandedMode = canUseOneHandedBouncer(); mView.setOneHandedMode(oneHandedMode); if (oneHandedMode) { mView.setOneHandedModeLeftAligned( isOneHandedKeyguardLeftAligned(), /* animate= */false); } } public void reportFailedUnlockAttempt(int userId, int timeoutMs) { // +1 for this time final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1; Loading Loading @@ -511,13 +565,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard int newOrientation = getResources().getConfiguration().orientation; if (newOrientation != mLastOrientation) { mLastOrientation = newOrientation; mView.updateLayoutForSecurityMode(mCurrentSecurityMode); configureOneHandedMode(); } } /** Update keyguard position based on a tapped X coordinate. */ public void updateKeyguardPosition(float x) { mView.updateKeyguardPosition(x); if (mView.isOneHandedMode()) { mView.setOneHandedModeLeftAligned(x <= mView.getWidth() / 2f, false); } } static class Factory { Loading @@ -533,6 +589,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardStateController mKeyguardStateController; private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final ConfigurationController mConfigurationController; private final FalsingCollector mFalsingCollector; @Inject Factory(KeyguardSecurityContainer view, Loading @@ -545,7 +602,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController) { ConfigurationController configurationController, FalsingCollector falsingCollector) { mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mLockPatternUtils = lockPatternUtils; Loading @@ -556,6 +614,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardStateController = keyguardStateController; mSecurityViewFlipperController = securityViewFlipperController; mConfigurationController = configurationController; mFalsingCollector = falsingCollector; } public KeyguardSecurityContainerController create( Loading @@ -564,7 +623,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, securityCallback, mSecurityViewFlipperController, mConfigurationController); mConfigurationController, mFalsingCollector); } } Loading packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +152 −5 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ package com.android.keyguard; import static android.view.WindowInsets.Type.ime; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; 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.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -33,6 +35,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; import android.view.WindowInsetsController; import androidx.test.filters.SmallTest; Loading @@ -43,6 +46,7 @@ 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.FalsingCollector; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; Loading @@ -58,6 +62,7 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private static final int VIEW_WIDTH = 1600; @Rule public MockitoRule mRule = MockitoJUnit.rule(); Loading Loading @@ -100,6 +105,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private EmergencyButtonController mEmergencyButtonController; @Mock private Resources mResources; @Mock private FalsingCollector mFalsingCollector; private Configuration mConfiguration; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; Loading @@ -112,7 +119,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED. when(mResources.getConfiguration()).thenReturn(mConfiguration); when(mView.getContext()).thenReturn(mContext); when(mView.getResources()).thenReturn(mResources); when(mView.getWidth()).thenReturn(VIEW_WIDTH); when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class))) .thenReturn(mAdminSecondaryLockScreenController); when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); Loading @@ -131,7 +140,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController) mConfigurationController, mFalsingCollector) .create(mSecurityCallback); } Loading Loading @@ -169,18 +178,156 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { public void onResourcesUpdate_callsThroughOnRotationChange() { // Rotation is the same, shouldn't cause an update mKeyguardSecurityContainerController.updateResources(); verify(mView, times(0)).updateLayoutForSecurityMode(any()); verify(mView, times(0)).setOneHandedMode(anyBoolean()); // Update rotation. Should trigger update mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; mKeyguardSecurityContainerController.updateResources(); verify(mView, times(1)).updateLayoutForSecurityMode(any()); verify(mView, times(1)).setOneHandedMode(anyBoolean()); } @Test public void updateKeyguardPosition_callsThroughToView() { public void updateKeyguardPosition_callsThroughToViewInOneHandedMode() { when(mView.isOneHandedMode()).thenReturn(true); mKeyguardSecurityContainerController.updateKeyguardPosition(VIEW_WIDTH / 3f); verify(mView).setOneHandedModeLeftAligned(true, false); mKeyguardSecurityContainerController.updateKeyguardPosition((VIEW_WIDTH / 3f) * 2); verify(mView).setOneHandedModeLeftAligned(false, false); } @Test public void updateKeyguardPosition_ignoredInTwoHandedMode() { when(mView.isOneHandedMode()).thenReturn(false); mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f); verify(mView).updateKeyguardPosition(1.0f); verify(mView, never()).setOneHandedModeLeftAligned(anyBoolean(), anyBoolean()); } private void touchDownLeftSide() { mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent( MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, /* x= */VIEW_WIDTH / 3f, /* y= */0, /* metaState= */0)); } private void touchDownRightSide() { mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent( MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, /* x= */(VIEW_WIDTH / 3f) * 2, /* y= */0, /* metaState= */0)); } @Test public void onInterceptTap_inhibitsFalsingInOneHandedMode() { when(mView.isOneHandedMode()).thenReturn(true); when(mView.isOneHandedModeLeftAligned()).thenReturn(true); touchDownLeftSide(); verify(mFalsingCollector, never()).avoidGesture(); // Now on the right. touchDownRightSide(); verify(mFalsingCollector).avoidGesture(); // Move and re-test reset(mFalsingCollector); when(mView.isOneHandedModeLeftAligned()).thenReturn(false); // On the right... touchDownRightSide(); verify(mFalsingCollector, never()).avoidGesture(); touchDownLeftSide(); verify(mFalsingCollector).avoidGesture(); } @Test public void showSecurityScreen_oneHandedMode_bothFlagsDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */false, /* sysuiResourceCanUseOneHandedKeyguard= */false); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_deviceFlagDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */false, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_sysUiFlagDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */false); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_bothFlagsEnabled_oneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(true); } @Test public void showSecurityScreen_twoHandedMode_bothFlagsEnabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); verify(mView).setOneHandedMode(false); } private void setUpKeyguardFlags( boolean deviceConfigCanUseOneHandedKeyguard, boolean sysuiResourceCanUseOneHandedKeyguard) { when(mResources.getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) .thenReturn(deviceConfigCanUseOneHandedKeyguard); when(mResources.getBoolean( R.bool.can_use_one_handed_bouncer)) .thenReturn(sysuiResourceCanUseOneHandedKeyguard); } } packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +21 −90 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +30 −69 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.view.WindowInsetsAnimation; import android.view.WindowManager; import android.widget.FrameLayout; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; Loading Loading @@ -104,7 +103,6 @@ public class KeyguardSecurityContainer extends FrameLayout { private boolean mIsSecurityViewLeftAligned = true; private boolean mOneHandedMode = false; private SecurityMode mSecurityMode = SecurityMode.Invalid; private ViewPropertyAnimator mRunningOneHandedAnimator; private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = Loading Loading @@ -248,66 +246,47 @@ public class KeyguardSecurityContainer extends FrameLayout { } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { mSecurityMode = securityMode; mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); updateLayoutForSecurityMode(securityMode); } void updateLayoutForSecurityMode(SecurityMode securityMode) { mSecurityMode = securityMode; mOneHandedMode = canUseOneHandedBouncer(); if (mOneHandedMode) { mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext); } /** * Sets whether this security container is in one handed mode. If so, it will measure its * child SecurityViewFlipper in one half of the screen, and move it when tapping on the opposite * side of the screen. */ public void setOneHandedMode(boolean oneHandedMode) { mOneHandedMode = oneHandedMode; updateSecurityViewGravity(); updateSecurityViewLocation(false); } /** Update keyguard position based on a tapped X coordinate. */ public void updateKeyguardPosition(float x) { if (mOneHandedMode) { moveBouncerForXCoordinate(x, /* animate= */false); } } /** Return whether the one-handed keyguard should be enabled. */ private boolean canUseOneHandedBouncer() { // Is it enabled? if (!getResources().getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) { return false; } if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) { return false; /** Returns whether this security container is in one-handed mode. */ public boolean isOneHandedMode() { return mOneHandedMode; } return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); /** * When in one-handed mode, sets if the inner SecurityViewFlipper should be aligned to the * left-hand side of the screen or not, and whether to animate when moving between the two. */ public void setOneHandedModeLeftAligned(boolean leftAligned, boolean animate) { mIsSecurityViewLeftAligned = leftAligned; updateSecurityViewLocation(animate); } /** Read whether the one-handed keyguard should be on the left/right from settings. */ private boolean isOneHandedKeyguardLeftAligned(Context context) { try { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.ONE_HANDED_KEYGUARD_SIDE) == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; } catch (Settings.SettingNotFoundException ex) { return true; } /** Returns whether the inner SecurityViewFlipper is left-aligned when in one-handed mode. */ public boolean isOneHandedModeLeftAligned() { return mIsSecurityViewLeftAligned; } private void updateSecurityViewGravity() { View securityView = findKeyguardSecurityView(); if (securityView == null) { if (mSecurityViewFlipper == null) { return; } FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams(); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSecurityViewFlipper.getLayoutParams(); if (mOneHandedMode) { lp.gravity = Gravity.LEFT | Gravity.BOTTOM; Loading @@ -315,7 +294,7 @@ public class KeyguardSecurityContainer extends FrameLayout { lp.gravity = Gravity.CENTER_HORIZONTAL; } securityView.setLayoutParams(lp); mSecurityViewFlipper.setLayoutParams(lp); } /** Loading @@ -324,14 +303,12 @@ public class KeyguardSecurityContainer extends FrameLayout { * by the security view . */ private void updateSecurityViewLocation(boolean animate) { View securityView = findKeyguardSecurityView(); if (securityView == null) { if (mSecurityViewFlipper == null) { return; } if (!mOneHandedMode) { securityView.setTranslationX(0); mSecurityViewFlipper.setTranslationX(0); return; } Loading @@ -343,7 +320,8 @@ public class KeyguardSecurityContainer extends FrameLayout { int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f); if (animate) { mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation); mRunningOneHandedAnimator = mSecurityViewFlipper.animate().translationX(targetTranslation); mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() { @Override Loading @@ -355,27 +333,10 @@ public class KeyguardSecurityContainer extends FrameLayout { mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); mRunningOneHandedAnimator.start(); } else { securityView.setTranslationX(targetTranslation); mSecurityViewFlipper.setTranslationX(targetTranslation); } } @Nullable private KeyguardSecurityViewFlipper findKeyguardSecurityView() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (isKeyguardSecurityView(child)) { return (KeyguardSecurityViewFlipper) child; } } return null; } private boolean isKeyguardSecurityView(View view) { return view instanceof KeyguardSecurityViewFlipper; } public void onPause() { if (mAlertDialog != null) { mAlertDialog.dismiss(); Loading Loading @@ -635,7 +596,7 @@ public class KeyguardSecurityContainer extends FrameLayout { for (int i = 0; i < getChildCount(); i++) { final View view = getChildAt(i); if (view.getVisibility() != GONE) { if (mOneHandedMode && isKeyguardSecurityView(view)) { if (mOneHandedMode && view == mSecurityViewFlipper) { measureChildWithMargins(view, halfWidthMeasureSpec, 0, heightMeasureSpec, 0); } else { Loading
packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +66 −7 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.metrics.LogMaker; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.Slog; import android.view.MotionEvent; Loading @@ -49,6 +50,8 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; Loading @@ -74,12 +77,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final SecurityCallback mSecurityCallback; private final ConfigurationController mConfigurationController; private final FalsingCollector mFalsingCollector; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { @VisibleForTesting final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { private MotionEvent mTouchDown; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Loading @@ -91,6 +96,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard // Do just a bit of our own falsing. People should only be tapping on the input, not // swiping. if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { // If we're in one handed mode, the user can tap on the opposite side of the screen // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps // to move the bouncer to each screen side can end up closing it instead). if (mView.isOneHandedMode()) { if ((mView.isOneHandedModeLeftAligned() && ev.getX() > mView.getWidth() / 2f) || (!mView.isOneHandedModeLeftAligned() && ev.getX() <= mView.getWidth() / 2f)) { mFalsingCollector.avoidGesture(); } } if (mTouchDown != null) { mTouchDown.recycle(); mTouchDown = null; Loading Loading @@ -202,7 +218,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard KeyguardStateController keyguardStateController, SecurityCallback securityCallback, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController) { ConfigurationController configurationController, FalsingCollector falsingCollector) { super(view); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = keyguardUpdateMonitor; Loading @@ -216,6 +233,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardSecurityCallback); mConfigurationController = configurationController; mLastOrientation = getResources().getConfiguration().orientation; mFalsingCollector = falsingCollector; } @Override Loading Loading @@ -440,13 +458,49 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); mSecurityViewFlipperController.show(newView); mView.updateLayoutForSecurityMode(securityMode); configureOneHandedMode(); } mSecurityCallback.onSecurityModeChanged( securityMode, newView != null && newView.needsInput()); } /** Read whether the one-handed keyguard should be on the left/right from settings. */ private boolean isOneHandedKeyguardLeftAligned() { try { return Settings.Global.getInt(mView.getContext().getContentResolver(), Settings.Global.ONE_HANDED_KEYGUARD_SIDE) == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; } catch (Settings.SettingNotFoundException ex) { return true; } } private boolean canUseOneHandedBouncer() { // Is it enabled? if (!getResources().getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) { return false; } if (!KeyguardSecurityModel.isSecurityViewOneHanded(mCurrentSecurityMode)) { return false; } return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); } private void configureOneHandedMode() { boolean oneHandedMode = canUseOneHandedBouncer(); mView.setOneHandedMode(oneHandedMode); if (oneHandedMode) { mView.setOneHandedModeLeftAligned( isOneHandedKeyguardLeftAligned(), /* animate= */false); } } public void reportFailedUnlockAttempt(int userId, int timeoutMs) { // +1 for this time final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1; Loading Loading @@ -511,13 +565,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard int newOrientation = getResources().getConfiguration().orientation; if (newOrientation != mLastOrientation) { mLastOrientation = newOrientation; mView.updateLayoutForSecurityMode(mCurrentSecurityMode); configureOneHandedMode(); } } /** Update keyguard position based on a tapped X coordinate. */ public void updateKeyguardPosition(float x) { mView.updateKeyguardPosition(x); if (mView.isOneHandedMode()) { mView.setOneHandedModeLeftAligned(x <= mView.getWidth() / 2f, false); } } static class Factory { Loading @@ -533,6 +589,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardStateController mKeyguardStateController; private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final ConfigurationController mConfigurationController; private final FalsingCollector mFalsingCollector; @Inject Factory(KeyguardSecurityContainer view, Loading @@ -545,7 +602,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, ConfigurationController configurationController) { ConfigurationController configurationController, FalsingCollector falsingCollector) { mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mLockPatternUtils = lockPatternUtils; Loading @@ -556,6 +614,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardStateController = keyguardStateController; mSecurityViewFlipperController = securityViewFlipperController; mConfigurationController = configurationController; mFalsingCollector = falsingCollector; } public KeyguardSecurityContainerController create( Loading @@ -564,7 +623,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, securityCallback, mSecurityViewFlipperController, mConfigurationController); mConfigurationController, mFalsingCollector); } } Loading
packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +152 −5 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ package com.android.keyguard; import static android.view.WindowInsets.Type.ime; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; 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.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -33,6 +35,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; import android.view.WindowInsetsController; import androidx.test.filters.SmallTest; Loading @@ -43,6 +46,7 @@ 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.FalsingCollector; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; Loading @@ -58,6 +62,7 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private static final int VIEW_WIDTH = 1600; @Rule public MockitoRule mRule = MockitoJUnit.rule(); Loading Loading @@ -100,6 +105,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private EmergencyButtonController mEmergencyButtonController; @Mock private Resources mResources; @Mock private FalsingCollector mFalsingCollector; private Configuration mConfiguration; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; Loading @@ -112,7 +119,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED. when(mResources.getConfiguration()).thenReturn(mConfiguration); when(mView.getContext()).thenReturn(mContext); when(mView.getResources()).thenReturn(mResources); when(mView.getWidth()).thenReturn(VIEW_WIDTH); when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class))) .thenReturn(mAdminSecondaryLockScreenController); when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); Loading @@ -131,7 +140,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController) mConfigurationController, mFalsingCollector) .create(mSecurityCallback); } Loading Loading @@ -169,18 +178,156 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { public void onResourcesUpdate_callsThroughOnRotationChange() { // Rotation is the same, shouldn't cause an update mKeyguardSecurityContainerController.updateResources(); verify(mView, times(0)).updateLayoutForSecurityMode(any()); verify(mView, times(0)).setOneHandedMode(anyBoolean()); // Update rotation. Should trigger update mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; mKeyguardSecurityContainerController.updateResources(); verify(mView, times(1)).updateLayoutForSecurityMode(any()); verify(mView, times(1)).setOneHandedMode(anyBoolean()); } @Test public void updateKeyguardPosition_callsThroughToView() { public void updateKeyguardPosition_callsThroughToViewInOneHandedMode() { when(mView.isOneHandedMode()).thenReturn(true); mKeyguardSecurityContainerController.updateKeyguardPosition(VIEW_WIDTH / 3f); verify(mView).setOneHandedModeLeftAligned(true, false); mKeyguardSecurityContainerController.updateKeyguardPosition((VIEW_WIDTH / 3f) * 2); verify(mView).setOneHandedModeLeftAligned(false, false); } @Test public void updateKeyguardPosition_ignoredInTwoHandedMode() { when(mView.isOneHandedMode()).thenReturn(false); mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f); verify(mView).updateKeyguardPosition(1.0f); verify(mView, never()).setOneHandedModeLeftAligned(anyBoolean(), anyBoolean()); } private void touchDownLeftSide() { mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent( MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, /* x= */VIEW_WIDTH / 3f, /* y= */0, /* metaState= */0)); } private void touchDownRightSide() { mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent( MotionEvent.obtain( /* downTime= */0, /* eventTime= */0, MotionEvent.ACTION_DOWN, /* x= */(VIEW_WIDTH / 3f) * 2, /* y= */0, /* metaState= */0)); } @Test public void onInterceptTap_inhibitsFalsingInOneHandedMode() { when(mView.isOneHandedMode()).thenReturn(true); when(mView.isOneHandedModeLeftAligned()).thenReturn(true); touchDownLeftSide(); verify(mFalsingCollector, never()).avoidGesture(); // Now on the right. touchDownRightSide(); verify(mFalsingCollector).avoidGesture(); // Move and re-test reset(mFalsingCollector); when(mView.isOneHandedModeLeftAligned()).thenReturn(false); // On the right... touchDownRightSide(); verify(mFalsingCollector, never()).avoidGesture(); touchDownLeftSide(); verify(mFalsingCollector).avoidGesture(); } @Test public void showSecurityScreen_oneHandedMode_bothFlagsDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */false, /* sysuiResourceCanUseOneHandedKeyguard= */false); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_deviceFlagDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */false, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_sysUiFlagDisabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */false); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(false); } @Test public void showSecurityScreen_oneHandedMode_bothFlagsEnabled_oneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).setOneHandedMode(true); } @Test public void showSecurityScreen_twoHandedMode_bothFlagsEnabled_noOneHandedMode() { setUpKeyguardFlags( /* deviceConfigCanUseOneHandedKeyguard= */true, /* sysuiResourceCanUseOneHandedKeyguard= */true); when(mKeyguardSecurityViewFlipperController.getSecurityView( eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); verify(mView).setOneHandedMode(false); } private void setUpKeyguardFlags( boolean deviceConfigCanUseOneHandedKeyguard, boolean sysuiResourceCanUseOneHandedKeyguard) { when(mResources.getBoolean( com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) .thenReturn(deviceConfigCanUseOneHandedKeyguard); when(mResources.getBoolean( R.bool.can_use_one_handed_bouncer)) .thenReturn(sysuiResourceCanUseOneHandedKeyguard); } }
packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +21 −90 File changed.Preview size limit exceeded, changes collapsed. Show changes