Loading packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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> packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml +2 −1 Original line number Diff line number Diff line Loading @@ -41,13 +41,14 @@ android:layout_gravity="center"> <com.android.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" android:layout_width="match_parent" android:layout_width="wrap_content" android:layout_height="match_parent" 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> Loading packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml 0 → 100644 +20 −0 Original line number Diff line number Diff line <?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> packages/SystemUI/res-keyguard/values/config.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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> packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +216 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -157,7 +169,9 @@ 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); /** Loading @@ -166,7 +180,9 @@ public class KeyguardSecurityContainer extends FrameLayout { * @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(); } Loading Loading @@ -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() { Loading @@ -238,6 +378,7 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog = null; } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); mOrientationEventListener.disable(); } @Override Loading Loading @@ -319,11 +460,36 @@ 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; } Loading Loading @@ -441,7 +607,6 @@ public class KeyguardSecurityContainer extends FrameLayout { return insets.inset(0, 0, 0, inset); } private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); Loading Loading @@ -490,6 +655,47 @@ 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()); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); // 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) { Loading Loading
packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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>
packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml +2 −1 Original line number Diff line number Diff line Loading @@ -41,13 +41,14 @@ android:layout_gravity="center"> <com.android.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" android:layout_width="match_parent" android:layout_width="wrap_content" android:layout_height="match_parent" 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> Loading
packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml 0 → 100644 +20 −0 Original line number Diff line number Diff line <?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>
packages/SystemUI/res-keyguard/values/config.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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>
packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +216 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -157,7 +169,9 @@ 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); /** Loading @@ -166,7 +180,9 @@ public class KeyguardSecurityContainer extends FrameLayout { * @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(); } Loading Loading @@ -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() { Loading @@ -238,6 +378,7 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog = null; } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); mOrientationEventListener.disable(); } @Override Loading Loading @@ -319,11 +460,36 @@ 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; } Loading Loading @@ -441,7 +607,6 @@ public class KeyguardSecurityContainer extends FrameLayout { return insets.inset(0, 0, 0, inset); } private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); Loading Loading @@ -490,6 +655,47 @@ 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()); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); // 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) { Loading