Landscape PIN bouncer: layouts + code for landscape Pin bouncer

Enable Sysui flag "lockscreen.enable_landscape", b/293252410, for this feature. Previously the Pin bouncer only had a portrait layout, now there is a layout for landscape pin bouncer - this layout will only be visible when in landscape orientation and minimum screen width < 600 dp.

NumPadAnimator assumed that height and width were the same, changed to maintain width after animation.

Bug: 293427037
Test: PinBouncerLandscapeLayout, PinBouncerPortraitLayout
Change-Id: I3fd6010605d6b5fc5800d5463cd3da5f54ecd88a
This commit is contained in:
axfordjc
2023-07-17 09:05:14 +00:00
committed by Jonathon Axford
parent e11fb91ddb
commit 0c052a8075
14 changed files with 365 additions and 17 deletions

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!--
**
** Copyright 2023, 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.
*/
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/keyguard_pin_view_landscape" />
</FrameLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!--
**
** Copyright 2023, 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.
*/
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/keyguard_pin_view_portrait" />
</FrameLayout>

View File

@@ -0,0 +1,231 @@
<?xml version="1.0" encoding="utf-8"?><!--
**
** Copyright 2023, 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.
*/
-->
<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/keyguard_pin_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|bottom"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:clipChildren="false"
android:clipToPadding="false"
android:layoutDirection="ltr"
android:orientation="vertical">
<include layout="@layout/keyguard_bouncer_message_area" />
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
androidprv:layout_constraintBottom_toTopOf="@+id/row0"
androidprv:layout_constraintTop_toTopOf="parent"
androidprv:layout_constraintVertical_chainStyle="packed" />
<!-- Set this to be just above key1. It would be better to introduce a barrier above
key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
case, the Flow should ensure that key1/2/3 all have the same top, so this should be
fine. -->
<com.android.keyguard.AlphaOptimizedRelativeLayout
android:id="@+id/row0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"
androidprv:layout_constraintTop_toBottomOf="@+id/bouncer_message_view"
tools:layout_editor_absoluteX="-16dp">
<com.android.keyguard.PasswordTextView
android:id="@+id/pinEntry"
style="@style/Widget.TextView.Password"
android:layout_width="@dimen/keyguard_security_width"
android:layout_height="@dimen/keyguard_password_height"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
android:contentDescription="@string/keyguard_accessibility_pin_area"
androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</com.android.keyguard.AlphaOptimizedRelativeLayout>
<include
android:id="@+id/keyguard_selector_fade_container"
layout="@layout/keyguard_eca"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
android:layout_marginTop="@dimen/keyguard_eca_top_margin"
android:gravity="center_horizontal"
android:orientation="vertical"
androidprv:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pin_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:clipChildren="false"
android:clipToPadding="false"
android:layoutDirection="ltr"
android:orientation="vertical">
<!-- Guideline used to place the top row of keys relative to the screen height. This will be
updated in KeyguardPINView to reduce the height of the PIN pad. -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/pin_pad_top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
androidprv:layout_constraintGuide_percent="0" />
<com.android.keyguard.KeyguardPinFlowView
android:id="@+id/flow1"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
androidprv:flow_horizontalStyle="packed"
androidprv:flow_maxElementsWrap="3"
androidprv:flow_verticalBias="0.5"
androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
androidprv:flow_verticalStyle="packed"
androidprv:flow_wrapMode="aligned"
androidprv:layout_constraintBottom_toBottomOf="parent"
androidprv:layout_constraintEnd_toEndOf="parent"
androidprv:layout_constraintStart_toStartOf="parent"
androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
<com.android.keyguard.NumPadButton
android:id="@+id/delete_button"
style="@style/NumPadKey.Delete"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key0"
android:contentDescription="@string/keyboardview_keycode_delete" />
<com.android.keyguard.NumPadButton
android:id="@+id/key_enter"
style="@style/NumPadKey.Enter"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/keyboardview_keycode_enter" />
<com.android.keyguard.NumPadKey
android:id="@+id/key1"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key2"
androidprv:digit="1"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key2"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key3"
androidprv:digit="2"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key3"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key4"
androidprv:digit="3"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key4"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key5"
androidprv:digit="4"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key5"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key6"
androidprv:digit="5"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key6"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key7"
androidprv:digit="6"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key7"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key8"
androidprv:digit="7"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key8"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key9"
androidprv:digit="8"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key9"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/delete_button"
androidprv:digit="9"
androidprv:textView="@+id/pinEntry" />
<com.android.keyguard.NumPadKey
android:id="@+id/key0"
android:layout_width="0dp"
android:layout_height="0dp"
android:accessibilityTraversalBefore="@id/key_enter"
androidprv:digit="0"
androidprv:textView="@+id/pinEntry" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.android.keyguard.KeyguardPINView>

