diff options
12 files changed, 374 insertions, 14 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e979e13d89c5..6ee7eb25eb2f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14614,6 +14614,29 @@ public final class Settings { public static final String POWER_BUTTON_VERY_LONG_PRESS = "power_button_very_long_press"; + + /** + * Keyguard should be on the left hand side of the screen, for wide screen layouts. + * + * @hide + */ + public static final int ONE_HANDED_KEYGUARD_SIDE_LEFT = 0; + + /** + * Keyguard should be on the right hand side of the screen, for wide screen layouts. + * + * @hide + */ + public static final int ONE_HANDED_KEYGUARD_SIDE_RIGHT = 1; + /** + * In one handed mode, which side the keyguard should be on. Allowable values are one of + * the ONE_HANDED_KEYGUARD_SIDE_* constants. + * + * @hide + */ + @Readable + public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b5af5240b843..e73d6e3af3cb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4203,4 +4203,6 @@ <java-symbol type="bool" name="config_telephony5gNonStandalone" /> <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" /> + + <java-symbol type="bool" name="config_enableOneHandedKeyguard" /> </resources> diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 66165b6d1ff2..ad6a5312f156 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -147,5 +147,10 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR); + VALIDATORS.put( + Global.ONE_HANDED_KEYGUARD_SIDE, + new InclusiveIntegerRangeValidator( + /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT, + /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT)); } } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 6719f179ef86..d715832dfca0 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -283,6 +283,7 @@ public class SettingsBackupTest { Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS, Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS, Settings.Global.FANCY_IME_ANIMATIONS, + Settings.Global.ONE_HANDED_KEYGUARD_SIDE, Settings.Global.FORCE_ALLOW_ON_EXTERNAL, Settings.Global.FORCED_APP_STANDBY_ENABLED, Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml index 79868093fb12..71cdaf5c7091 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml @@ -24,7 +24,7 @@ <include style="@style/BouncerSecurityContainer" layout="@layout/keyguard_host_view" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" /> </FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml index 04e645bd0a32..c75ee51517d1 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml @@ -41,13 +41,14 @@ android:layout_gravity="center"> <com.android.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:clipChildren="false" android:clipToPadding="false" android:paddingTop="@dimen/keyguard_security_view_top_margin" android:paddingStart="@dimen/keyguard_security_view_lateral_margin" android:paddingEnd="@dimen/keyguard_security_view_lateral_margin" + android:layout_gravity="center" android:gravity="center"> </com.android.keyguard.KeyguardSecurityViewFlipper> </com.android.keyguard.KeyguardSecurityContainer> diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml new file mode 100644 index 000000000000..e09bf7e37ed0 --- /dev/null +++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <bool name="can_use_one_handed_bouncer">true</bool> +</resources> diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml index 8d9d6ee68c67..6176f7c1dd0a 100644 --- a/packages/SystemUI/res-keyguard/values/config.xml +++ b/packages/SystemUI/res-keyguard/values/config.xml @@ -22,4 +22,5 @@ <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] --> <bool name="config_disableMenuKeyInLockScreen">false</bool> + <bool name="can_use_one_handed_bouncer">false</bool> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 5f6fd30ffa1b..f511ed1c69c4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -29,12 +29,17 @@ import android.app.AlertDialog; import android.content.Context; import android.graphics.Insets; import android.graphics.Rect; +import android.provider.Settings; import android.util.AttributeSet; import android.util.MathUtils; import android.util.TypedValue; +import android.view.Gravity; import android.view.MotionEvent; +import android.view.OrientationEventListener; import android.view.VelocityTracker; +import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewPropertyAnimator; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimationControlListener; @@ -55,6 +60,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import java.util.List; @@ -99,6 +105,12 @@ public class KeyguardSecurityContainer extends FrameLayout { private boolean mDisappearAnimRunning; private SwipeListener mSwipeListener; + private boolean mIsSecurityViewLeftAligned = true; + private boolean mOneHandedMode = false; + private SecurityMode mSecurityMode = SecurityMode.Invalid; + private ViewPropertyAnimator mRunningOneHandedAnimator; + private final OrientationEventListener mOrientationEventListener; + private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -157,16 +169,20 @@ public class KeyguardSecurityContainer extends FrameLayout { // Used to notify the container when something interesting happens. public interface SecurityCallback { boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen); + void userActivity(); + void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); /** - * @param strongAuth wheher the user has authenticated with strong authentication like - * pattern, password or PIN but not by trust agents or fingerprint + * @param strongAuth wheher the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint * @param targetUserId a user that needs to be the foreground user at the finish completion. */ void finish(boolean strongAuth, int targetUserId); + void reset(); + void onCancelClicked(); } @@ -224,12 +240,136 @@ public class KeyguardSecurityContainer extends FrameLayout { super(context, attrs, defStyle); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mViewConfiguration = ViewConfiguration.get(context); + + mOrientationEventListener = new OrientationEventListener(context) { + @Override + public void onOrientationChanged(int orientation) { + updateLayoutForSecurityMode(mSecurityMode); + } + }; } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { + mSecurityMode = securityMode; mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); + updateLayoutForSecurityMode(securityMode); + mOrientationEventListener.enable(); + } + + void updateLayoutForSecurityMode(SecurityMode securityMode) { + mSecurityMode = securityMode; + mOneHandedMode = canUseOneHandedBouncer(); + + if (mOneHandedMode) { + mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext); + } + + updateSecurityViewGravity(); + updateSecurityViewLocation(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_enableOneHandedKeyguard)) { + return false; + } + + if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) { + return false; + } + + return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); + } + + /** 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; + } + } + + private void updateSecurityViewGravity() { + View securityView = findKeyguardSecurityView(); + + if (securityView == null) { + return; + } + + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams(); + + if (mOneHandedMode) { + lp.gravity = Gravity.LEFT | Gravity.BOTTOM; + } else { + lp.gravity = Gravity.CENTER_HORIZONTAL; + } + + securityView.setLayoutParams(lp); + } + + /** + * Moves the inner security view to the correct location (in one handed mode) with animation. + * This is triggered when the user taps on the side of the screen that is not currently occupied + * by the security view . + */ + private void updateSecurityViewLocation(boolean animate) { + View securityView = findKeyguardSecurityView(); + + if (securityView == null) { + return; + } + + if (!mOneHandedMode) { + securityView.setTranslationX(0); + return; + } + + if (mRunningOneHandedAnimator != null) { + mRunningOneHandedAnimator.cancel(); + mRunningOneHandedAnimator = null; + } + + int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f); + + if (animate) { + mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation); + mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mRunningOneHandedAnimator = null; + } + }); + + mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + mRunningOneHandedAnimator.start(); + } else { + securityView.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() { @@ -238,6 +378,7 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog = null; } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); + mOrientationEventListener.disable(); } @Override @@ -319,19 +460,44 @@ public class KeyguardSecurityContainer extends FrameLayout { if (mSwipeListener != null) { mSwipeListener.onSwipeUp(); } + } else { + if (!mIsDragging) { + handleTap(event); + } } } return true; } + private void handleTap(MotionEvent event) { + // If we're using a fullscreen security mode, skip + if (!mOneHandedMode) { + return; + } + + // Did the tap hit the "other" side of the bouncer? + if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f)) + || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) { + mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned; + + Settings.Global.putInt( + mContext.getContentResolver(), + Settings.Global.ONE_HANDED_KEYGUARD_SIDE, + mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT + : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); + + updateSecurityViewLocation(true); + } + } + void setSwipeListener(SwipeListener swipeListener) { mSwipeListener = swipeListener; } private void startSpringAnimation(float startVelocity) { mSpringAnimation - .setStartVelocity(startVelocity) - .animateToFinalPosition(0); + .setStartVelocity(startVelocity) + .animateToFinalPosition(0); } public void startDisappearAnimation(SecurityMode securitySelection) { @@ -441,18 +607,17 @@ public class KeyguardSecurityContainer extends FrameLayout { return insets.inset(0, 0, 0, inset); } - private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); } mAlertDialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setCancelable(false) - .setNeutralButton(R.string.ok, null) - .create(); + .setTitle(title) + .setMessage(message) + .setCancelable(false) + .setNeutralButton(R.string.ok, null) + .create(); if (!(mContext instanceof Activity)) { mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); } @@ -490,6 +655,44 @@ public class KeyguardSecurityContainer extends FrameLayout { } } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int maxHeight = 0; + int maxWidth = 0; + int childState = 0; + + int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + MeasureSpec.getSize(widthMeasureSpec) / 2, + MeasureSpec.getMode(widthMeasureSpec)); + + for (int i = 0; i < getChildCount(); i++) { + final View view = getChildAt(i); + if (view.getVisibility() != GONE) { + if (mOneHandedMode && isKeyguardSecurityView(view)) { + measureChildWithMargins(view, halfWidthMeasureSpec, 0, + heightMeasureSpec, 0); + } else { + measureChildWithMargins(view, widthMeasureSpec, 0, + heightMeasureSpec, 0); + } + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + maxWidth = Math.max(maxWidth, + view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); + maxHeight = Math.max(maxHeight, + view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); + childState = combineMeasuredStates(childState, view.getMeasuredState()); + } + } + + // Check against our minimum height and width + maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); + maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); + + setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), + resolveSizeAndState(maxHeight, heightMeasureSpec, + childState << MEASURED_HEIGHT_STATE_SHIFT)); + } + void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { String message = null; switch (userType) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 1a8d420fb394..fdab8db67431 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -404,6 +404,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); mSecurityViewFlipperController.show(newView); + mView.updateLayoutForSecurityMode(securityMode); } mSecurityCallback.onSecurityModeChanged( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index c77c86711abf..631c24844417 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -92,4 +92,13 @@ public class KeyguardSecurityModel { throw new IllegalStateException("Unknown security quality:" + security); } } + + /** + * Returns whether the given security view should be used in a "one handed" way. This can be + * used to change how the security view is drawn (e.g. take up less of the screen, and align to + * one side). + */ + public static boolean isSecurityViewOneHanded(SecurityMode securityMode) { + return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN; + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 854be1f76722..14b4d0262f60 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -26,11 +26,16 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.testing.TestableResources; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowInsetsController; +import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import org.junit.Before; @@ -45,12 +50,21 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerTest extends SysuiTestCase { + private static final int SCREEN_WIDTH = 1600; + private static final int FAKE_MEASURE_SPEC = + View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY); + + private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN; + private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password; + + @Rule public MockitoRule mRule = MockitoJUnit.rule(); @Mock private WindowInsetsController mWindowInsetsController; + @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; @@ -58,9 +72,18 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Before public void setup() { + // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache + // the real references (rather than the TestableResources that this call creates). + mContext.ensureTestableResources(); + FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); + when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams); mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; + mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } @Test @@ -69,4 +92,75 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(), any(), any()); } -}
\ No newline at end of file + + @Test + public void onMeasure_usesFullWidthWithoutOneHandedMode() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthWithDeviceFlagDisabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthWithSysUIFlagDisabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesHalfWidthWithFlagsEnabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + ONE_HANDED_SECURITY_MODE); + + int halfWidthMeasureSpec = + View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY); + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + + verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthForFullScreenIme() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + TWO_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + private void setUpKeyguard( + boolean deviceConfigCanUseOneHandedKeyguard, + boolean sysuiResourceCanUseOneHandedKeyguard, + SecurityMode securityMode) { + TestableResources testableResources = mContext.getOrCreateTestableResources(); + testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard, + deviceConfigCanUseOneHandedKeyguard); + testableResources.addOverride(R.bool.can_use_one_handed_bouncer, + sysuiResourceCanUseOneHandedKeyguard); + mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode); + } +} |