Merge "Ring & notif vol missing on a largescreen device" into tm-qpr-dev
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index b4915b9..3eb307e 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -533,6 +533,86 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_fp_captured_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="54"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_fp_error_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="55"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_bg_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="56"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_fill_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="57"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_error_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="58"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <color name="message_bubble_incoming">#52534D</color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -597,6 +677,86 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_fp_captured_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="205"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_fp_error_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="206"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_bg_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="207"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_fill_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="208"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="sfps_enrollment_progress_bar_error_color">#ffffffff</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="209"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <color name="message_icon_background_outgoing">#FBBC04</color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -4837,6 +4997,38 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="android:colorPrimary">@color/material_grey_100</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes_suw.xml"
+ line="233"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="android:titleTextColor">@color/material_blue_700</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes_suw.xml"
+ line="235"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" android:background="@color/gestures_setting_background_color""
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -4845,4 +5037,36 @@
column="5"/>
</issue>
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" android:progressBackgroundTint="@color/sfps_enrollment_progress_bar_bg_color""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/layout/sfps_enroll_enrolling.xml"
+ line="71"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" android:progressBackgroundTint="@color/sfps_enrollment_progress_bar_bg_color""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/layout/sfps_enroll_enrolling.xml"
+ line="71"
+ column="20"/>
+ </issue>
+
</issues>
diff --git a/res/layout-land/choose_lock_pattern_common.xml b/res/layout-land/choose_lock_pattern_common.xml
new file mode 100644
index 0000000..1673413
--- /dev/null
+++ b/res/layout-land/choose_lock_pattern_common.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<!-- Used in phone portrait and tablet, as referenced in alias.xml. -->
+<com.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_lock">
+
+ <!-- takes up all space above button bar at bottom -->
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <TextView
+ android:id="@+id/headerText"
+ style="@style/SudDescription.Glif"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minLines="2"
+ android:gravity="center"
+ android:paddingStart="?attr/sudMarginStart"
+ android:paddingEnd="?attr/sudMarginEnd"
+ android:fontFamily="@*android:string/config_headlineFontFamily" />
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"/>
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView android:id="@+id/footerText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:minHeight="24dp"
+ android:textSize="14sp"
+ android:visibility="gone"/>
+
+ <Button
+ android:id="@+id/screen_lock_options"
+ style="@style/SudGlifButton.Tertiary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/setup_lock_settings_options_button_label"
+ android:visibility="gone"/>
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_base.xml b/res/layout-land/confirm_lock_pattern_base.xml
new file mode 100644
index 0000000..4ae5de3
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_base.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_enterprise">
+
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="24dp">
+
+ <Button
+ android:id="@+id/cancelButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_marginBottom="80dp"
+ android:text="@string/cancel" />
+
+ <Button
+ android:id="@+id/forgotButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:accessibilityLiveRegion="polite"
+ android:id="@+id/errorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:paddingStart="?attr/sudMarginStart"
+ android:paddingEnd="?attr/sudMarginEnd"
+ android:layout_marginTop="12dp"
+ android:gravity="center_vertical"/>
+
+ </LinearLayout>
+
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_normal_base.xml b/res/layout-land/confirm_lock_pattern_normal_base.xml
new file mode 100644
index 0000000..1e26912
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_normal_base.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.google.android.setupdesign.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_lock">
+
+ <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+ android:id="@+id/topLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ style="@style/SudContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+
+ <com.google.android.setupdesign.view.FillContentLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ </com.google.android.setupdesign.view.FillContentLayout>
+
+ <TextView
+ style="@style/TextAppearance.ErrorText"
+ android:accessibilityLiveRegion="polite"
+ android:id="@+id/errorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:gravity="center_vertical"/>
+
+ <Button
+ android:id="@+id/cancelButton"
+ style="@style/SudGlifButton.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="?attr/sudMarginStart"
+ android:layout_marginEnd="?attr/sudMarginEnd"
+ android:layout_marginBottom="80dp"
+ android:text="@string/cancel" />
+
+ </LinearLayout>
+
+ </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/choose_lock_pattern_common.xml b/res/layout/choose_lock_pattern_common.xml
index 2dd8cd5..b63b2c6 100644
--- a/res/layout/choose_lock_pattern_common.xml
+++ b/res/layout/choose_lock_pattern_common.xml
@@ -51,13 +51,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center"/>
</com.google.android.setupdesign.view.FillContentLayout>
@@ -66,7 +65,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:minHeight="50dip"
+ android:minHeight="24dp"
android:textSize="14sp"
android:visibility="gone"/>
diff --git a/res/layout/confirm_lock_pattern_base.xml b/res/layout/confirm_lock_pattern_base.xml
index 15c6121..5b19105 100644
--- a/res/layout/confirm_lock_pattern_base.xml
+++ b/res/layout/confirm_lock_pattern_base.xml
@@ -67,13 +67,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center" />
</com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/layout/confirm_lock_pattern_normal_base.xml b/res/layout/confirm_lock_pattern_normal_base.xml
index 7fd6172..5d1ca7c 100644
--- a/res/layout/confirm_lock_pattern_normal_base.xml
+++ b/res/layout/confirm_lock_pattern_normal_base.xml
@@ -39,13 +39,12 @@
style="@style/LockPatternContainerStyle"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:minHeight="@dimen/choose_lockscreen_min_height"
android:layout_weight="1">
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/biometric_auth_pattern_view_size"
+ android:layout_height="@dimen/biometric_auth_pattern_view_size"
android:layout_gravity="center" />
</com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/raw/face_posture_guidance_lottie.json b/res/raw/face_posture_guidance_lottie.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/res/raw/face_posture_guidance_lottie.json
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 5248da6..3942430 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -28,4 +28,8 @@
<!-- Display, Screen zoom -->
<dimen name="screen_zoom_preview_height">160dp</dimen>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
</resources>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
new file mode 100644
index 0000000..e6fb332
--- /dev/null
+++ b/res/values-land/styles.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2022 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>
+ <style name="LockPatternContainerStyle">
+ <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:paddingHorizontal">0dp</item>
+ <item name="android:paddingTop">0dp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-sw360dp/dimens.xml b/res/values-sw360dp/dimens.xml
index 23a1176..07a7bb7 100755
--- a/res/values-sw360dp/dimens.xml
+++ b/res/values-sw360dp/dimens.xml
@@ -25,4 +25,7 @@
<!-- Suggestion cards-->
<dimen name="suggestion_card_padding_bottom_one_card">22dp</dimen>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
+
</resources>
diff --git a/res/values-sw392dp-land/dimens.xml b/res/values-sw392dp-land/dimens.xml
new file mode 100755
index 0000000..920a0ec
--- /dev/null
+++ b/res/values-sw392dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">248dp</dimen>
+
+</resources>
diff --git a/res/values-sw392dp/dimens.xml b/res/values-sw392dp/dimens.xml
new file mode 100755
index 0000000..f90d4ee
--- /dev/null
+++ b/res/values-sw392dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp-land/dimens.xml b/res/values-sw410dp-land/dimens.xml
new file mode 100755
index 0000000..644486d
--- /dev/null
+++ b/res/values-sw410dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp/dimens.xml b/res/values-sw410dp/dimens.xml
new file mode 100755
index 0000000..5120e4a
--- /dev/null
+++ b/res/values-sw410dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 015a6af..2016650 100755
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -25,4 +25,8 @@
<!-- Padding for screen pinning -->
<dimen name="screen_pinning_padding_start">128dp</dimen>
<dimen name="screen_pinning_padding_end">128dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
+
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 2e821e0..02ff494 100755
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -55,4 +55,7 @@
<dimen name="screen_pinning_padding_end">40dp</dimen>
<dimen name="settings_panel_width">560dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index c701044..6f5bddf 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -38,4 +38,8 @@
<dimen name="wifi_assistant_padding_start_end">24dp</dimen>
<dimen name="wifi_assistant_padding">25dp</dimen>
<dimen name="wifi_assistant_text_padding">24dp</dimen>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+
</resources>
diff --git a/res/values-sw800dp/dimens.xml b/res/values-sw800dp/dimens.xml
new file mode 100644
index 0000000..48392ef
--- /dev/null
+++ b/res/values-sw800dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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>
+
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 4aa4142..f49eff7 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -283,6 +283,19 @@
<!-- ComponentName to launch a vendor-specific enrollment activity if available -->
<string name="config_face_enroll" translatable="false"></string>
+ <!-- ComponentName to launch a vendor-specific posture guidance activity if available -->
+ <string name="config_face_enroll_guidance_page" translatable="false"></string>
+
+ <!-- Whether to support posture listening for face auth, default is 0(DEVICE_POSTURE_UNKNOWN)
+ means setting will try listening on device posture changes.
+ 0 : DEVICE_POSTURE_UNKNOWN
+ 1 : DEVICE_POSTURE_CLOSED
+ 2 : DEVICE_POSTURE_HALF_OPENED
+ 3 : DEVICE_POSTURE_OPENED
+ 4 : DEVICE_POSTURE_FLIPPED
+ -->
+ <integer name="config_face_enroll_supported_posture">0</integer>
+
<!-- Whether to show the "less secure" info section on the face enroll intro screen -->
<bool name="config_face_intro_show_less_secure">false</bool>
@@ -292,6 +305,9 @@
<!-- Whether to use the Lottie animation for the face education enrollment screen -->
<bool name="config_face_education_use_lottie">false</bool>
+ <!-- Whether to support enrollment during setup wizard flow -->
+ <bool name="config_suw_support_face_enroll">true</bool>
+
<!-- App intent -->
<string name="config_account_intent_uri" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index afb6f68..84cfe63 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -242,6 +242,10 @@
<item name="face_preview_scale" format="float" type="dimen">1.0</item>
<dimen name="face_enroll_intro_illustration_margin_bottom">0dp</dimen>
+ <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+ <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+ <dimen name="biometric_auth_pattern_view_max_size">@dimen/biometric_auth_pattern_view_size</dimen>
+
<!-- Confirm device credentials -->
<dimen name="confirm_credentials_security_method_margin">48dp</dimen>
<dimen name="confirm_credentials_layout_width">@dimen/match_parent</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4839b68..d105d78 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1287,9 +1287,9 @@
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (default) [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_finish_v2_message" product="default">Now you can use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase</string>
<!-- Title for require screen on to auth toggle shown in fingerprint enrollment dialog once enrollment is completed. [CHAR LIMIT=NONE] -->
- <string name="security_settings_require_screen_on_to_auth_title">Unlock only when screen is on</string>
+ <string name="security_settings_require_screen_on_to_auth_title">Touch to unlock anytime</string>
<!-- Description for require screen on to auth toggle shown in fingerprint enrollment dialog once enrollment is completed. [CHAR LIMIT=NONE] -->
- <string name="security_settings_require_screen_on_to_auth_description">The screen must be on before you can unlock with your fingerprint. This makes accidental unlocking less likely.</string>
+ <string name="security_settings_require_screen_on_to_auth_description">Touch the sensor to unlock, even when the screen is off. This makes accidental unlocking more likely.</string>
<!-- Description for require screen on to auth toggle shown in fingerprint enrollment dialog once enrollment is completed. [CHAR LIMIT=NONE] -->
<string name="security_settings_require_screen_on_to_auth_keywords">Screen, Unlock</string>
<!-- Button text to skip enrollment of fingerprint [CHAR LIMIT=40] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4fc6e9f..ce683724 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -432,10 +432,11 @@
</style>
<style name="LockPatternContainerStyle">
- <item name="android:maxHeight">620dp</item>
- <item name="android:maxWidth">620dp</item>
- <item name="android:minHeight">0dp</item>
- <item name="android:minWidth">0dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+ <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+ <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
<item name="android:paddingBottom">0dp</item>
<item name="android:paddingHorizontal">0dp</item>
<item name="android:paddingTop">0dp</item>
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
index 03bff7b..369f453 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
@@ -36,6 +36,7 @@
import com.android.settings.Settings;
import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
+import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
@@ -228,6 +229,8 @@
addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class);
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
+ addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
+ addActivityFilter(activityFilters, Settings.FaceSettingsInternalActivity.class);
addActivityFilter(activityFilters, AvatarPickerActivity.class);
mSplitController.registerRule(new ActivityRule(activityFilters, true /* alwaysExpand */));
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
index 932c410..bb16f0b 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
@@ -48,6 +48,7 @@
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.core.InstrumentedActivity;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockPattern;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -215,11 +216,16 @@
mIsFaceEnrollable =
faceManager.getEnrolledFaces(mUserId).size() < maxEnrolls;
- // exclude face enrollment from setup wizard if configured as a convenience
- // isSetupWizard is always false for unicorn enrollment, so if consent is
- // required check if setup has completed instead.
- final boolean isSettingUp = isSetupWizard || (mParentalOptionsRequired
+ final boolean parentalConsent = isSetupWizard || (mParentalOptionsRequired
&& !WizardManagerHelper.isUserSetupComplete(this));
+ if (parentalConsent && isMultiSensor && mIsFaceEnrollable) {
+ // Exclude face enrollment from setup wizard if feature config not supported
+ // in setup wizard flow, we still allow user enroll faces through settings.
+ mIsFaceEnrollable = FeatureFactory.getFactory(getApplicationContext())
+ .getFaceFeatureProvider()
+ .isSetupWizardSupported(getApplicationContext());
+ Log.d(TAG, "config_suw_support_face_enroll: " + mIsFaceEnrollable);
+ }
}
}
if (mHasFeatureFingerprint) {
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index eea1bad..2f852f0 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -38,7 +38,10 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
import com.android.settings.core.InstrumentedActivity;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
+import com.android.systemui.unfold.updates.FoldProvider;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
@@ -60,8 +63,10 @@
public static final String EXTRA_KEY_SENSOR_ID = "sensor_id";
public static final String EXTRA_KEY_CHALLENGE = "challenge";
public static final String EXTRA_KEY_MODALITY = "sensor_modality";
+ public static final String EXTRA_KEY_NEXT_LAUNCHED = "next_launched";
public static final String EXTRA_FINISHED_ENROLL_FACE = "finished_enrolling_face";
public static final String EXTRA_FINISHED_ENROLL_FINGERPRINT = "finished_enrolling_fingerprint";
+ public static final String EXTRA_LAUNCHED_POSTURE_GUIDANCE = "launched_posture_guidance";
/**
* Used by the choose fingerprint wizard to indicate the wizard is
@@ -115,14 +120,25 @@
* example, when starting fingerprint enroll after face enroll.
*/
public static final int ENROLL_NEXT_BIOMETRIC_REQUEST = 6;
+ public static final int REQUEST_POSTURE_GUIDANCE = 7;
protected boolean mLaunchedConfirmLock;
+ protected boolean mLaunchedPostureGuidance;
+ protected boolean mNextLaunched;
protected byte[] mToken;
protected int mUserId;
protected int mSensorId;
+ @BiometricUtils.DevicePostureInt
+ protected int mDevicePostureState;
protected long mChallenge;
protected boolean mFromSettingsSummary;
protected FooterBarMixin mFooterBarMixin;
+ @Nullable
+ protected ScreenSizeFoldProvider mScreenSizeFoldProvider;
+ @Nullable
+ protected Intent mPostureGuidanceIntent = null;
+ @Nullable
+ protected FoldProvider.FoldCallback mFoldCallback = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -139,16 +155,23 @@
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
}
mFromSettingsSummary = getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false);
- if (savedInstanceState != null && mToken == null) {
- mLaunchedConfirmLock = savedInstanceState.getBoolean(EXTRA_KEY_LAUNCHED_CONFIRM);
- mToken = savedInstanceState.getByteArray(
- ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
- mFromSettingsSummary =
- savedInstanceState.getBoolean(EXTRA_FROM_SETTINGS_SUMMARY, false);
- mChallenge = savedInstanceState.getLong(EXTRA_KEY_CHALLENGE);
- mSensorId = savedInstanceState.getInt(EXTRA_KEY_SENSOR_ID);
+ if (savedInstanceState != null) {
+ if (mToken == null) {
+ mLaunchedConfirmLock = savedInstanceState.getBoolean(EXTRA_KEY_LAUNCHED_CONFIRM);
+ mToken = savedInstanceState.getByteArray(
+ ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+ mFromSettingsSummary =
+ savedInstanceState.getBoolean(EXTRA_FROM_SETTINGS_SUMMARY, false);
+ mChallenge = savedInstanceState.getLong(EXTRA_KEY_CHALLENGE);
+ mSensorId = savedInstanceState.getInt(EXTRA_KEY_SENSOR_ID);
+ }
+ mLaunchedPostureGuidance = savedInstanceState.getBoolean(
+ EXTRA_LAUNCHED_POSTURE_GUIDANCE);
+ mNextLaunched = savedInstanceState.getBoolean(EXTRA_KEY_NEXT_LAUNCHED);
}
mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
+ mPostureGuidanceIntent = FeatureFactory.getFactory(getApplicationContext())
+ .getFaceFeatureProvider().getPostureGuidanceIntent(getApplicationContext());
}
@Override
@@ -159,6 +182,8 @@
outState.putBoolean(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
outState.putLong(EXTRA_KEY_CHALLENGE, mChallenge);
outState.putInt(EXTRA_KEY_SENSOR_ID, mSensorId);
+ outState.putBoolean(EXTRA_LAUNCHED_POSTURE_GUIDANCE, mLaunchedPostureGuidance);
+ outState.putBoolean(EXTRA_KEY_NEXT_LAUNCHED, mNextLaunched);
}
@Override
@@ -184,6 +209,12 @@
@Override
protected void onStop() {
super.onStop();
+ if (mScreenSizeFoldProvider != null && mFoldCallback != null) {
+ mScreenSizeFoldProvider.unregisterCallback(mFoldCallback);
+ }
+ mScreenSizeFoldProvider = null;
+ mFoldCallback = null;
+
if (!isChangingConfigurations() && shouldFinishWhenBackgrounded()
&& !BiometricUtils.isAnyMultiBiometricFlow(this)) {
setResult(RESULT_TIMEOUT);
@@ -191,6 +222,17 @@
}
}
+ protected boolean launchPostureGuidance() {
+ if (mPostureGuidanceIntent == null || mLaunchedPostureGuidance) {
+ return false;
+ }
+ BiometricUtils.copyMultiBiometricExtras(getIntent(), mPostureGuidanceIntent);
+ startActivityForResult(mPostureGuidanceIntent, REQUEST_POSTURE_GUIDANCE);
+ mLaunchedPostureGuidance = true;
+ overridePendingTransition(0 /* no enter anim */, 0 /* no exit anim */);
+ return mLaunchedPostureGuidance;
+ }
+
protected boolean shouldFinishWhenBackgrounded() {
return !WizardManagerHelper.isAnySetupWizard(getIntent());
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index acfe5a1..730e049 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -155,6 +155,8 @@
if (savedInstanceState != null) {
mConfirmingCredentials = savedInstanceState.getBoolean(KEY_CONFIRMING_CREDENTIALS);
mHasScrolledToBottom = savedInstanceState.getBoolean(KEY_SCROLLED_TO_BOTTOM);
+ mLaunchedPostureGuidance = savedInstanceState.getBoolean(
+ EXTRA_LAUNCHED_POSTURE_GUIDANCE);
}
Intent intent = getIntent();
@@ -273,6 +275,7 @@
finish();
}
}
+ mNextLaunched = true;
}
private void launchChooseLock() {
diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java
index 4cd2f790..7333083 100644
--- a/src/com/android/settings/biometrics/BiometricUtils.java
+++ b/src/com/android/settings/biometrics/BiometricUtils.java
@@ -16,6 +16,7 @@
package com.android.settings.biometrics;
+import android.annotation.IntDef;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
@@ -39,6 +40,7 @@
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -46,17 +48,53 @@
import com.google.android.setupcompat.util.WizardManagerHelper;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Common biometric utilities.
*/
public class BiometricUtils {
private static final String TAG = "BiometricUtils";
+ // Note: Theis IntDef must align SystemUI DevicePostureInt
+ @IntDef(prefix = {"DEVICE_POSTURE_"}, value = {
+ DEVICE_POSTURE_UNKNOWN,
+ DEVICE_POSTURE_CLOSED,
+ DEVICE_POSTURE_HALF_OPENED,
+ DEVICE_POSTURE_OPENED,
+ DEVICE_POSTURE_FLIPPED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DevicePostureInt {}
+
+ // NOTE: These constants **must** match those defined for Jetpack Sidecar. This is because we
+ // use the Device State -> Jetpack Posture map in DevicePostureControllerImpl to translate
+ // between the two.
+ public static final int DEVICE_POSTURE_UNKNOWN = 0;
+ public static final int DEVICE_POSTURE_CLOSED = 1;
+ public static final int DEVICE_POSTURE_HALF_OPENED = 2;
+ public static final int DEVICE_POSTURE_OPENED = 3;
+ public static final int DEVICE_POSTURE_FLIPPED = 4;
+
+ public static int sAllowEnrollPosture = DEVICE_POSTURE_UNKNOWN;
+
/**
* Request was sent for starting another enrollment of a previously
* enrolled biometric of the same type.
*/
public static int REQUEST_ADD_ANOTHER = 7;
+
+ /**
+ * Gatekeeper credential not match exception, it throws if VerifyCredentialResponse is not
+ * matched in requestGatekeeperHat().
+ */
+ public static class GatekeeperCredentialNotMatchException extends IllegalStateException {
+ public GatekeeperCredentialNotMatchException(String s) {
+ super(s);
+ }
+ };
+
/**
* Given the result from confirming or choosing a credential, request Gatekeeper to generate
* a HardwareAuthToken with the Gatekeeper Password together with a biometric challenge.
@@ -66,6 +104,8 @@
* @param userId User ID that the credential/biometric operation applies to
* @param challenge Unique biometric challenge from FingerprintManager/FaceManager
* @return
+ * @throws GatekeeperCredentialNotMatchException if Gatekeeper response is not match
+ * @throws IllegalStateException if Gatekeeper Password is missing
*/
public static byte[] requestGatekeeperHat(@NonNull Context context, @NonNull Intent result,
int userId, long challenge) {
@@ -83,7 +123,7 @@
final VerifyCredentialResponse response = utils.verifyGatekeeperPasswordHandle(gkPwHandle,
challenge, userId);
if (!response.isMatched()) {
- throw new IllegalStateException("Unable to request Gatekeeper HAT");
+ throw new GatekeeperCredentialNotMatchException("Unable to request Gatekeeper HAT");
}
return response.getGatekeeperHAT();
}
@@ -152,9 +192,13 @@
*/
public static Intent getFingerprintFindSensorIntent(@NonNull Context context,
@NonNull Intent activityIntent) {
- Intent intent = new Intent(context, FingerprintEnrollFindSensor.class);
- SetupWizardUtils.copySetupExtras(activityIntent, intent);
- return intent;
+ if (WizardManagerHelper.isAnySetupWizard(activityIntent)) {
+ Intent intent = new Intent(context, SetupFingerprintEnrollFindSensor.class);
+ SetupWizardUtils.copySetupExtras(activityIntent, intent);
+ return intent;
+ } else {
+ return new Intent(context, FingerprintEnrollFindSensor.class);
+ }
}
/**
@@ -265,6 +309,51 @@
|| isMultiBiometricFingerprintEnrollmentFlow(activity);
}
+ /**
+ * Used to check if the activity is showing a posture guidance to user.
+ *
+ * @param devicePosture the device posture state
+ * @param isLaunchedPostureGuidance True launching a posture guidance to user
+ * @return True if the activity is showing posture guidance to user
+ */
+ public static boolean isPostureGuidanceShowing(@DevicePostureInt int devicePosture,
+ boolean isLaunchedPostureGuidance) {
+ return !isPostureAllowEnrollment(devicePosture) && isLaunchedPostureGuidance;
+ }
+
+ /**
+ * Used to check if current device posture state is allow to enroll biometrics.
+ * For compatibility, we don't restrict enrollment if device do not config.
+ *
+ * @param devicePosture True if current device posture allow enrollment
+ * @return True if current device posture state allow enrollment
+ */
+ public static boolean isPostureAllowEnrollment(@DevicePostureInt int devicePosture) {
+ return (sAllowEnrollPosture == DEVICE_POSTURE_UNKNOWN)
+ || (devicePosture == sAllowEnrollPosture);
+ }
+
+ /**
+ * Used to check if the activity should show a posture guidance to user.
+ *
+ * @param devicePosture the device posture state
+ * @param isLaunchedPostureGuidance True launching a posture guidance to user
+ * @return True if posture disallow enroll and posture guidance not showing, false otherwise.
+ */
+ public static boolean shouldShowPostureGuidance(@DevicePostureInt int devicePosture,
+ boolean isLaunchedPostureGuidance) {
+ return !isPostureAllowEnrollment(devicePosture) && !isLaunchedPostureGuidance;
+ }
+
+ /**
+ * Sets allowed device posture for face enrollment.
+ *
+ * @param devicePosture the allowed posture state {@link DevicePostureInt} for enrollment
+ */
+ public static void setDevicePosturesAllowEnroll(@DevicePostureInt int devicePosture) {
+ sAllowEnrollPosture = devicePosture;
+ }
+
public static void copyMultiBiometricExtras(@NonNull Intent fromIntent,
@NonNull Intent toIntent) {
PendingIntent pendingIntent = (PendingIntent) fromIntent.getExtra(
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
index d2d356b..4ef4752 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
@@ -16,24 +16,35 @@
package com.android.settings.biometrics.face;
+import static com.android.settings.biometrics.BiometricUtils.isPostureAllowEnrollment;
+import static com.android.settings.biometrics.BiometricUtils.isPostureGuidanceShowing;
+
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.res.Configuration;
import android.hardware.face.FaceManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.Button;
import android.widget.CompoundButton;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.SetupSkipDialog;
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
+import com.android.systemui.unfold.updates.FoldProvider;
import com.airbnb.lottie.LottieAnimationView;
import com.google.android.setupcompat.template.FooterBarMixin;
@@ -41,18 +52,19 @@
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.view.IllustrationVideoView;
+/**
+ * Provides animated education for users to know how to enroll a face with appropriate posture.
+ */
public class FaceEnrollEducation extends BiometricEnrollBase {
private static final String TAG = "FaceEducation";
private FaceManager mFaceManager;
private FaceEnrollAccessibilityToggle mSwitchDiversity;
-
private boolean mIsUsingLottie;
private IllustrationVideoView mIllustrationDefault;
private LottieAnimationView mIllustrationLottie;
private View mIllustrationAccessibility;
private Intent mResultIntent;
- private boolean mNextClicked;
private boolean mAccessibilityEnabled;
private final CompoundButton.OnCheckedChangeListener mSwitchDiversityListener =
@@ -155,6 +167,34 @@
}
@Override
+ protected void onStart() {
+ super.onStart();
+ if (getPostureGuidanceIntent() == null) {
+ Log.d(TAG, "Device do not support posture guidance");
+ return;
+ }
+
+ BiometricUtils.setDevicePosturesAllowEnroll(
+ getResources().getInteger(R.integer.config_face_enroll_supported_posture));
+
+ if (getPostureCallback() == null) {
+ mFoldCallback = isFolded -> {
+ mDevicePostureState = isFolded ? BiometricUtils.DEVICE_POSTURE_CLOSED
+ : BiometricUtils.DEVICE_POSTURE_OPENED;
+ if (BiometricUtils.shouldShowPostureGuidance(mDevicePostureState,
+ mLaunchedPostureGuidance) && !mNextLaunched) {
+ launchPostureGuidance();
+ }
+ };
+ }
+
+ if (mScreenSizeFoldProvider == null) {
+ mScreenSizeFoldProvider = new ScreenSizeFoldProvider(getApplicationContext());
+ mScreenSizeFoldProvider.registerCallback(mFoldCallback, getMainExecutor());
+ }
+ }
+
+ @Override
protected void onResume() {
super.onResume();
mSwitchDiversityListener.onCheckedChanged(mSwitchDiversity.getSwitch(),
@@ -172,7 +212,8 @@
@Override
protected boolean shouldFinishWhenBackgrounded() {
- return super.shouldFinishWhenBackgrounded() && !mNextClicked;
+ return super.shouldFinishWhenBackgrounded() && !mNextLaunched
+ && !isPostureGuidanceShowing(mDevicePostureState, mLaunchedPostureGuidance);
}
@Override
@@ -206,13 +247,14 @@
FaceEnrollAccessibilityDialog dialog = FaceEnrollAccessibilityDialog.newInstance();
dialog.setPositiveButtonListener((dialog1, which) -> {
startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST);
- mNextClicked = true;
+ mNextLaunched = true;
});
dialog.show(getSupportFragmentManager(), FaceEnrollAccessibilityDialog.class.getName());
} else {
startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST);
- mNextClicked = true;
+ mNextLaunched = true;
}
+
}
protected void onSkipButtonClick(View view) {
@@ -224,14 +266,28 @@
}
@Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mScreenSizeFoldProvider != null && getPostureCallback() != null) {
+ mScreenSizeFoldProvider.onConfigurationChange(newConfig);
+ }
+ }
+
+ @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_POSTURE_GUIDANCE) {
+ mLaunchedPostureGuidance = false;
+ if (resultCode == RESULT_CANCELED || resultCode == RESULT_SKIP) {
+ onSkipButtonClick(getCurrentFocus());
+ }
+ return;
+ }
mResultIntent = data;
boolean hasEnrolledFace = false;
if (data != null) {
hasEnrolledFace = data.getBooleanExtra(EXTRA_FINISHED_ENROLL_FACE, false);
}
- if (resultCode == RESULT_TIMEOUT) {
+ if (resultCode == RESULT_TIMEOUT || !isPostureAllowEnrollment(mDevicePostureState)) {
setResult(resultCode, data);
finish();
} else if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST
@@ -243,6 +299,26 @@
finish();
}
}
+ mNextLaunched = false;
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected Intent getPostureGuidanceIntent() {
+ return mPostureGuidanceIntent;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected FoldProvider.FoldCallback getPostureCallback() {
+ return mFoldCallback;
+ }
+
+ @VisibleForTesting
+ @BiometricUtils.DevicePostureInt
+ protected int getDevicePostureState() {
+ return mDevicePostureState;
}
@Override
@@ -262,8 +338,10 @@
private void showDefaultIllustration() {
if (mIsUsingLottie) {
+ mIllustrationLottie.setAnimation(R.raw.face_education_lottie);
mIllustrationLottie.setVisibility(View.VISIBLE);
mIllustrationLottie.playAnimation();
+ mIllustrationLottie.setProgress(0f);
} else {
mIllustrationDefault.setVisibility(View.VISIBLE);
mIllustrationDefault.start();
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index ed74d2a..a123308 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -18,9 +18,12 @@
import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_UNLOCK_DISABLED;
+import static com.android.settings.biometrics.BiometricUtils.GatekeeperCredentialNotMatchException;
+
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.Intent;
+import android.content.res.Configuration;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.FaceManager;
@@ -36,6 +39,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
@@ -43,11 +47,12 @@
import com.android.settings.biometrics.BiometricEnrollIntroduction;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.MultiBiometricEnrollHelper;
-import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.SetupSkipDialog;
import com.android.settings.utils.SensorPrivacyManagerHelper;
import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
+import com.android.systemui.unfold.updates.FoldProvider;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -61,7 +66,6 @@
private static final String TAG = "FaceEnrollIntroduction";
private FaceManager mFaceManager;
- private FaceFeatureProvider mFaceFeatureProvider;
@Nullable private FooterButton mPrimaryFooterButton;
@Nullable private FooterButton mSecondaryFooterButton;
@Nullable private SensorPrivacyManager mSensorPrivacyManager;
@@ -99,6 +103,12 @@
}
@Override
+ protected boolean shouldFinishWhenBackgrounded() {
+ return super.shouldFinishWhenBackgrounded() && !BiometricUtils.isPostureGuidanceShowing(
+ mDevicePostureState, mLaunchedPostureGuidance);
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -142,9 +152,7 @@
infoMessageRequireEyes.setText(getInfoMessageRequireEyes());
}
- mFaceManager = Utils.getFaceManagerOrNull(this);
- mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
- .getFaceFeatureProvider();
+ mFaceManager = getFaceManager();
// This path is an entry point for SetNewPasswordController, e.g.
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
@@ -154,11 +162,22 @@
// We either block on generateChallenge, or need to gray out the "next" button until
// the challenge is ready. Let's just do this for now.
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
- mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId,
- challenge);
- mSensorId = sensorId;
- mChallenge = challenge;
- mFooterBarMixin.getPrimaryButton().setEnabled(true);
+ if (isFinishing()) {
+ // Do nothing if activity is finishing
+ Log.w(TAG, "activity finished before challenge callback launched.");
+ return;
+ }
+
+ try {
+ mToken = requestGatekeeperHat(challenge);
+ mSensorId = sensorId;
+ mChallenge = challenge;
+ mFooterBarMixin.getPrimaryButton().setEnabled(true);
+ } catch (GatekeeperCredentialNotMatchException e) {
+ // Let BiometricEnrollBase#onCreate() to trigger confirmLock()
+ getIntent().removeExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE);
+ recreate();
+ }
});
}
}
@@ -172,8 +191,82 @@
Log.v(TAG, "cameraPrivacyEnabled : " + cameraPrivacyEnabled);
}
+ @VisibleForTesting
+ @Nullable
+ protected FaceManager getFaceManager() {
+ return Utils.getFaceManagerOrNull(this);
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected Intent getPostureGuidanceIntent() {
+ return mPostureGuidanceIntent;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected FoldProvider.FoldCallback getPostureCallback() {
+ return mFoldCallback;
+ }
+
+ @VisibleForTesting
+ @BiometricUtils.DevicePostureInt
+ protected int getDevicePostureState() {
+ return mDevicePostureState;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected byte[] requestGatekeeperHat(long challenge) {
+ return BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
+ }
+
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mScreenSizeFoldProvider != null && getPostureCallback() != null) {
+ mScreenSizeFoldProvider.onConfigurationChange(newConfig);
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (getPostureGuidanceIntent() == null) {
+ Log.d(TAG, "Device do not support posture guidance");
+ return;
+ }
+
+ BiometricUtils.setDevicePosturesAllowEnroll(
+ getResources().getInteger(R.integer.config_face_enroll_supported_posture));
+
+ if (getPostureCallback() == null) {
+ mFoldCallback = isFolded -> {
+ mDevicePostureState = isFolded ? BiometricUtils.DEVICE_POSTURE_CLOSED
+ : BiometricUtils.DEVICE_POSTURE_OPENED;
+ if (BiometricUtils.shouldShowPostureGuidance(mDevicePostureState,
+ mLaunchedPostureGuidance) && !mNextLaunched) {
+ launchPostureGuidance();
+ }
+ };
+ }
+
+ if (mScreenSizeFoldProvider == null) {
+ mScreenSizeFoldProvider = new ScreenSizeFoldProvider(getApplicationContext());
+ mScreenSizeFoldProvider.registerCallback(mFoldCallback, getMainExecutor());
+ }
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_POSTURE_GUIDANCE) {
+ mLaunchedPostureGuidance = false;
+ if (resultCode == RESULT_CANCELED || resultCode == RESULT_SKIP) {
+ onSkipButtonClick(getCurrentFocus());
+ }
+ return;
+ }
+
// If user has skipped or finished enrolling, don't restart enrollment.
final boolean isEnrollRequest = requestCode == BIOMETRIC_FIND_SENSOR_REQUEST
|| requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST;
@@ -184,10 +277,12 @@
hasEnrolledFace = data.getBooleanExtra(EXTRA_FINISHED_ENROLL_FACE, false);
}
- if (resultCode == RESULT_CANCELED && hasEnrolledFace) {
- setResult(resultCode, data);
- finish();
- return;
+ if (resultCode == RESULT_CANCELED) {
+ if (hasEnrolledFace || !BiometricUtils.isPostureAllowEnrollment(mDevicePostureState)) {
+ setResult(resultCode, data);
+ finish();
+ return;
+ }
}
if (isEnrollRequest && isResultSkipOrFinished || hasEnrolledFace) {
diff --git a/src/com/android/settings/biometrics/face/FaceFeatureProvider.java b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
index 26ea261..1a4fd90 100644
--- a/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
+++ b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
@@ -17,9 +17,19 @@
package com.android.settings.biometrics.face;
import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.Nullable;
/** Feature provider for face unlock */
public interface FaceFeatureProvider {
+ /** Returns specified intent config by resource R.string.config_face_enroll_guidance_page. */
+ @Nullable
+ Intent getPostureGuidanceIntent(Context context);
+
/** Returns true if attention checking is supported. */
boolean isAttentionSupported(Context context);
+
+ /** Returns true if setup wizard supported face enrollment. */
+ boolean isSetupWizardSupported(Context context);
}
diff --git a/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java b/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java
index e508600..8b7edce 100644
--- a/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java
+++ b/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java
@@ -16,13 +16,48 @@
package com.android.settings.biometrics.face;
+import android.content.ComponentName;
import android.content.Context;
-import android.provider.Settings;
+import android.content.Intent;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
public class FaceFeatureProviderImpl implements FaceFeatureProvider {
+ /**
+ * Returns the guidance page intent if device support {@link FoldingFeature}, and we want to
+ * guide user enrolling faces with specific device posture.
+ *
+ * @param context the application context
+ * @return the posture guidance intent, otherwise null if device not support
+ */
+ @Nullable
+ @Override
+ public Intent getPostureGuidanceIntent(Context context) {
+ final String flattenedString = context.getString(R.string.config_face_enroll_guidance_page);
+ final Intent intent;
+ if (!TextUtils.isEmpty(flattenedString)) {
+ ComponentName componentName = ComponentName.unflattenFromString(flattenedString);
+ if (componentName != null) {
+ intent = new Intent();
+ intent.setComponent(componentName);
+ return intent;
+ }
+ }
+ return null;
+ }
+
@Override
public boolean isAttentionSupported(Context context) {
return true;
}
+
+ @Override
+ public boolean isSetupWizardSupported(@NonNull Context context) {
+ return true;
+ }
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index bbb4f45..2721c77 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -494,8 +494,10 @@
if (root != null) {
root.removeAll();
}
- root = getPreferenceScreen();
- addFingerprintItemPreferences(root);
+ final String fpPrefKey = addFingerprintItemPreferences(root);
+ if (isSfps()) {
+ scrollToPreference(fpPrefKey);
+ }
addPreferencesFromResource(getPreferenceScreenResId());
mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
@@ -529,15 +531,20 @@
}
}
- private void addFingerprintItemPreferences(PreferenceGroup root) {
+ private String addFingerprintItemPreferences(PreferenceGroup root) {
root.removeAll();
+ String keyToReturn = KEY_FINGERPRINT_ADD;
final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
final int fingerprintCount = items.size();
for (int i = 0; i < fingerprintCount; i++) {
final Fingerprint item = items.get(i);
FingerprintPreference pref = new FingerprintPreference(root.getContext(),
this /* onDeleteClickListener */);
- pref.setKey(genKey(item.getBiometricId()));
+ String key = genKey(item.getBiometricId());
+ if (i == 0) {
+ keyToReturn = key;
+ }
+ pref.setKey(key);
pref.setTitle(item.getName());
pref.setFingerprint(item);
pref.setPersistent(false);
@@ -560,6 +567,8 @@
addPreference.setOnPreferenceChangeListener(this);
updateAddPreference();
createFooterPreference(root);
+
+ return keyToReturn;
}
private void updateAddPreference() {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
index 5b183c1..6507083 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java
@@ -51,21 +51,26 @@
} else if (getRestrictingAdmin() != null) {
return false;
}
- int defaultValue = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_requireScreenOnToAuthEnabled) ? 1 : 0;
-
- return Settings.Secure.getIntForUser(
+ int toReturn = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
- defaultValue,
- getUserHandle()) != 0;
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
+ -1,
+ getUserHandle());
+ if (toReturn == -1) {
+ toReturn = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_requireScreenOnToAuthEnabled) ? 1 : 0;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, toReturn, getUserHandle());
+ }
+
+ return toReturn == 1;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Secure.putIntForUser(
mContext.getContentResolver(),
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
isChecked ? 1 : 0,
getUserHandle());
return true;
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index c39ef66..07c533f 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -215,6 +215,7 @@
private FooterButton mNextButton;
@VisibleForTesting protected LockscreenCredential mChosenPattern;
private ColorStateList mDefaultHeaderColorList;
+ private View mSudContent;
/**
* The patten used during the help screen to show how to draw a pattern.
@@ -537,6 +538,10 @@
);
mSkipOrClearButton = mixin.getSecondaryButton();
mNextButton = mixin.getPrimaryButton();
+ // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+ mSudContent = layout.findViewById(R.id.sud_layout_content);
+ mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+ 0);
return layout;
}
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 1062d94..b4f0aa3 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -100,6 +100,7 @@
private CountDownTimer mCountdownTimer;
private GlifLayout mGlifLayout;
+ private View mSudContent;
// caller-supplied text for various prompts
private CharSequence mHeaderText;
@@ -129,7 +130,10 @@
mGlifLayout = view.findViewById(R.id.setup_wizard_layout);
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
-
+ // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+ mSudContent = mGlifLayout.findViewById(R.id.sud_layout_content);
+ mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+ 0);
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
// make it so unhandled touch events within the unlock screen go to the
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
index 4e08f98..71c532c 100644
--- a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
@@ -20,10 +20,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -39,7 +39,6 @@
import android.os.UserHandle;
import android.os.UserManager;
-import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,6 +48,7 @@
import org.robolectric.shadows.ShadowApplication;
import java.util.Arrays;
+import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public final class AppWithAdminGrantedPermissionsCounterTest {
@@ -129,7 +129,7 @@
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(),
eq(MANAGED_PROFILE_ID));
- verify(mPackageManager, atLeast(0)).getInstallReason(anyObject(), anyObject());
+ verify(mPackageManager, atLeast(0)).getInstallReason(any(), any());
verifyNoMoreInteractions(mPackageManager);
}
@@ -166,9 +166,9 @@
}
private void configureInstallTimePermissions() throws RemoteException {
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_1_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_1_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_2_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_2_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_3_UID))
.thenReturn(PackageManager.PERMISSION_DENIED);
@@ -178,9 +178,9 @@
.thenReturn(PackageManager.PERMISSION_DENIED);
when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_4_UID))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_5_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_5_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_6_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_6_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
}
@@ -189,15 +189,15 @@
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_2))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
}
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
index a818637..9a4978b 100644
--- a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
@@ -20,10 +20,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -122,19 +122,19 @@
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
when(mDevicePolicyManager.getPermissionGrantState(null, APP_1, PERMISSION_2))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_2), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_3), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_4), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_5), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
// Grant install-time permissions as appropriate.
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_1_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_1_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_2_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_2_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
when(mPackageManagerService.checkUidPermission(PERMISSION_1, APP_3_UID))
.thenReturn(PackageManager.PERMISSION_DENIED);
@@ -144,7 +144,7 @@
.thenReturn(PackageManager.PERMISSION_DENIED);
when(mPackageManagerService.checkUidPermission(PERMISSION_2, APP_4_UID))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_5_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_5_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
// app3 and app5 were installed by enterprise policy.
@@ -168,11 +168,11 @@
buildInfo(APP_6_UID, APP_6, 0 /* flags */, Build.VERSION_CODES.M)));
// Grant run-time permissions as appropriate.
- when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), anyObject()))
+ when(mDevicePolicyManager.getPermissionGrantState(eq(null), eq(APP_6), any()))
.thenReturn(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
// Grant install-time permissions as appropriate.
- when(mPackageManagerService.checkUidPermission(anyObject(), eq(APP_6_UID)))
+ when(mPackageManagerService.checkUidPermission(any(), eq(APP_6_UID)))
.thenReturn(PackageManager.PERMISSION_DENIED);
// app6 was not installed by enterprise policy.
@@ -202,7 +202,7 @@
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(),
eq(MANAGED_PROFILE_ID));
- verify(mPackageManager, atLeast(0)).getInstallReason(anyObject(), anyObject());
+ verify(mPackageManager, atLeast(0)).getInstallReason(any(), any());
verifyNoMoreInteractions(mPackageManager);
}
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
index e2aed36..602d678 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
@@ -20,11 +20,11 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -170,7 +170,7 @@
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID));
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MANAGED_PROFILE_ID));
verify(mPackageManager, atLeast(0))
- .queryIntentActivitiesAsUser(anyObject(), anyInt(), anyInt());
+ .queryIntentActivitiesAsUser(any(), anyInt(), anyInt());
}
public static boolean checkAppFound(List<UserAppInfo> mInstalledAppList, String appId,
diff --git a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
index e0a0836..da5ada7 100644
--- a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
@@ -20,7 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
diff --git a/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPreferenceControllerTest.java
index 3e46027..178a26f 100644
--- a/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPreferenceControllerTest.java
@@ -24,7 +24,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.Manifest;
@@ -142,6 +142,6 @@
controller.getSettingIntent(null);
- verifyZeroInteractions(assistUtils);
+ verifyNoInteractions(assistUtils);
}
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollEducationTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollEducationTest.java
new file mode 100644
index 0000000..b4dddde
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollEducationTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.settings.biometrics.face;
+
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.util.DisplayMetrics.DENSITY_XXXHIGH;
+
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_NEXT_LAUNCHED;
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_LAUNCHED_POSTURE_GUIDANCE;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_CLOSED;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_OPENED;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.hardware.face.FaceManager;
+import android.view.View;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUtils.class})
+public class FaceEnrollEducationTest {
+ @Mock
+ private FaceManager mFaceManager;
+
+ private Context mContext;
+ private ActivityController<TestFaceEnrollEducation> mActivityController;
+ private TestFaceEnrollEducation mActivity;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ public static class TestFaceEnrollEducation extends FaceEnrollEducation {
+
+ @Override
+ protected boolean launchPostureGuidance() {
+ return super.launchPostureGuidance();
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowUtils.setFaceManager(mFaceManager);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ }
+
+ @After
+ public void tearDown() {
+ ShadowUtils.reset();
+ }
+
+ private void setupActivityForPosture() {
+ final Intent testIntent = new Intent();
+ // Set the challenge token so the confirm screen will not be shown
+ testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+ testIntent.putExtra(EXTRA_KEY_NEXT_LAUNCHED, false);
+ testIntent.putExtra(EXTRA_LAUNCHED_POSTURE_GUIDANCE, false);
+
+ when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
+ testIntent);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mActivityController = Robolectric.buildActivity(
+ TestFaceEnrollEducation.class, testIntent);
+ mActivity = spy(mActivityController.create().get());
+
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ }
+
+ private void setupActivity() {
+ final Intent testIntent = new Intent();
+ // Set the challenge token so the confirm screen will not be shown
+ testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+
+ when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
+ null /* Simulate no posture intent */);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mActivityController = Robolectric.buildActivity(
+ TestFaceEnrollEducation.class, testIntent);
+ mActivity = spy(mActivityController.create().get());
+
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ }
+
+ private GlifLayout getGlifLayout() {
+ return mActivity.findViewById(R.id.setup_wizard_layout);
+ }
+
+ @Test
+ public void testFaceEnrollEducation_hasHeader() {
+ setupActivity();
+ CharSequence headerText = getGlifLayout().getHeaderText();
+
+ assertThat(headerText.toString()).isEqualTo(
+ mContext.getString(R.string.security_settings_face_enroll_education_title));
+ }
+
+ @Test
+ public void testFaceEnrollEducation_hasDescription() {
+ setupActivity();
+ CharSequence desc = getGlifLayout().getDescriptionText();
+
+ assertThat(desc.toString()).isEqualTo(
+ mContext.getString(R.string.security_settings_face_enroll_education_message));
+ }
+
+ @Test
+ public void testFaceEnrollEducation_showFooterPrimaryButton() {
+ setupActivity();
+ FooterBarMixin footer = getGlifLayout().getMixin(FooterBarMixin.class);
+ FooterButton footerButton = footer.getPrimaryButton();
+
+ assertThat(footerButton.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(footerButton.getText().toString()).isEqualTo(
+ mContext.getString(R.string.security_settings_face_enroll_education_start));
+ }
+
+ @Test
+ public void testFaceEnrollEducation_showFooterSecondaryButton() {
+ setupActivity();
+ FooterBarMixin footer = getGlifLayout().getMixin(FooterBarMixin.class);
+ FooterButton footerButton = footer.getSecondaryButton();
+
+ assertThat(footerButton.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(footerButton.getText().toString()).isEqualTo(mContext.getString(
+ R.string.security_settings_face_enroll_introduction_cancel));
+ }
+
+ @Test
+ public void testFaceEnrollEducation_defaultNeverLaunchPostureGuidance() {
+ setupActivity();
+
+ assertThat(mActivity.launchPostureGuidance()).isFalse();
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_UNKNOWN);
+ }
+
+ @Test
+ public void testFaceEnrollEducation_onStartNeverRegisterPostureChangeCallback() {
+ setupActivity();
+ mActivity.onStart();
+
+ assertThat(mActivity.getPostureGuidanceIntent()).isNull();
+ assertThat(mActivity.getPostureCallback()).isNull();
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_UNKNOWN);
+ }
+
+ @Test
+ public void testFaceEnrollEducationWithPosture_onStartRegisteredPostureChangeCallback() {
+ setupActivityForPosture();
+ mActivity.onStart();
+
+ assertThat(mActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mActivity.getPostureCallback()).isNotNull();
+ }
+
+ @Test
+ public void testFaceEnrollEducationWithPosture_onFoldedUpdated_unFolded() {
+ final Configuration newConfig = new Configuration();
+ newConfig.smallestScreenWidthDp = DENSITY_XXXHIGH;
+ setupActivityForPosture();
+ mActivity.onStart();
+
+ assertThat(mActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mActivity.getPostureCallback()).isNotNull();
+
+ mActivity.onConfigurationChanged(newConfig);
+
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_OPENED);
+ }
+
+ @Test
+ public void testFaceEnrollEducationWithPosture_onFoldedUpdated_folded() {
+ final Configuration newConfig = new Configuration();
+ newConfig.smallestScreenWidthDp = DENSITY_DEFAULT;
+ setupActivityForPosture();
+ mActivity.onStart();
+
+ assertThat(mActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mActivity.getPostureCallback()).isNotNull();
+
+ mActivity.onConfigurationChanged(newConfig);
+
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_CLOSED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
new file mode 100644
index 0000000..6c04add
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package com.android.settings.biometrics.face;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.util.DisplayMetrics.DENSITY_XXXHIGH;
+
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_NEXT_LAUNCHED;
+import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_LAUNCHED_POSTURE_GUIDANCE;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_CLOSED;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_OPENED;
+import static com.android.settings.biometrics.BiometricUtils.DEVICE_POSTURE_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.os.UserHandle;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
+import com.android.settings.biometrics.BiometricUtils;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+import com.google.android.setupdesign.view.BottomScrollView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowLockPatternUtils.class,
+ ShadowUserManager.class,
+ ShadowUtils.class,
+ ShadowDevicePolicyManager.class,
+ ShadowSensorPrivacyManager.class
+})
+public class FaceEnrollIntroductionTest {
+
+ @Mock
+ private FaceManager mFaceManager;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+
+ private Context mContext;
+ private ActivityController<? extends Activity> mController;
+ private TestFaceEnrollIntroduction mActivity;
+ private FaceEnrollIntroduction mSpyActivity;
+ private FakeFeatureFactory mFakeFeatureFactory;
+ private ShadowUserManager mUserManager;
+
+ enum GateKeeperAction { CALL_SUPER, RETURN_BYTE_ARRAY, THROW_CREDENTIAL_NOT_MATCH }
+
+ public static class TestFaceEnrollIntroduction extends FaceEnrollIntroduction {
+
+ private int mRecreateCount = 0;
+
+ public int getRecreateCount() {
+ return mRecreateCount;
+ }
+
+ @Override
+ public void recreate() {
+ mRecreateCount++;
+ // Do nothing
+ }
+
+ public boolean getConfirmingCredentials() {
+ return mConfirmingCredentials;
+ }
+
+ public FaceManager mOverrideFaceManager = null;
+ @NonNull
+ public GateKeeperAction mGateKeeperAction = GateKeeperAction.CALL_SUPER;
+
+ @Nullable
+ @Override
+ public byte[] requestGatekeeperHat(long challenge) {
+ switch (mGateKeeperAction) {
+ case RETURN_BYTE_ARRAY:
+ return new byte[]{1};
+ case THROW_CREDENTIAL_NOT_MATCH:
+ throw new BiometricUtils.GatekeeperCredentialNotMatchException("test");
+ case CALL_SUPER:
+ default:
+ return super.requestGatekeeperHat(challenge);
+ }
+ }
+
+ @Nullable
+ @Override
+ protected FaceManager getFaceManager() {
+ return mOverrideFaceManager;
+ }
+
+ @Override
+ protected boolean launchPostureGuidance() {
+ return super.launchPostureGuidance();
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowUtils.setFaceManager(mFaceManager);
+ mUserManager = ShadowUserManager.getShadow();
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+
+ when(mFakeFeatureFactory.securityFeatureProvider.getLockPatternUtils(any(Context.class)))
+ .thenReturn(mLockPatternUtils);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowUtils.reset();
+ }
+
+ private void setupActivity() {
+ final Intent testIntent = new Intent();
+ // Set the challenge token so the confirm screen will not be shown
+ testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+
+ when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
+ null /* Simulate no posture intent */);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mUserManager.addUserProfile(new UserHandle(0));
+ mController = Robolectric.buildActivity(
+ TestFaceEnrollIntroduction.class, testIntent);
+ mActivity = (TestFaceEnrollIntroduction) spy(mController.get());
+ mActivity.mOverrideFaceManager = mFaceManager;
+ when(mActivity.getPostureGuidanceIntent()).thenReturn(null);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mLockPatternUtils.getActivePasswordQuality(Mockito.anyInt())).thenReturn(
+ PASSWORD_QUALITY_NUMERIC);
+
+ mController.create();
+ }
+
+ private void setupActivityForPosture() {
+ final Intent testIntent = new Intent();
+ // Set the challenge token so the confirm screen will not be shown
+ testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+ testIntent.putExtra(EXTRA_KEY_NEXT_LAUNCHED, false);
+ testIntent.putExtra(EXTRA_LAUNCHED_POSTURE_GUIDANCE, false);
+
+ when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
+ testIntent);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mUserManager.addUserProfile(new UserHandle(0));
+ mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, testIntent);
+ mSpyActivity = (FaceEnrollIntroduction) spy(mController.get());
+ when(mSpyActivity.getPostureGuidanceIntent()).thenReturn(testIntent);
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mLockPatternUtils.getActivePasswordQuality(Mockito.anyInt())).thenReturn(
+ PASSWORD_QUALITY_NUMERIC);
+
+ mController.create();
+ }
+
+ private void setupActivityWithGenerateChallenge(@NonNull Intent intent) {
+ doAnswer(invocation -> {
+ final FaceManager.GenerateChallengeCallback callback =
+ invocation.getArgument(1);
+ callback.onGenerateChallengeResult(0, 0, 1L);
+ return null;
+ }).when(mFaceManager).generateChallenge(anyInt(), any());
+ mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+ mActivity = (TestFaceEnrollIntroduction) mController.get();
+ mActivity.mOverrideFaceManager = mFaceManager;
+ }
+
+ private GlifLayout getGlifLayout(Activity activity) {
+ return activity.findViewById(R.id.setup_wizard_layout);
+ }
+
+ private void setFaceManagerToHave(int numEnrollments) {
+ List<Face> faces = new ArrayList<>();
+ for (int i = 0; i < numEnrollments; i++) {
+ faces.add(new Face("Face " + i /* name */, 1 /*faceId */, 1 /* deviceId */));
+ }
+ when(mFaceManager.getEnrolledFaces(anyInt())).thenReturn(faces);
+ }
+
+ @Test
+ public void intro_CheckCanEnroll() {
+ setFaceManagerToHave(0 /* numEnrollments */);
+ setupActivityWithGenerateChallenge(new Intent());
+ mController.create();
+ int result = mActivity.checkMaxEnrolled();
+
+ assertThat(result).isEqualTo(0);
+ }
+
+ @Test
+ public void intro_CheckMaxEnrolled() {
+ setFaceManagerToHave(1 /* numEnrollments */);
+ setupActivityWithGenerateChallenge(new Intent());
+ mController.create();
+ int result = mActivity.checkMaxEnrolled();
+
+ assertThat(result).isEqualTo(R.string.face_intro_error_max);
+ }
+
+ @Test
+ public void testOnCreate() {
+ setupActivityWithGenerateChallenge(new Intent());
+ mController.create();
+ }
+
+ @Test
+ public void testOnCreateToGenerateChallenge() {
+ setupActivityWithGenerateChallenge(
+ new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L));
+ mActivity.mGateKeeperAction = GateKeeperAction.RETURN_BYTE_ARRAY;
+ mController.create();
+ }
+
+ @Test
+ public void testGenerateChallengeFailThenRecreate() {
+ setupActivityWithGenerateChallenge(
+ new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L));
+ mActivity.mGateKeeperAction = GateKeeperAction.THROW_CREDENTIAL_NOT_MATCH;
+ mController.create();
+
+ // Make sure recreate() is called on original activity
+ assertThat(mActivity.getRecreateCount()).isEqualTo(1);
+
+ // Simulate recreate() action
+ setupActivityWithGenerateChallenge(mActivity.getIntent());
+ mController.create();
+
+ // Verify confirmLock()
+ assertThat(mActivity.getConfirmingCredentials()).isTrue();
+ ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+ ShadowActivity.IntentForResult startedActivity =
+ shadowActivity.getNextStartedActivityForResult();
+ assertWithMessage("Next activity 1").that(startedActivity).isNotNull();
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_hasHeader() {
+ setupActivity();
+ TextView headerTextView = getGlifLayout(mActivity).findViewById(R.id.suc_layout_title);
+
+ assertThat(headerTextView).isNotNull();
+ assertThat(headerTextView.getText().toString()).isNotEmpty();
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_hasDescription() {
+ setupActivity();
+ CharSequence desc = getGlifLayout(mActivity).getDescriptionText();
+
+ assertThat(desc.toString()).isEqualTo(
+ mContext.getString(R.string.security_settings_face_enroll_introduction_message));
+ }
+
+ @Test
+ public void testFaceEnrollEducation_hasBottomScrollView() {
+ setupActivity();
+ BottomScrollView scrollView = getGlifLayout(mActivity).findViewById(R.id.sud_scroll_view);
+
+ assertThat(scrollView).isNotNull();
+ assertThat(scrollView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_showFooterPrimaryButton() {
+ setupActivity();
+ FooterBarMixin footer = getGlifLayout(mActivity).getMixin(FooterBarMixin.class);
+ FooterButton footerButton = footer.getPrimaryButton();
+
+ assertThat(footerButton).isNotNull();
+ assertThat(footerButton.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(footerButton.getText().toString()).isEqualTo(
+ mContext.getString(R.string.security_settings_face_enroll_introduction_agree));
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_notShowFooterSecondaryButton() {
+ setupActivity();
+ FooterBarMixin footer = getGlifLayout(mActivity).getMixin(FooterBarMixin.class);
+ FooterButton footerButton = footer.getSecondaryButton();
+
+ assertThat(footerButton.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_defaultNeverLaunchPostureGuidance() {
+ setupActivity();
+
+ assertThat(mActivity.launchPostureGuidance()).isFalse();
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_UNKNOWN);
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_onStartNeverRegisterPostureChangeCallback() {
+ setupActivity();
+ mActivity.onStart();
+
+ assertThat(mActivity.getPostureGuidanceIntent()).isNull();
+ assertThat(mActivity.getPostureCallback()).isNull();
+ assertThat(mActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_UNKNOWN);
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_onStartRegisteredPostureChangeCallback() {
+ setupActivityForPosture();
+ mSpyActivity.onStart();
+
+ assertThat(mSpyActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mSpyActivity.getPostureCallback()).isNotNull();
+ }
+
+ @Test
+ public void testFaceEnrollIntroduction_onFoldedUpdated_unFolded() {
+ final Configuration newConfig = new Configuration();
+ newConfig.smallestScreenWidthDp = DENSITY_XXXHIGH;
+ setupActivityForPosture();
+ mSpyActivity.onStart();
+
+ assertThat(mSpyActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mSpyActivity.getPostureCallback()).isNotNull();
+
+ mSpyActivity.onConfigurationChanged(newConfig);
+
+ assertThat(mSpyActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_OPENED);
+ }
+
+ @Test
+ public void testFaceEnrollEducation_onFoldedUpdated_folded() {
+ final Configuration newConfig = new Configuration();
+ newConfig.smallestScreenWidthDp = DENSITY_DEFAULT;
+ setupActivityForPosture();
+ mSpyActivity.onStart();
+
+ assertThat(mSpyActivity.getPostureGuidanceIntent()).isNotNull();
+ assertThat(mSpyActivity.getPostureCallback()).isNotNull();
+
+ mSpyActivity.onConfigurationChanged(newConfig);
+
+ assertThat(mSpyActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_CLOSED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index b899206..ee6ae22 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -25,11 +25,11 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
index ff74d59..b6df62e 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java
@@ -81,12 +81,12 @@
@Test
public void onPreferenceChange_settingIsUpdated() {
boolean state = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED, 1) != 0;
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, 1) != 0;
assertThat(mController.isChecked()).isFalse();
assertThat(mController.onPreferenceChange(mPreference, !state)).isTrue();
boolean newState = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED, 1) != 0;
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, 1) != 0;
assertThat(newState).isEqualTo(!state);
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index fac8b58..81f4859 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -21,8 +21,8 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index f2b0acd..37b8ab6 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -40,7 +40,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -268,7 +268,7 @@
mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
null /* keys */, tile, "123", Preference.DEFAULT_ORDER);
- verifyZeroInteractions(tile);
+ verifyNoInteractions(tile);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index bccec3e..e7b59a3 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -19,14 +19,14 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
index 861b4e3..cef5928 100644
--- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
@@ -19,16 +19,15 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -133,9 +132,9 @@
mDataLimit, mDataWarning, mEnableDataLimit, mEnableDataWarning);
doReturn("some-string").when(billingCycleSettings).getString(anyInt(), anyInt());
- when(mNetworkPolicyEditor.getPolicyCycleDay(anyObject())).thenReturn(CYCLE_NONE + 1);
- when(mNetworkPolicyEditor.getPolicyLimitBytes(anyObject())).thenReturn(2000L);
- when(mNetworkPolicyEditor.getPolicyWarningBytes(anyObject())).thenReturn(1000L);
+ when(mNetworkPolicyEditor.getPolicyCycleDay(any())).thenReturn(CYCLE_NONE + 1);
+ when(mNetworkPolicyEditor.getPolicyLimitBytes(any())).thenReturn(2000L);
+ when(mNetworkPolicyEditor.getPolicyWarningBytes(any())).thenReturn(1000L);
billingCycleSettings.updatePrefs();
diff --git a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
index 70a1a38..4391425 100644
--- a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
index b9c4edc..9fb364e 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
@@ -24,7 +24,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.time.Capabilities;
@@ -99,7 +99,7 @@
mController.setChecked(true);
// Verify the TimeManager was not called.
- verifyZeroInteractions(mTimeManager);
+ verifyNoInteractions(mTimeManager);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
index 3f49b15..35e044c 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
@@ -23,8 +23,8 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java b/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
index 09d1c84..06e4107 100644
--- a/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
+++ b/tests/robotests/src/com/android/settings/enterprise/AdminGrantedPermissionsPreferenceControllerTestBase.java
@@ -18,10 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -79,7 +79,7 @@
}
}).when(mFeatureFactory.applicationFeatureProvider)
.calculateNumberOfAppsWithAdminGrantedPermissions(eq(mPermissions),
- eq(async), anyObject());
+ eq(async), any());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java
index f39b4b8..c32d2d7 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
@@ -74,7 +74,7 @@
return null;
}
}).when(mFeatureFactory.applicationFeatureProvider)
- .calculateNumberOfPolicyInstalledApps(eq(async), anyObject());
+ .calculateNumberOfPolicyInstalledApps(eq(async), any());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 90e8caf..8c65086 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -30,7 +30,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
@@ -859,7 +859,7 @@
mFragment.onRadioButtonClicked(mOptimizePreference);
mFragment.onPause();
- verifyZeroInteractions(mMetricsFeatureProvider);
+ verifyNoInteractions(mMetricsFeatureProvider);
}
@Test
@@ -870,7 +870,7 @@
mFragment.notifyBackupManager();
- verifyZeroInteractions(mBackupManager);
+ verifyNoInteractions(mBackupManager);
}
@Test
@@ -893,6 +893,6 @@
mFragment.onPause();
- verifyZeroInteractions(mBackupManager);
+ verifyNoInteractions(mBackupManager);
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index 283df7b..55ff93b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -34,7 +34,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import android.app.AppOpsManager;
import android.app.backup.BackupDataInputStream;
@@ -254,7 +254,7 @@
mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
- verifyZeroInteractions(mBackupDataInputStream);
+ verifyNoInteractions(mBackupDataInputStream);
}
@Test
@@ -292,13 +292,13 @@
@Test
public void restoreOptimizationMode_nullBytesData_skipRestore() throws Exception {
mBatteryBackupHelper.restoreOptimizationMode(new byte[0]);
- verifyZeroInteractions(mBatteryOptimizeUtils);
+ verifyNoInteractions(mBatteryOptimizeUtils);
mBatteryBackupHelper.restoreOptimizationMode("invalid data format".getBytes());
- verifyZeroInteractions(mBatteryOptimizeUtils);
+ verifyNoInteractions(mBatteryOptimizeUtils);
mBatteryBackupHelper.restoreOptimizationMode(DELIMITER.getBytes());
- verifyZeroInteractions(mBatteryOptimizeUtils);
+ verifyNoInteractions(mBatteryOptimizeUtils);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index 6389dc9..78534e1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -23,7 +23,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.Activity;
@@ -267,7 +267,7 @@
mController.updateHeaderByBatteryTips(null, mBatteryInfo);
- verifyZeroInteractions(mBatteryUsageProgressBarPref);
+ verifyNoInteractions(mBatteryUsageProgressBarPref);
}
@Test
@@ -277,7 +277,7 @@
mController.updateHeaderByBatteryTips(lowBatteryTip, null);
- verifyZeroInteractions(mBatteryUsageProgressBarPref);
+ verifyNoInteractions(mBatteryUsageProgressBarPref);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
index b223d0b..f92c322 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
@@ -25,16 +25,16 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
@@ -183,8 +183,8 @@
mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED);
TimeUnit.SECONDS.sleep(1);
- verifyZeroInteractions(mMockBackend);
- verifyZeroInteractions(mMockBatteryUtils);
+ verifyNoInteractions(mMockBackend);
+ verifyNoInteractions(mMockBatteryUtils);
}
@Test
@@ -247,7 +247,7 @@
AppOpsManager.MODE_ALLOWED, /* allowListed */ false,
/* isSystemOrDefaultApp */ false);
- verifyZeroInteractions(mMockBatteryUtils);
+ verifyNoInteractions(mMockBatteryUtils);
final InOrder inOrder = inOrder(mMockBackend);
inOrder.verify(mMockBackend).refreshList();
@@ -261,7 +261,7 @@
AppOpsManager.MODE_ALLOWED, /* allowListed */ true,
/* isSystemOrDefaultApp */ true);
- verifyZeroInteractions(mMockBatteryUtils);
+ verifyNoInteractions(mMockBatteryUtils);
final InOrder inOrder = inOrder(mMockBackend);
inOrder.verify(mMockBackend).refreshList();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
index da397fd..5815bae 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryAppListPreferenceControllerTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 683f0fd..a6db9ff 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -19,7 +19,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
diff --git a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
index bafc021..9aa79ff 100644
--- a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
@@ -16,16 +16,15 @@
package com.android.settings.network;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import android.app.admin.DevicePolicyManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -162,7 +161,7 @@
mController.onResume();
- verifyZeroInteractions(mPreference);
+ verifyNoInteractions(mPreference);
Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeAutomaticRulesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeAutomaticRulesPreferenceControllerTest.java
index 1660955..3791c23 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeAutomaticRulesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeAutomaticRulesPreferenceControllerTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
@@ -42,10 +43,10 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.internal.util.reflection.FieldSetter;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.util.ReflectionHelpers;
+import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@@ -192,16 +193,26 @@
rule.setEnabled(false);
rMap.put(testId, rule);
mockGetAutomaticZenRules(NUM_RULES, rMap);
- FieldSetter.setField(mZenRulePreference, ZenRulePreference.class.getDeclaredField("mId"), testId);
+ setZenRulePreferenceField("mId", testId);
mController.updateState(mockPref);
verify(mZenRulePreference, times(1)).updatePreference(any());
verify(mockPref, never()).removeAll();
assertEquals(NUM_RULES, mController.mZenRulePreferences.size());
}
+ private void setZenRulePreferenceField(String name, Object value) {
+ try {
+ Field field = ZenRulePreference.class.getDeclaredField("mId");
+ field.setAccessible(true);
+ field.set(mZenRulePreference, value);
+ } catch (ReflectiveOperationException e) {
+ fail("Unable to set mZenRulePreference field: " + name);
+ }
+ }
+
private void mockGetAutomaticZenRules(int numRules, Map<String, AutomaticZenRule> rules) {
Map.Entry<String, AutomaticZenRule>[] arr = new Map.Entry[numRules];
rules.entrySet().toArray(arr);
when(mBackend.getAutomaticZenRules()).thenReturn(arr);
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModePriorityConversationsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModePriorityConversationsPreferenceControllerTest.java
index 6bf0538..d5834f9 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModePriorityConversationsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModePriorityConversationsPreferenceControllerTest.java
@@ -26,7 +26,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -146,4 +146,4 @@
}
return null;
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceControllerTest.java
index 99fa8e6..c431c53 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceControllerTest.java
@@ -30,8 +30,8 @@
import static com.android.settings.notification.zen.ZenPrioritySendersHelper.KEY_NONE;
import static com.android.settings.notification.zen.ZenPrioritySendersHelper.UNKNOWN;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenRuleStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenRuleStarredContactsPreferenceControllerTest.java
index 2f7dfe7..01f3dfa 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenRuleStarredContactsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenRuleStarredContactsPreferenceControllerTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java
index 96036d5..b5d07cc 100644
--- a/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java
@@ -21,8 +21,8 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -72,7 +72,7 @@
mPreference = new Preference(mContext);
when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
- when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
+ when(mPrintManager.getPrintJob(any())).thenReturn(mPrintJob);
when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
mController = new PrintJobMessagePreferenceController(mContext, PREF_KEY);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
@@ -93,7 +93,7 @@
@Test
public void updateUi_visiblePreference() {
- when(mPrintJobInfo.getStatus(anyObject())).thenReturn("TestPrint");
+ when(mPrintJobInfo.getStatus(any())).thenReturn("TestPrint");
mLifecycle.handleLifecycleEvent(ON_START);
assertThat(mPreference.isVisible()).isTrue();
@@ -103,7 +103,7 @@
@Test
public void updateUi_invisiblePreference() {
- when(mPrintJobInfo.getStatus(anyObject())).thenReturn(null);
+ when(mPrintJobInfo.getStatus(any())).thenReturn(null);
mLifecycle.handleLifecycleEvent(ON_START);
assertThat(mPreference.isVisible()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java
index 09c5bf3..da4d58c 100644
--- a/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java
@@ -21,8 +21,8 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -75,7 +75,7 @@
mTestLabel = "PrintTest";
when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
- when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
+ when(mPrintManager.getPrintJob(any())).thenReturn(mPrintJob);
when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
mController = new PrintJobPreferenceController(mContext, PREF_KEY);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
diff --git a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
index c646a93..2a7bd29 100644
--- a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
+++ b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
@@ -21,7 +21,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
@@ -91,7 +91,7 @@
SearchMenuController.init(mHost);
mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
- verifyZeroInteractions(mMenu);
+ verifyNoInteractions(mMenu);
}
@Test
@@ -100,7 +100,7 @@
SearchMenuController.init(mHost);
mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
- verifyZeroInteractions(mMenu);
+ verifyNoInteractions(mMenu);
}
@Test
@@ -112,6 +112,6 @@
mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
- verifyZeroInteractions(mMenu);
+ verifyNoInteractions(mMenu);
}
}
diff --git a/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java b/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
index 62c7bd8..e297b78 100644
--- a/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/widget/HighlightablePreferenceGroupAdapterTest.java
@@ -26,7 +26,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -111,7 +111,7 @@
ReflectionHelpers.setField(mAdapter, "mHighlightRequested", false);
mAdapter.requestHighlight(mRoot, null /* recyclerView */, mock(AppBarLayout.class));
- verifyZeroInteractions(mRoot);
+ verifyNoInteractions(mRoot);
}
@Test
@@ -125,7 +125,7 @@
when(mFragment.getArguments()).thenReturn(null);
when(mFragment.getPreferenceScreen()).thenReturn(screen);
HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment);
- verifyZeroInteractions(screen);
+ verifyNoInteractions(screen);
}
@Test
@@ -150,7 +150,7 @@
HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment);
verify(mFragment).getInitialExpandedChildCount();
- verifyZeroInteractions(screen);
+ verifyNoInteractions(screen);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index e4d3982..e5b13c4 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -195,7 +195,7 @@
}
private List<WifiEntry> createWifiEntryList() {
- List<WifiEntry> wifiEntryList = spy(new ArrayList<>());
+ List<WifiEntry> wifiEntryList = new ArrayList<>();
final WifiEntry wifiEntry1 = mock(WifiEntry.class);
when(wifiEntry1.getSsid()).thenReturn("Test AP 1");
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
index 8478a54..610e520 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
@@ -21,9 +21,9 @@
import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
.DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -75,7 +75,7 @@
mDisclaimerItem = spy(new MockDisclaimerItem(mContext, 0 /* subId */));
mDisclaimerItemList.add(mDisclaimerItem);
- when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+ when(mLayoutInflater.inflate(anyInt(), any(), anyBoolean())).thenReturn(mView);
when(mViewGroup.getContext()).thenReturn(mContext);
when(mViewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(
mLayoutInflater);
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
index 985edda..c8e4cce 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/EmergencyCallLimitationDisclaimerTest.java
@@ -18,8 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java b/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
index 3fe9678..148095a 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/LocationPolicyDisclaimerTest.java
@@ -18,8 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
index 207a231..0ece537 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
@@ -16,10 +16,9 @@
package com.android.settings.wifi.calling;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -95,7 +94,7 @@
doReturn(mActivity).when(mFragment).getActivity();
- when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+ when(mLayoutInflater.inflate(anyInt(), any(), anyBoolean())).thenReturn(mView);
when(mView.findViewById(R.id.agree_button)).thenReturn(mAgreeButton);
when(mView.findViewById(R.id.disagree_button)).thenReturn(mDisagreeButton);
when(mView.findViewById(R.id.disclaimer_item_list)).thenReturn(mRecyclerView);
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index e2c5ca3..1faa611 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -16,17 +16,17 @@
package com.android.settings.wifi.calling;
-import static junit.framework.Assert.assertEquals;
-
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -44,7 +44,6 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsMmTelManager;
import android.view.View;
-import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
index 274ac16..c86a023 100644
--- a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
@@ -17,15 +17,16 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -93,7 +94,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
-import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -1255,7 +1255,7 @@
mMockWifiConfig.creatorUid = doUid;
ComponentName doComponent = new ComponentName(doPackage, "some.Class");
try {
- when(mMockPackageManager.getPackageUidAsUser(Matchers.anyString(), Matchers.anyInt()))
+ when(mMockPackageManager.getPackageUidAsUser(anyString(), anyInt()))
.thenReturn(doUid);
} catch (PackageManager.NameNotFoundException e) {
//do nothing