View File

@@ -32,7 +32,6 @@ import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.media.AudioManager;
@@ -142,7 +141,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private Runnable mCancelAction;
private boolean mWillRunDismissFromKeyguard;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
private int mLastOrientation;
private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
@@ -348,7 +347,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
@Override
public void onDensityOrFontScaleChanged() {
KeyguardSecurityContainerController.this.onDensityOrFontScaleChanged();
KeyguardSecurityContainerController.this
.onDensityOrFontScaleOrOrientationChanged();
}
@Override
public void onOrientationChanged(int orientation) {
KeyguardSecurityContainerController.this
.onDensityOrFontScaleOrOrientationChanged();
}
};
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
@@ -1142,7 +1148,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
/** Handles density or font scale changes. */
private void onDensityOrFontScaleChanged() {
private void onDensityOrFontScaleOrOrientationChanged() {
reinflateViewFlipper(controller -> mView.onDensityOrFontScaleChanged());
}

View File

@@ -58,6 +58,7 @@ class NumPadAnimator {
private float mStartRadius;
private float mEndRadius;
private int mHeight;
private int mWidth;
private static final int EXPAND_ANIMATION_MS = 100;
private static final int EXPAND_COLOR_ANIMATION_MS = 50;
@@ -95,11 +96,17 @@ class NumPadAnimator {
mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
int height = (int) (mHeight * 0.7f + mHeight * 0.3 * progress);
int difference = mHeight - height;
mBackground.setBounds(0, difference / 2, mHeight, mHeight - difference / 2);
int left = 0;
int top = difference / 2;
int right = mWidth;
int bottom = mHeight - difference / 2;
mBackground.setBounds(left, top, right, bottom);
}
void onLayout(int height) {
void onLayout(int width, int height) {
boolean shouldUpdateHeight = height != mHeight;
mWidth = width;
mHeight = height;
mStartRadius = height / 2f;
mEndRadius = height / 4f;
@@ -121,7 +128,7 @@ class NumPadAnimator {
ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle);
@SuppressLint("ResourceType") TypedArray a = ctw.obtainStyledAttributes(customAttrs);
mNormalBackgroundColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0,
NUM_PAD_BACKGROUND);
NUM_PAD_BACKGROUND);
a.recycle();
mPressedBackgroundColor = getColorAttrDefaultColor(context, NUM_PAD_BACKGROUND_PRESSED);

View File

@@ -74,8 +74,9 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (mAnimator != null) mAnimator.onLayout(b - t);
int width = r - l;
int height = b - t;
if (mAnimator != null) mAnimator.onLayout(width, height);
}
@Override

View File

@@ -211,7 +211,9 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
left = centerX - mKlondikeText.getMeasuredWidth() / 2;
mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
if (mAnimator != null) mAnimator.onLayout(b - t);
int width = r - l;
int height = b - t;
if (mAnimator != null) mAnimator.onLayout(width, height);
}
@Override

View File

@@ -548,6 +548,12 @@ object Flags {
val ENABLE_PIP_APP_ICON_OVERLAY =
sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
// TODO(b/293252410) : Tracking Bug
@JvmField
val LOCKSCREEN_ENABLE_LANDSCAPE =
unreleasedFlag(1116, name = "lockscreen.enable_landscape")
// TODO(b/273443374): Tracking Bug
@Keep
@JvmField val LOCKSCREEN_LIVE_WALLPAPER =

View File

@@ -22,8 +22,6 @@ import android.os.LocaleList
import android.view.View.LAYOUT_DIRECTION_RTL
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.policy.ConfigurationController
import java.util.ArrayList
import javax.inject.Inject
@SysUISingleton
@@ -40,6 +38,7 @@ class ConfigurationControllerImpl @Inject constructor(context: Context) : Config
private var localeList: LocaleList? = null
private val context: Context
private var layoutDirection: Int
private var orientation = Configuration.ORIENTATION_UNDEFINED
init {
val currentConfig = context.resources.configuration
@@ -134,8 +133,18 @@ class ConfigurationControllerImpl @Inject constructor(context: Context) : Config
it.onThemeChanged()
}
}
val newOrientation = newConfig.orientation
if (orientation != newOrientation) {
orientation = newOrientation
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onOrientationChanged(orientation)
}
}
}
override fun addCallback(listener: ConfigurationController.ConfigurationListener) {
listeners.add(listener)
listener.onDensityOrFontScaleChanged()

View File

@@ -42,5 +42,6 @@ public interface ConfigurationController extends CallbackController<Configuratio
default void onThemeChanged() {}
default void onLocaleListChanged() {}
default void onLayoutDirectionChanged(boolean isLayoutRtl) {}
default void onOrientationChanged(int orientation) {}
}
}

View File

@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.policy;
import static android.hardware.biometrics.BiometricSourceType.FACE;
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -38,6 +40,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import dagger.Lazy;
@@ -49,6 +52,7 @@ import java.util.Objects;
import javax.inject.Inject;
/**
*
*/
@SysUISingleton
public class KeyguardStateControllerImpl implements KeyguardStateController, Dumpable {
@@ -103,7 +107,10 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
*/
private boolean mSnappingKeyguardBackAfterSwipe = false;
private FeatureFlags mFeatureFlags;
/**
*
*/
@Inject
public KeyguardStateControllerImpl(
@@ -112,13 +119,15 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
LockPatternUtils lockPatternUtils,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
KeyguardUpdateMonitorLogger logger,
DumpManager dumpManager) {
DumpManager dumpManager,
FeatureFlags featureFlags) {
mContext = context;
mLogger = logger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mUnlockAnimationControllerLazy = keyguardUnlockAnimationController;
mFeatureFlags = featureFlags;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -272,7 +281,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
@Override
public boolean isKeyguardScreenRotationAllowed() {
return SystemProperties.getBoolean("lockscreen.rot_override", false)
|| mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation);
|| mContext.getResources().getBoolean(R.bool.config_enableLockScreenRotation)
|| mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE);
}
@Override

View File

@@ -47,10 +47,10 @@ class NumPadAnimatorTest : SysuiTestCase() {
@Test
fun testOnLayout() {
underTest.onLayout(100)
underTest.onLayout(100, 100)
verify(background).cornerRadius = 50f
reset(background)
underTest.onLayout(100)
underTest.onLayout(100, 100)
verify(background, never()).cornerRadius = anyFloat()
}
}

View File

@@ -273,6 +273,23 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
assertThat(listener.themeChanged).isTrue()
}
@Test
fun orientationUpdated_listenerNotified() {
val config = mContext.resources.configuration
config.orientation = Configuration.ORIENTATION_LANDSCAPE
mConfigurationController.onConfigurationChanged(config)
val listener = createAndAddListener()
// WHEN the orientation is updated
config.orientation = Configuration.ORIENTATION_PORTRAIT
mConfigurationController.onConfigurationChanged(config)
// THEN the listener is notified
assertThat(listener.orientationChanged).isTrue()
}
@Test
fun multipleUpdates_listenerNotifiedOfAll() {
val config = mContext.resources.configuration
@@ -325,6 +342,7 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
var themeChanged = false
var localeListChanged = false
var layoutDirectionChanged = false
var orientationChanged = false
override fun onConfigChanged(newConfig: Configuration?) {
changedConfig = newConfig
@@ -350,6 +368,9 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
override fun onLayoutDirectionChanged(isLayoutRtl: Boolean) {
layoutDirectionChanged = true
}
override fun onOrientationChanged(orientation: Int) {
orientationChanged = true
}
fun assertNoMethodsCalled() {
assertThat(densityOrFontScaleChanged).isFalse()

View File

@@ -36,6 +36,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import dagger.Lazy;
@@ -67,6 +68,8 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
@Mock
private KeyguardUpdateMonitorLogger mLogger;
@Mock
private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateCallbackCaptor;
@@ -80,7 +83,8 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
mLockPatternUtils,
mKeyguardUnlockAnimationControllerLazy,
mLogger,
mDumpManager);
mDumpManager,
mFeatureFlags);
}
@Test