Merge changes from topic "unicorn-1" into sc-dev
* changes: Update strings for parental consent flow in setup wizard. Add plumbing and placeholder screens for parental consent flow.
This commit is contained in:
@@ -1803,6 +1803,10 @@
|
|||||||
android:theme="@style/GlifV3Theme.Light"
|
android:theme="@style/GlifV3Theme.Light"
|
||||||
android:exported="false"/>
|
android:exported="false"/>
|
||||||
|
|
||||||
|
<activity android:name=".biometrics.face.FaceEnrollParentalConsent"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="portrait"/>
|
||||||
|
|
||||||
<activity android:name=".biometrics.face.FaceEnrollIntroduction"
|
<activity android:name=".biometrics.face.FaceEnrollIntroduction"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:screenOrientation="portrait"/>
|
android:screenOrientation="portrait"/>
|
||||||
@@ -1837,6 +1841,7 @@
|
|||||||
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFindSensor" android:exported="false"/>
|
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFindSensor" android:exported="false"/>
|
||||||
<activity android:name=".biometrics.fingerprint.FingerprintEnrollEnrolling" android:exported="false"/>
|
<activity android:name=".biometrics.fingerprint.FingerprintEnrollEnrolling" android:exported="false"/>
|
||||||
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFinish" android:exported="false"/>
|
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFinish" android:exported="false"/>
|
||||||
|
<activity android:name=".biometrics.fingerprint.FingerprintEnrollParentalConsent" android:exported="false"/>
|
||||||
<activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroduction"
|
<activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroduction"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/GlifTheme.Light">
|
android:theme="@style/GlifTheme.Light">
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (C) 2019 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
|
|
||||||
-->
|
|
||||||
|
|
||||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt">
|
|
||||||
<aapt:attr name="android:drawable">
|
|
||||||
<vector android:height="24dp" android:width="24dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:tint="?android:attr/colorControlNormal">
|
|
||||||
<group android:name="_R_G">
|
|
||||||
<group android:name="_R_G_L_0_G">
|
|
||||||
<path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#000000"
|
|
||||||
android:fillAlpha="1" android:fillType="nonZero"
|
|
||||||
android:pathData=" M12 2 C12,2 3.82,5.64 3.82,5.64 C3.82,5.64 3.82,11.09 3.82,11.09 C3.82,16.14 7.31,20.85 12,22 C16.69,20.85 20.18,16.14 20.18,11.09 C20.18,11.09 20.18,5.64 20.18,5.64 C20.18,5.64 12,2 12,2c M18.18 11.09 C18.18,12.64 17.77,14.14 17.08,15.47 C15.77,14.5 13.4,14 12,14 C10.6,14 8.23,14.5 6.92,15.47 C6.23,14.14 5.82,12.64 5.82,11.09 C5.82,11.09 5.82,6.94 5.82,6.94 C5.82,6.94 12,4.19 12,4.19 C12,4.19 18.18,6.94 18.18,6.94 C18.18,6.94 18.18,11.09 18.18,11.09c "/>
|
|
||||||
<path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="#000000"
|
|
||||||
android:fillAlpha="1" android:fillType="nonZero"
|
|
||||||
android:pathData=" M12 7.5 C13.66,7.5 15,8.84 15,10.5 C15,12.16 13.66,13.5 12,13.5 C10.34,13.5 9,12.16 9,10.5 C9,8.84 10.34,7.5 12,7.5c "/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
<group android:name="time_group"/>
|
|
||||||
</vector>
|
|
||||||
</aapt:attr>
|
|
||||||
<target android:name="time_group">
|
|
||||||
<aapt:attr name="android:animation">
|
|
||||||
<set android:ordering="together">
|
|
||||||
<objectAnimator android:propertyName="translateX" android:duration="2000"
|
|
||||||
android:startOffset="0" android:valueFrom="0" android:valueTo="1"
|
|
||||||
android:valueType="floatType"/>
|
|
||||||
</set>
|
|
||||||
</aapt:attr>
|
|
||||||
</target>
|
|
||||||
</animated-vector>
|
|
@@ -30,7 +30,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="?attr/sudMarginStart"
|
||||||
|
android:layout_marginEnd="?attr/sudMarginEnd">
|
||||||
|
|
||||||
<com.google.android.setupdesign.view.RichTextView
|
<com.google.android.setupdesign.view.RichTextView
|
||||||
android:id="@+id/error_text"
|
android:id="@+id/error_text"
|
||||||
@@ -60,6 +62,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Keep in mind -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -78,19 +81,15 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/ic_face_enroll_introduction_glasses"/>
|
android:background="@drawable/ic_face_enroll_introduction_glasses"/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="16dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/info_message_glasses"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_info_glasses"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"/>
|
||||||
android:lineSpacingExtra="4sp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -104,56 +103,28 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/ic_face_enroll_introduction_visibility"/>
|
android:background="@drawable/ic_face_enroll_introduction_visibility"/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="16dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/info_message_looking"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_info_looking"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"/>
|
||||||
android:lineSpacingExtra="4sp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingTop="24dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/icon_security"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/ic_face_enroll_introduction_shield"/>
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/security_settings_face_enroll_introduction_info_security"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:lineSpacingExtra="4sp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="40dp"/>
|
android:layout_height="40dp"/>
|
||||||
|
|
||||||
|
<!-- How it works -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_how_title"
|
android:text="@string/security_settings_face_enroll_introduction_how_title"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:textSize="20sp"/>
|
android:textSize="20sp"/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
@@ -161,21 +132,21 @@
|
|||||||
android:layout_height="24dp"/>
|
android:layout_height="24dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/how_message"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_how_message"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="14sp"
|
android:textSize="16sp"/>
|
||||||
android:lineSpacingExtra="2sp"/>
|
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="24dp"/>
|
android:layout_height="24dp"/>
|
||||||
|
|
||||||
|
<!-- You're in control -->
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/title_in_control"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_control_title"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="20sp"/>
|
android:textSize="20sp"/>
|
||||||
|
|
||||||
@@ -184,12 +155,11 @@
|
|||||||
android:layout_height="24dp"/>
|
android:layout_height="24dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/message_in_control"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_face_enroll_introduction_control_message"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textSize="14sp"
|
android:textSize="16sp"/>
|
||||||
android:lineSpacingExtra="2sp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@@ -30,7 +30,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="?attr/sudMarginStart"
|
||||||
|
android:layout_marginEnd="?attr/sudMarginEnd">
|
||||||
|
|
||||||
<com.google.android.setupdesign.view.RichTextView
|
<com.google.android.setupdesign.view.RichTextView
|
||||||
android:id="@+id/error_text"
|
android:id="@+id/error_text"
|
||||||
@@ -52,26 +54,25 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Contains the extra information text at the bottom -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- How it works -->
|
<!-- How it works -->
|
||||||
<com.google.android.setupdesign.view.RichTextView
|
<TextView
|
||||||
style="@style/SudDescription.Glif"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_title_2"
|
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_title_2"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="20sp"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="12dp">
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon_fingerprint"
|
android:id="@+id/icon_fingerprint"
|
||||||
@@ -80,86 +81,92 @@
|
|||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/ic_fingerprint_24dp"/>
|
android:src="@drawable/ic_fingerprint_24dp"/>
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="24dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/footer_message_2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_message_2"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textSize="16sp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="12dp">
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon_locked"
|
android:id="@+id/icon_fingerprint"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/ic_device_locked_24dp"/>
|
android:src="@drawable/ic_device_locked_24dp"/>
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="24dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/footer_message_3"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_message_3"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textSize="16sp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="24dp"/>
|
||||||
|
|
||||||
<!-- You're in control -->
|
<!-- You're in control -->
|
||||||
<com.google.android.setupdesign.view.RichTextView
|
<TextView
|
||||||
style="@style/SudDescription.Glif"
|
android:id="@+id/footer_title_1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAlignment="viewStart"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:paddingTop="12dp"
|
android:textSize="20sp"/>
|
||||||
android:text="@string/security_settings_fingerprint_enroll_introduction_footer_title_1"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="12dp">
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon_delete"
|
android:id="@+id/icon_fingerprint"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/ic_trash_can"/>
|
android:src="@drawable/ic_trash_can"/>
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="24dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/footer_message_4"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_message_4"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textSize="16sp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="24dp"/>
|
||||||
|
|
||||||
<!-- Keep in mind -->
|
<!-- Keep in mind -->
|
||||||
<com.google.android.setupdesign.view.RichTextView
|
<TextView
|
||||||
style="@style/SudDescription.Glif"
|
android:id="@+id/footer_title_2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAlignment="viewStart"
|
android:text="@string/security_settings_face_enroll_introduction_info_title"
|
||||||
android:paddingTop="12dp"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:text="@string/security_settings_fingerprint_enroll_introduction_footer_title_2"
|
android:textSize="20sp"/>
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="12dp">
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon_info"
|
android:id="@+id/icon_info"
|
||||||
@@ -168,20 +175,21 @@
|
|||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/ic_info_outline_24dp"/>
|
android:src="@drawable/ic_info_outline_24dp"/>
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="24dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/footer_message_5"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_message_5"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textSize="16sp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="12dp">
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon_link"
|
android:id="@+id/icon_link"
|
||||||
@@ -190,13 +198,16 @@
|
|||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/ic_link_24dp"/>
|
android:src="@drawable/ic_link_24dp"/>
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="24dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_message_learn_more"
|
android:text="@string/security_settings_fingerprint_v2_enroll_introduction_message_learn_more"
|
||||||
android:textColor="?android:attr/textColorPrimary"/>
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@@ -777,10 +777,14 @@
|
|||||||
<string name="security_settings_face_enroll_introduction_more">More</string>
|
<string name="security_settings_face_enroll_introduction_more">More</string>
|
||||||
<!-- Introduction title shown in face enrollment to introduce the face unlock feature [CHAR LIMIT=40] -->
|
<!-- Introduction title shown in face enrollment to introduce the face unlock feature [CHAR LIMIT=40] -->
|
||||||
<string name="security_settings_face_enroll_introduction_title">Unlock with your face</string>
|
<string name="security_settings_face_enroll_introduction_title">Unlock with your face</string>
|
||||||
|
<!-- Introduction title shown in face enrollment when when asking for parental consent for the face unlock feature [CHAR LIMIT=40] -->
|
||||||
|
<string name="security_settings_face_enroll_consent_introduction_title">Allow face unlock</string>
|
||||||
<!-- Introduction title shown in face enrollment to introduce the face unlock feature, when face unlock is disabled by device admin [CHAR LIMIT=60] -->
|
<!-- Introduction title shown in face enrollment to introduce the face unlock feature, when face unlock is disabled by device admin [CHAR LIMIT=60] -->
|
||||||
<string name="security_settings_face_enroll_introduction_title_unlock_disabled">Use your face to authenticate</string>
|
<string name="security_settings_face_enroll_introduction_title_unlock_disabled">Use your face to authenticate</string>
|
||||||
<!-- Introduction detail message shown in face enrollment dialog [CHAR LIMIT=NONE]-->
|
<!-- Introduction detail message shown in face enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_face_enroll_introduction_message">Use your face to unlock your phone, authorize purchases, or sign in to apps.</string>
|
<string name="security_settings_face_enroll_introduction_message">Use your face to unlock your phone, authorize purchases, or sign in to apps.</string>
|
||||||
|
<!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="security_settings_face_enroll_introduction_consent_message">Allow your child to use their face to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
|
||||||
<!-- Introduction detail message shown in face enrollment dialog, when face unlock is disabled by device admin [CHAR LIMIT=NONE] -->
|
<!-- Introduction detail message shown in face enrollment dialog, when face unlock is disabled by device admin [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_message_unlock_disabled">Use your face to unlock your phone or approve purchases.\n\nNote: You can\u2019t use your face to unlock this device. For more information, contact your organization\u2019s admin.</string>
|
<string name="security_settings_face_enroll_introduction_message_unlock_disabled">Use your face to unlock your phone or approve purchases.\n\nNote: You can\u2019t use your face to unlock this device. For more information, contact your organization\u2019s admin.</string>
|
||||||
<!-- Introduction detail message shown in face enrollment screen in setup wizard. [CHAR LIMIT=NONE] -->
|
<!-- Introduction detail message shown in face enrollment screen in setup wizard. [CHAR LIMIT=NONE] -->
|
||||||
@@ -789,18 +793,26 @@
|
|||||||
<string name="security_settings_face_enroll_introduction_info_title"></string>
|
<string name="security_settings_face_enroll_introduction_info_title"></string>
|
||||||
<!-- Message on the face enrollment introduction page that provides information about glasses. [CHAR LIMIT=NONE] -->
|
<!-- Message on the face enrollment introduction page that provides information about glasses. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_info_glasses"></string>
|
<string name="security_settings_face_enroll_introduction_info_glasses"></string>
|
||||||
|
<!-- Message on the face enrollment introduction page that provides information about glasses when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_face_enroll_introduction_info_consent_glasses"></string>
|
||||||
<!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock. [CHAR LIMIT=NONE] -->
|
<!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_info_looking"></string>
|
<string name="security_settings_face_enroll_introduction_info_looking"></string>
|
||||||
<!-- Message on the face enrollment introduction page that provides information about the security of face unlock. [CHAR LIMIT=NONE] -->
|
<!-- Message on the face enrollment introduction page that provides information about what could cause the phone to unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_info_security"></string>
|
<string name="security_settings_face_enroll_introduction_info_consent_looking"></string>
|
||||||
<!-- Title of a section on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=40] -->
|
<!-- Title of a section on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=40] -->
|
||||||
<string name="security_settings_face_enroll_introduction_how_title"></string>
|
<string name="security_settings_face_enroll_introduction_how_title"></string>
|
||||||
<!-- Message on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=NONE] -->
|
<!-- Message on the face enrollment introduction page that explains how face unlock works. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_how_message"></string>
|
<string name="security_settings_face_enroll_introduction_how_message"></string>
|
||||||
|
<!-- Message on the face enrollment introduction page that explains how Face Unlock works when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_face_enroll_introduction_how_consent_message"></string>
|
||||||
<!-- Title of a section on the face enrollment introduction page that explains privacy controls for face unlock. [CHAR LIMIT=NONE] -->
|
<!-- Title of a section on the face enrollment introduction page that explains privacy controls for face unlock. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_control_title"></string>
|
<string name="security_settings_face_enroll_introduction_control_title"></string>
|
||||||
|
<!-- Title of a section on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_face_enroll_introduction_control_consent_title"></string>
|
||||||
<!-- Message on the face enrollment introduction page that explains privacy controls for face unlock [CHAR LIMIT=NONE] -->
|
<!-- Message on the face enrollment introduction page that explains privacy controls for face unlock [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_enroll_introduction_control_message"></string>
|
<string name="security_settings_face_enroll_introduction_control_message"></string>
|
||||||
|
<!-- Message on the face enrollment introduction page that explains privacy controls for face unlock when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_face_enroll_introduction_control_consent_message"></string>
|
||||||
<!-- Title shown in face enrollment dialog [CHAR LIMIT=40] -->
|
<!-- Title shown in face enrollment dialog [CHAR LIMIT=40] -->
|
||||||
<string name="security_settings_face_enroll_repeat_title">Center your face in the circle</string>
|
<string name="security_settings_face_enroll_repeat_title">Center your face in the circle</string>
|
||||||
<!-- Button text to skip enrollment of face [CHAR LIMIT=40] -->
|
<!-- Button text to skip enrollment of face [CHAR LIMIT=40] -->
|
||||||
@@ -890,13 +902,19 @@
|
|||||||
<string name="security_settings_fingerprint_preference_summary_none"></string>
|
<string name="security_settings_fingerprint_preference_summary_none"></string>
|
||||||
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature [CHAR LIMIT=29] -->
|
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature [CHAR LIMIT=29] -->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_title">Set up your fingerprint</string>
|
<string name="security_settings_fingerprint_enroll_introduction_title">Set up your fingerprint</string>
|
||||||
|
<!-- Introduction title shown in fingerprint enrollment when asking for parental consent for fingerprint unlock [CHAR LIMIT=29] -->
|
||||||
|
<string name="security_settings_fingerprint_enroll_consent_introduction_title">Allow fingerprint unlock</string>
|
||||||
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature, when fingerprint unlock is disabled by device admin [CHAR LIMIT=40] -->
|
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature, when fingerprint unlock is disabled by device admin [CHAR LIMIT=40] -->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled">Use your fingerprint</string>
|
<string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled">Use your fingerprint</string>
|
||||||
<!-- Introduction detail message shown in fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
<!-- Introduction detail message shown in fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_message">Just touch the fingerprint sensor to unlock your phone, authorize purchases, or sign in to apps. Be careful whose fingerprints you add. Even one added print can do any of these things.</string>
|
<string name="security_settings_fingerprint_enroll_introduction_message">Use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.</string>
|
||||||
|
<!-- Introduction detail message shown in fingerprint enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="security_settings_fingerprint_enroll_introduction_consent_message">Allow your child to use their fingerprint to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
|
||||||
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_footer_title_1">You\u2019re in control</string>
|
<string name="security_settings_fingerprint_enroll_introduction_footer_title_1">You\u2019re in control</string>
|
||||||
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="security_settings_fingerprint_enroll_introduction_footer_title_consent_1">You and your child are in control</string>
|
||||||
|
<!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_footer_title_2">Keep in mind</string>
|
<string name="security_settings_fingerprint_enroll_introduction_footer_title_2">Keep in mind</string>
|
||||||
<!-- Introduction detail message shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
<!-- Introduction detail message shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_footer_message_1">The data recorded by Fingerprint is stored securely and never leaves your phone. You can delete your data anytime in Settings.</string>
|
<string name="security_settings_fingerprint_enroll_introduction_footer_message_1">The data recorded by Fingerprint is stored securely and never leaves your phone. You can delete your data anytime in Settings.</string>
|
||||||
@@ -935,13 +953,21 @@
|
|||||||
<!-- Introduction subtitle message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
<!-- Introduction subtitle message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_title_2">How it works</string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_title_2">How it works</string>
|
||||||
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_2">Fingerprint Unlock creates a unique model of your fingerprint to recognize you during authentication. To create this fingerprint model during setup, you will take images of your fingerprint from different positions.</string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_2">Fingerprint Unlock creates a unique model of your fingerprint to verify it\u2019s you. To create this fingerprint model during setup, you will take images of your fingerprint from different positions.</string>
|
||||||
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_2">Fingerprint Unlock creates a unique model of your child\u2019s fingerprint to verify it\u2019s them. To create this fingerprint model during setup, they will take images of their fingerprint from different positions.</string>
|
||||||
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3">The phone will also use images from your interactions with Fingerprint Unlock to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your phone and never leaves the phone. All processing occurs securely on your phone.</string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_3">When you use Pixel Imprint, images are used to update your fingerprint model. Images used to create your fingerprint model are never stored, but the fingerprint model is stored securely on your phone and never leaves the phone. All processing occurs securely on your phone.</string>
|
||||||
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3">When they use Pixel Imprint, images are used to update their fingerprint model. Images used to create your child\u2019s fingerprint model are never stored, but the fingerprint model is stored securely on the phone and never leaves the phone. All processing occurs securely on the phone.</string>
|
||||||
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4">You can delete your fingerprint model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint models are stored on the phone until you delete them.</string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_4">You can delete your fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until you delete them.</string>
|
||||||
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4">You and your child can delete their fingerprint images and model, or turn off Fingerprint Unlock at any time in Settings. Fingerprint images and models are stored on the phone until they\u2019re deleted.</string>
|
||||||
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard. [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5">Your phone can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_5">Your phone can be unlocked when you don\u2019t intend to, like if someone holds it up to your finger.</string>
|
||||||
|
<!-- Introduction description message shown in fingerprint enrollment introduction screen in setup wizard when asking for parental consent. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5">Your child\u2019s phone can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger.</string>
|
||||||
<!-- Introduction detail message shown in fingerprint enrollment introduction to learn more about fingerprint [CHAR LIMIT=NONE]-->
|
<!-- Introduction detail message shown in fingerprint enrollment introduction to learn more about fingerprint [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_v2_enroll_introduction_message_learn_more"></string>
|
<string name="security_settings_fingerprint_v2_enroll_introduction_message_learn_more"></string>
|
||||||
|
|
||||||
@@ -961,7 +987,7 @@
|
|||||||
<string name="security_settings_fingerprint_v2_enroll_error_max_attempts">You\u2019ve reached the maximum number of attempts</string>
|
<string name="security_settings_fingerprint_v2_enroll_error_max_attempts">You\u2019ve reached the maximum number of attempts</string>
|
||||||
|
|
||||||
<!-- Message shown in fingerprint security settings home screen. [CHAR LIMIT=NONE]-->
|
<!-- Message shown in fingerprint security settings home screen. [CHAR LIMIT=NONE]-->
|
||||||
<string name="security_settings_fingerprint_v2_home_screen">Use your fingerprint to unlock your phone or for authentication, like when you sign in to apps or approve a purchase\n\n<annotation id="url">Learn more</annotation></string>
|
<string name="security_settings_fingerprint_v2_home_screen">Use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\n<annotation id="url">Learn more</annotation></string>
|
||||||
|
|
||||||
<!-- Biometric settings --><skip />
|
<!-- Biometric settings --><skip />
|
||||||
<!-- Title shown for menu item that launches biometric settings. [CHAR LIMIT=66] -->
|
<!-- Title shown for menu item that launches biometric settings. [CHAR LIMIT=66] -->
|
||||||
|
@@ -19,6 +19,9 @@ package com.android.settings.biometrics;
|
|||||||
import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
|
import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
|
||||||
import static android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED;
|
import static android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED;
|
||||||
|
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_DENIED;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_GRANTED;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
@@ -64,6 +67,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
|
|
||||||
private static final int REQUEST_CHOOSE_LOCK = 1;
|
private static final int REQUEST_CHOOSE_LOCK = 1;
|
||||||
private static final int REQUEST_CONFIRM_LOCK = 2;
|
private static final int REQUEST_CONFIRM_LOCK = 2;
|
||||||
|
// prompt for parental consent options
|
||||||
|
private static final int REQUEST_CHOOSE_OPTIONS = 3;
|
||||||
|
|
||||||
public static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
|
public static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
|
||||||
|
|
||||||
@@ -71,8 +76,12 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
// this only applies to fingerprint.
|
// this only applies to fingerprint.
|
||||||
public static final String EXTRA_SKIP_INTRO = "skip_intro";
|
public static final String EXTRA_SKIP_INTRO = "skip_intro";
|
||||||
|
|
||||||
|
// TODO: temporary while waiting for team to add real flag
|
||||||
|
public static final String EXTRA_TEMP_REQUIRE_PARENTAL_CONSENT = "require_consent";
|
||||||
|
|
||||||
private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
|
private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
|
||||||
private static final String SAVED_STATE_ENROLL_ACTION_LOGGED = "enroll_action_logged";
|
private static final String SAVED_STATE_ENROLL_ACTION_LOGGED = "enroll_action_logged";
|
||||||
|
private static final String SAVED_STATE_PARENTAL_OPTIONS = "enroll_preferences";
|
||||||
private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle";
|
private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle";
|
||||||
|
|
||||||
public static final class InternalActivity extends BiometricEnrollActivity {}
|
public static final class InternalActivity extends BiometricEnrollActivity {}
|
||||||
@@ -80,9 +89,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
private int mUserId = UserHandle.myUserId();
|
private int mUserId = UserHandle.myUserId();
|
||||||
private boolean mConfirmingCredentials;
|
private boolean mConfirmingCredentials;
|
||||||
private boolean mIsEnrollActionLogged;
|
private boolean mIsEnrollActionLogged;
|
||||||
private boolean mIsFaceEnrollable;
|
private boolean mHasFeatureFace = false;
|
||||||
private boolean mIsFingerprintEnrollable;
|
private boolean mHasFeatureFingerprint = false;
|
||||||
|
private boolean mIsFaceEnrollable = false;
|
||||||
|
private boolean mIsFingerprintEnrollable = false;
|
||||||
|
private boolean mParentalOptionsRequired = false;
|
||||||
|
private Bundle mParentalOptions;
|
||||||
@Nullable private Long mGkPwHandle;
|
@Nullable private Long mGkPwHandle;
|
||||||
|
@Nullable private ParentalConsentHelper mParentalConsentHelper;
|
||||||
@Nullable private MultiBiometricEnrollHelper mMultiBiometricEnrollHelper;
|
@Nullable private MultiBiometricEnrollHelper mMultiBiometricEnrollHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,6 +115,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
SAVED_STATE_CONFIRMING_CREDENTIALS, false);
|
SAVED_STATE_CONFIRMING_CREDENTIALS, false);
|
||||||
mIsEnrollActionLogged = savedInstanceState.getBoolean(
|
mIsEnrollActionLogged = savedInstanceState.getBoolean(
|
||||||
SAVED_STATE_ENROLL_ACTION_LOGGED, false);
|
SAVED_STATE_ENROLL_ACTION_LOGGED, false);
|
||||||
|
mParentalOptions = savedInstanceState.getBundle(SAVED_STATE_PARENTAL_OPTIONS);
|
||||||
if (savedInstanceState.containsKey(SAVED_STATE_GK_PW_HANDLE)) {
|
if (savedInstanceState.containsKey(SAVED_STATE_GK_PW_HANDLE)) {
|
||||||
mGkPwHandle = savedInstanceState.getLong(SAVED_STATE_GK_PW_HANDLE);
|
mGkPwHandle = savedInstanceState.getLong(SAVED_STATE_GK_PW_HANDLE);
|
||||||
}
|
}
|
||||||
@@ -141,60 +156,109 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
SetupWizardUtils.getThemeString(intent));
|
SetupWizardUtils.getThemeString(intent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
|
final PackageManager pm = getApplicationContext().getPackageManager();
|
||||||
final int authenticators = intent.getIntExtra(
|
mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||||
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
|
mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||||
|
|
||||||
|
// determine what can be enrolled
|
||||||
|
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||||
|
if (mHasFeatureFace) {
|
||||||
|
final FaceManager faceManager = getSystemService(FaceManager.class);
|
||||||
|
final List<FaceSensorPropertiesInternal> faceProperties =
|
||||||
|
faceManager.getSensorPropertiesInternal();
|
||||||
|
if (!faceProperties.isEmpty()) {
|
||||||
|
final int maxEnrolls =
|
||||||
|
isSetupWizard ? 1 : faceProperties.get(0).maxEnrollmentsPerUser;
|
||||||
|
mIsFaceEnrollable =
|
||||||
|
faceManager.getEnrolledFaces(mUserId).size() < maxEnrolls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mHasFeatureFingerprint) {
|
||||||
|
final FingerprintManager fpManager = getSystemService(FingerprintManager.class);
|
||||||
|
final List<FingerprintSensorPropertiesInternal> fpProperties =
|
||||||
|
fpManager.getSensorPropertiesInternal();
|
||||||
|
if (!fpProperties.isEmpty()) {
|
||||||
|
final int maxEnrolls =
|
||||||
|
isSetupWizard ? 1 : fpProperties.get(0).maxEnrollmentsPerUser;
|
||||||
|
mIsFingerprintEnrollable =
|
||||||
|
fpManager.getEnrolledFingerprints(mUserId).size() < maxEnrolls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/188847063): replace with real flag when ready
|
||||||
|
mParentalOptionsRequired = intent.getBooleanExtra(
|
||||||
|
BiometricEnrollActivity.EXTRA_TEMP_REQUIRE_PARENTAL_CONSENT, false);
|
||||||
|
|
||||||
|
if (mParentalOptionsRequired && mParentalOptions == null) {
|
||||||
|
mParentalConsentHelper = new ParentalConsentHelper(
|
||||||
|
mIsFaceEnrollable, mIsFingerprintEnrollable, mGkPwHandle);
|
||||||
|
setOrConfirmCredentialsNow();
|
||||||
|
} else {
|
||||||
|
startEnroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startEnroll() {
|
||||||
|
// TODO(b/188847063): This can be deleted, but log it now until it's wired up for real.
|
||||||
|
if (mParentalOptionsRequired) {
|
||||||
|
if (mParentalOptions == null) {
|
||||||
|
throw new IllegalStateException("consent options required, but not set");
|
||||||
|
}
|
||||||
|
Log.d(TAG, "consent for face: "
|
||||||
|
+ ParentalConsentHelper.hasFaceConsent(mParentalOptions));
|
||||||
|
Log.d(TAG, "consent for fingerprint: "
|
||||||
|
+ ParentalConsentHelper.hasFingerprintConsent(mParentalOptions));
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "startEnroll without requiring consent");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
|
||||||
|
final int authenticators = getIntent().getIntExtra(
|
||||||
|
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
|
||||||
Log.d(TAG, "Authenticators: " + authenticators);
|
Log.d(TAG, "Authenticators: " + authenticators);
|
||||||
|
|
||||||
final PackageManager pm = getApplicationContext().getPackageManager();
|
startEnrollWith(authenticators, WizardManagerHelper.isAnySetupWizard(getIntent()));
|
||||||
final boolean hasFeatureFingerprint =
|
|
||||||
pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
|
||||||
final boolean hasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
|
||||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
|
||||||
|
|
||||||
if (isSetupWizard) {
|
|
||||||
if (hasFeatureFace && hasFeatureFingerprint) {
|
|
||||||
setupForMultiBiometricEnroll();
|
|
||||||
} else if (hasFeatureFace) {
|
|
||||||
launchFaceOnlyEnroll();
|
|
||||||
} else if (hasFeatureFingerprint) {
|
|
||||||
launchFingerprintOnlyEnroll();
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "No biometrics but started by SUW?");
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
private void startEnrollWith(@Authenticators.Types int authenticators, boolean setupWizard) {
|
||||||
// If the caller is not setup wizard, and the user has something enrolled, finish.
|
// If the caller is not setup wizard, and the user has something enrolled, finish.
|
||||||
|
if (!setupWizard) {
|
||||||
final BiometricManager bm = getSystemService(BiometricManager.class);
|
final BiometricManager bm = getSystemService(BiometricManager.class);
|
||||||
final @BiometricError int result = bm.canAuthenticate(authenticators);
|
final @BiometricError int result = bm.canAuthenticate(authenticators);
|
||||||
if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
|
if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
|
||||||
Log.e(TAG, "Unexpected result: " + result);
|
Log.e(TAG, "Unexpected result (has enrollments): " + result);
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This will need to be updated if the device has sensors other than BIOMETRIC_STRONG
|
// This will need to be updated if the device has sensors other than BIOMETRIC_STRONG
|
||||||
if (authenticators == BiometricManager.Authenticators.DEVICE_CREDENTIAL) {
|
if (!setupWizard && authenticators == BiometricManager.Authenticators.DEVICE_CREDENTIAL) {
|
||||||
launchCredentialOnlyEnroll();
|
launchCredentialOnlyEnroll();
|
||||||
} else if (hasFeatureFace && hasFeatureFingerprint) {
|
} else if (mHasFeatureFace && mHasFeatureFingerprint) {
|
||||||
setupForMultiBiometricEnroll();
|
if (mParentalOptionsRequired && mGkPwHandle != null) {
|
||||||
} else if (hasFeatureFingerprint) {
|
launchFaceAndFingerprintEnroll();
|
||||||
|
} else {
|
||||||
|
setOrConfirmCredentialsNow();
|
||||||
|
}
|
||||||
|
} else if (mHasFeatureFingerprint) {
|
||||||
launchFingerprintOnlyEnroll();
|
launchFingerprintOnlyEnroll();
|
||||||
} else if (hasFeatureFace) {
|
} else if (mHasFeatureFace) {
|
||||||
launchFaceOnlyEnroll();
|
launchFaceOnlyEnroll();
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Unknown state, finishing");
|
Log.e(TAG, "Unknown state, finishing (was SUW: " + setupWizard + ")");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
|
outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
|
||||||
outState.putBoolean(SAVED_STATE_ENROLL_ACTION_LOGGED, mIsEnrollActionLogged);
|
outState.putBoolean(SAVED_STATE_ENROLL_ACTION_LOGGED, mIsEnrollActionLogged);
|
||||||
|
if (mParentalOptions != null) {
|
||||||
|
outState.putBundle(SAVED_STATE_PARENTAL_OPTIONS, mParentalOptions);
|
||||||
|
}
|
||||||
if (mGkPwHandle != null) {
|
if (mGkPwHandle != null) {
|
||||||
outState.putLong(SAVED_STATE_GK_PW_HANDLE, mGkPwHandle);
|
outState.putLong(SAVED_STATE_GK_PW_HANDLE, mGkPwHandle);
|
||||||
}
|
}
|
||||||
@@ -204,31 +268,84 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
// single enrollment is handled entirely by the launched activity
|
||||||
|
// this handles multi enroll or if parental consent is required
|
||||||
|
if (mParentalConsentHelper != null) {
|
||||||
|
handleOnActivityResultWhileConsenting(requestCode, resultCode, data);
|
||||||
|
} else {
|
||||||
|
handleOnActivityResultWhileEnrollingMultiple(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles responses while parental consent is pending
|
||||||
|
private void handleOnActivityResultWhileConsenting(
|
||||||
|
int requestCode, int resultCode, Intent data) {
|
||||||
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||||
|
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_CHOOSE_LOCK:
|
||||||
|
case REQUEST_CONFIRM_LOCK:
|
||||||
|
mConfirmingCredentials = false;
|
||||||
|
if (isSuccessfulConfirmOrChooseCredential(requestCode, resultCode)) {
|
||||||
|
updateGatekeeperPasswordHandle(data);
|
||||||
|
if (!mParentalConsentHelper.launchNext(this, REQUEST_CHOOSE_OPTIONS)) {
|
||||||
|
Log.e(TAG, "Nothing to prompt for consent (no modalities enabled)!");
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Unknown result for set/choose lock: " + resultCode);
|
||||||
|
setResult(resultCode);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REQUEST_CHOOSE_OPTIONS:
|
||||||
|
if (resultCode == RESULT_CONSENT_GRANTED || resultCode == RESULT_CONSENT_DENIED) {
|
||||||
|
final boolean isStillPrompting = mParentalConsentHelper.launchNext(
|
||||||
|
this, REQUEST_CHOOSE_OPTIONS, resultCode, data);
|
||||||
|
if (!isStillPrompting) {
|
||||||
|
Log.d(TAG, "Enrollment options set, starting enrollment now");
|
||||||
|
|
||||||
|
mParentalOptions = mParentalConsentHelper.getConsentResult();
|
||||||
|
mParentalConsentHelper = null;
|
||||||
|
startEnroll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Unknown or cancelled parental consent");
|
||||||
|
setResult(RESULT_CANCELED);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w(TAG, "Unknown consenting requestCode: " + requestCode + ", finishing");
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles responses while multi biometric enrollment is pending
|
||||||
|
private void handleOnActivityResultWhileEnrollingMultiple(
|
||||||
|
int requestCode, int resultCode, Intent data) {
|
||||||
if (mMultiBiometricEnrollHelper == null) {
|
if (mMultiBiometricEnrollHelper == null) {
|
||||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||||
|
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CHOOSE_LOCK:
|
case REQUEST_CHOOSE_LOCK:
|
||||||
|
case REQUEST_CONFIRM_LOCK:
|
||||||
mConfirmingCredentials = false;
|
mConfirmingCredentials = false;
|
||||||
if (resultCode == ChooseLockPattern.RESULT_FINISHED) {
|
final boolean isOk =
|
||||||
startMultiBiometricEnroll(data);
|
isSuccessfulConfirmOrChooseCredential(requestCode, resultCode);
|
||||||
|
// single modality enrollment requests confirmation directly
|
||||||
|
// via BiometricEnrollBase#onCreate and should never get here
|
||||||
|
if (isOk && mHasFeatureFace && mHasFeatureFingerprint) {
|
||||||
|
updateGatekeeperPasswordHandle(data);
|
||||||
|
launchFaceAndFingerprintEnroll();
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Unknown result for chooseLock: " + resultCode);
|
Log.d(TAG, "Unknown result for set/choose lock: " + resultCode);
|
||||||
setResult(resultCode);
|
setResult(resultCode);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REQUEST_CONFIRM_LOCK:
|
|
||||||
mConfirmingCredentials = false;
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
startMultiBiometricEnroll(data);
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Unknown result for confirmLock: " + resultCode);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
Log.d(TAG, "Unknown requestCode: " + requestCode + ", finishing");
|
Log.w(TAG, "Unknown enrolling requestCode: " + requestCode + ", finishing");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -236,18 +353,28 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isSuccessfulConfirmOrChooseCredential(int requestCode, int resultCode) {
|
||||||
|
final boolean okChoose = requestCode == REQUEST_CHOOSE_LOCK
|
||||||
|
&& resultCode == ChooseLockPattern.RESULT_FINISHED;
|
||||||
|
final boolean okConfirm = requestCode == REQUEST_CONFIRM_LOCK
|
||||||
|
&& resultCode == RESULT_OK;
|
||||||
|
return okChoose || okConfirm;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
|
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
|
||||||
final int new_resid = SetupWizardUtils.getTheme(this, getIntent());
|
final int newResid = SetupWizardUtils.getTheme(this, getIntent());
|
||||||
theme.applyStyle(R.style.SetupWizardPartnerResource, true);
|
theme.applyStyle(R.style.SetupWizardPartnerResource, true);
|
||||||
super.onApplyThemeResource(theme, new_resid, first);
|
super.onApplyThemeResource(theme, newResid, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
|
||||||
if (mConfirmingCredentials || mMultiBiometricEnrollHelper != null) {
|
if (mConfirmingCredentials
|
||||||
|
|| mMultiBiometricEnrollHelper != null
|
||||||
|
|| mParentalConsentHelper != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +384,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupForMultiBiometricEnroll() {
|
|
||||||
|
private void setOrConfirmCredentialsNow() {
|
||||||
if (!mConfirmingCredentials) {
|
if (!mConfirmingCredentials) {
|
||||||
mConfirmingCredentials = true;
|
mConfirmingCredentials = true;
|
||||||
if (!userHasPassword(mUserId)) {
|
if (!userHasPassword(mUserId)) {
|
||||||
@@ -268,37 +396,11 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMultiBiometricEnroll(Intent data) {
|
private void updateGatekeeperPasswordHandle(@NonNull Intent data) {
|
||||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
|
||||||
final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
|
|
||||||
final FaceManager faceManager = getSystemService(FaceManager.class);
|
|
||||||
final List<FingerprintSensorPropertiesInternal> fpProperties =
|
|
||||||
fingerprintManager.getSensorPropertiesInternal();
|
|
||||||
final List<FaceSensorPropertiesInternal> faceProperties =
|
|
||||||
faceManager.getSensorPropertiesInternal();
|
|
||||||
|
|
||||||
mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
|
mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
|
||||||
|
if (mParentalConsentHelper != null) {
|
||||||
if (isSetupWizard) {
|
mParentalConsentHelper.updateGatekeeperHandle(data);
|
||||||
// This would need to be updated for devices with multiple sensors of the same modality
|
|
||||||
mIsFaceEnrollable = !faceProperties.isEmpty()
|
|
||||||
&& faceManager.getEnrolledFaces(mUserId).size() == 0;
|
|
||||||
mIsFingerprintEnrollable = !fpProperties.isEmpty()
|
|
||||||
&& fingerprintManager.getEnrolledFingerprints(mUserId).size() == 0;
|
|
||||||
} else {
|
|
||||||
// This would need to be updated for devices with multiple sensors of the same modality
|
|
||||||
mIsFaceEnrollable = !faceProperties.isEmpty()
|
|
||||||
&& faceManager.getEnrolledFaces(mUserId).size()
|
|
||||||
< faceProperties.get(0).maxEnrollmentsPerUser;
|
|
||||||
mIsFingerprintEnrollable = !fpProperties.isEmpty()
|
|
||||||
&& fingerprintManager.getEnrolledFingerprints(mUserId).size()
|
|
||||||
< fpProperties.get(0).maxEnrollmentsPerUser;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mMultiBiometricEnrollHelper = new MultiBiometricEnrollHelper(this, mUserId,
|
|
||||||
mIsFaceEnrollable, mIsFingerprintEnrollable, mGkPwHandle);
|
|
||||||
mMultiBiometricEnrollHelper.startNextStep();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean userHasPassword(int userId) {
|
private boolean userHasPassword(int userId) {
|
||||||
@@ -310,6 +412,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
|
|
||||||
private void launchChooseLock() {
|
private void launchChooseLock() {
|
||||||
Log.d(TAG, "launchChooseLock");
|
Log.d(TAG, "launchChooseLock");
|
||||||
|
|
||||||
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
@@ -323,6 +426,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
|
|
||||||
private void launchConfirmLock() {
|
private void launchConfirmLock() {
|
||||||
Log.d(TAG, "launchConfirmLock");
|
Log.d(TAG, "launchConfirmLock");
|
||||||
|
|
||||||
final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this);
|
final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this);
|
||||||
builder.setRequestCode(REQUEST_CONFIRM_LOCK)
|
builder.setRequestCode(REQUEST_CONFIRM_LOCK)
|
||||||
.setRequestGatekeeperPasswordHandle(true)
|
.setRequestGatekeeperPasswordHandle(true)
|
||||||
@@ -346,7 +450,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
* @param intent Enrollment activity that should be started (e.g. FaceEnrollIntroduction.class,
|
* @param intent Enrollment activity that should be started (e.g. FaceEnrollIntroduction.class,
|
||||||
* etc).
|
* etc).
|
||||||
*/
|
*/
|
||||||
private void launchEnrollActivity(@NonNull Intent intent) {
|
private void launchSingleSensorEnrollActivity(@NonNull Intent intent) {
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||||
byte[] hardwareAuthToken = null;
|
byte[] hardwareAuthToken = null;
|
||||||
if (this instanceof InternalActivity) {
|
if (this instanceof InternalActivity) {
|
||||||
@@ -362,7 +466,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
// If only device credential was specified, ask the user to only set that up.
|
// If only device credential was specified, ask the user to only set that up.
|
||||||
intent = new Intent(this, ChooseLockGeneric.class);
|
intent = new Intent(this, ChooseLockGeneric.class);
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
launchEnrollActivity(intent);
|
launchSingleSensorEnrollActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchFingerprintOnlyEnroll() {
|
private void launchFingerprintOnlyEnroll() {
|
||||||
@@ -374,12 +478,18 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
} else {
|
} else {
|
||||||
intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
|
intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
|
||||||
}
|
}
|
||||||
launchEnrollActivity(intent);
|
launchSingleSensorEnrollActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchFaceOnlyEnroll() {
|
private void launchFaceOnlyEnroll() {
|
||||||
final Intent intent = BiometricUtils.getFaceIntroIntent(this, getIntent());
|
final Intent intent = BiometricUtils.getFaceIntroIntent(this, getIntent());
|
||||||
launchEnrollActivity(intent);
|
launchSingleSensorEnrollActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchFaceAndFingerprintEnroll() {
|
||||||
|
mMultiBiometricEnrollHelper = new MultiBiometricEnrollHelper(this, mUserId,
|
||||||
|
mIsFaceEnrollable, mIsFingerprintEnrollable, mGkPwHandle);
|
||||||
|
mMultiBiometricEnrollHelper.startNextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -26,6 +26,7 @@ import android.graphics.Color;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -50,12 +51,15 @@ import com.google.android.setupdesign.util.ThemeHelper;
|
|||||||
*/
|
*/
|
||||||
public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "BiometricEnrollBase";
|
||||||
|
|
||||||
public static final String EXTRA_FROM_SETTINGS_SUMMARY = "from_settings_summary";
|
public static final String EXTRA_FROM_SETTINGS_SUMMARY = "from_settings_summary";
|
||||||
public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
|
public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
|
||||||
public static final String EXTRA_KEY_REQUIRE_VISION = "accessibility_vision";
|
public static final String EXTRA_KEY_REQUIRE_VISION = "accessibility_vision";
|
||||||
public static final String EXTRA_KEY_REQUIRE_DIVERSITY = "accessibility_diversity";
|
public static final String EXTRA_KEY_REQUIRE_DIVERSITY = "accessibility_diversity";
|
||||||
public static final String EXTRA_KEY_SENSOR_ID = "sensor_id";
|
public static final String EXTRA_KEY_SENSOR_ID = "sensor_id";
|
||||||
public static final String EXTRA_KEY_CHALLENGE = "challenge";
|
public static final String EXTRA_KEY_CHALLENGE = "challenge";
|
||||||
|
public static final String EXTRA_KEY_MODALITY = "sensor_modality";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the choose fingerprint wizard to indicate the wizard is
|
* Used by the choose fingerprint wizard to indicate the wizard is
|
||||||
@@ -84,11 +88,26 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
|||||||
*/
|
*/
|
||||||
public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2;
|
public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by consent screens to indicate that consent was granted. Extras, such as
|
||||||
|
* EXTRA_KEY_MODALITY, will be included in the result to provide details about the
|
||||||
|
* consent that was granted.
|
||||||
|
*/
|
||||||
|
public static final int RESULT_CONSENT_GRANTED = RESULT_FIRST_USER + 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by consent screens to indicate that consent was denied. Extras, such as
|
||||||
|
* EXTRA_KEY_MODALITY, will be included in the result to provide details about the
|
||||||
|
* consent that was not granted.
|
||||||
|
*/
|
||||||
|
public static final int RESULT_CONSENT_DENIED = RESULT_FIRST_USER + 4;
|
||||||
|
|
||||||
public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
|
public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
|
||||||
public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
|
public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
|
||||||
public static final int LEARN_MORE_REQUEST = 3;
|
public static final int LEARN_MORE_REQUEST = 3;
|
||||||
public static final int CONFIRM_REQUEST = 4;
|
public static final int CONFIRM_REQUEST = 4;
|
||||||
public static final int ENROLL_REQUEST = 5;
|
public static final int ENROLL_REQUEST = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request code when starting another biometric enrollment from within a biometric flow. For
|
* Request code when starting another biometric enrollment from within a biometric flow. For
|
||||||
* example, when starting fingerprint enroll after face enroll.
|
* example, when starting fingerprint enroll after face enroll.
|
||||||
@@ -242,6 +261,8 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void launchConfirmLock(int titleResId) {
|
protected void launchConfirmLock(int titleResId) {
|
||||||
|
Log.d(TAG, "launchConfirmLock");
|
||||||
|
|
||||||
final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this);
|
final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this);
|
||||||
builder.setRequestCode(CONFIRM_REQUEST)
|
builder.setRequestCode(CONFIRM_REQUEST)
|
||||||
.setTitle(getString(titleResId))
|
.setTitle(getString(titleResId))
|
||||||
|
@@ -294,15 +294,19 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
|||||||
mConfirmingCredentials = false;
|
mConfirmingCredentials = false;
|
||||||
if (resultCode == RESULT_FINISHED) {
|
if (resultCode == RESULT_FINISHED) {
|
||||||
updatePasswordQuality();
|
updatePasswordQuality();
|
||||||
|
final boolean handled = onSetOrConfirmCredentials(data);
|
||||||
|
if (!handled) {
|
||||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||||
getNextButton().setEnabled(false);
|
getNextButton().setEnabled(false);
|
||||||
getChallenge(((sensorId, userId, challenge) -> {
|
getChallenge(((sensorId, userId, challenge) -> {
|
||||||
mSensorId = sensorId;
|
mSensorId = sensorId;
|
||||||
mChallenge = challenge;
|
mChallenge = challenge;
|
||||||
mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, challenge);
|
mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId,
|
||||||
|
challenge);
|
||||||
BiometricUtils.removeGatekeeperPasswordHandle(this, data);
|
BiometricUtils.removeGatekeeperPasswordHandle(this, data);
|
||||||
getNextButton().setEnabled(true);
|
getNextButton().setEnabled(true);
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setResult(resultCode, data);
|
setResult(resultCode, data);
|
||||||
finish();
|
finish();
|
||||||
@@ -310,15 +314,19 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
|||||||
} else if (requestCode == CONFIRM_REQUEST) {
|
} else if (requestCode == CONFIRM_REQUEST) {
|
||||||
mConfirmingCredentials = false;
|
mConfirmingCredentials = false;
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
final boolean handled = onSetOrConfirmCredentials(data);
|
||||||
|
if (!handled) {
|
||||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||||
getNextButton().setEnabled(false);
|
getNextButton().setEnabled(false);
|
||||||
getChallenge(((sensorId, userId, challenge) -> {
|
getChallenge(((sensorId, userId, challenge) -> {
|
||||||
mSensorId = sensorId;
|
mSensorId = sensorId;
|
||||||
mChallenge = challenge;
|
mChallenge = challenge;
|
||||||
mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId, challenge);
|
mToken = BiometricUtils.requestGatekeeperHat(this, data, mUserId,
|
||||||
|
challenge);
|
||||||
BiometricUtils.removeGatekeeperPasswordHandle(this, data);
|
BiometricUtils.removeGatekeeperPasswordHandle(this, data);
|
||||||
getNextButton().setEnabled(true);
|
getNextButton().setEnabled(true);
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setResult(resultCode, data);
|
setResult(resultCode, data);
|
||||||
finish();
|
finish();
|
||||||
@@ -335,6 +343,18 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
|||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after confirming credentials. Can be used to prevent the default
|
||||||
|
* behavior of immediately calling #getChallenge (useful to things like intro
|
||||||
|
* consent screens that don't actually do enrollment and will later start an
|
||||||
|
* activity that does).
|
||||||
|
*
|
||||||
|
* @return True if the default behavior should be skipped and handled by this method instead.
|
||||||
|
*/
|
||||||
|
protected boolean onSetOrConfirmCredentials(@Nullable Intent data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected void onCancelButtonClick(View view) {
|
protected void onCancelButtonClick(View view) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
168
src/com/android/settings/biometrics/ParentalConsentHelper.java
Normal file
168
src/com/android/settings/biometrics/ParentalConsentHelper.java
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.biometrics;
|
||||||
|
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
|
||||||
|
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_MODALITY;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_DENIED;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_GRANTED;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.settings.biometrics.face.FaceEnrollParentalConsent;
|
||||||
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollParentalConsent;
|
||||||
|
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||||
|
|
||||||
|
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for {@link BiometricEnrollActivity} to ask for parental consent prior to actual user
|
||||||
|
* enrollment.
|
||||||
|
*/
|
||||||
|
public class ParentalConsentHelper {
|
||||||
|
|
||||||
|
private static final String KEY_FACE_CONSENT = "face";
|
||||||
|
private static final String KEY_FINGERPRINT_CONSENT = "fingerprint";
|
||||||
|
|
||||||
|
private final boolean mRequireFace;
|
||||||
|
private final boolean mRequireFingerprint;
|
||||||
|
|
||||||
|
private long mGkPwHandle;
|
||||||
|
@Nullable
|
||||||
|
private Boolean mConsentFace;
|
||||||
|
@Nullable
|
||||||
|
private Boolean mConsentFingerprint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for aggregating user consent.
|
||||||
|
*
|
||||||
|
* @param requireFace if face consent should be shown
|
||||||
|
* @param requireFingerprint if fingerprint consent should be shown
|
||||||
|
* @param gkPwHandle for launched intents
|
||||||
|
*/
|
||||||
|
public ParentalConsentHelper(boolean requireFace, boolean requireFingerprint,
|
||||||
|
@Nullable Long gkPwHandle) {
|
||||||
|
mRequireFace = requireFace;
|
||||||
|
mRequireFingerprint = requireFingerprint;
|
||||||
|
mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updated the handle used for launching activities
|
||||||
|
*
|
||||||
|
* @param data result intent for credential verification
|
||||||
|
*/
|
||||||
|
public void updateGatekeeperHandle(Intent data) {
|
||||||
|
mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the next consent screen.
|
||||||
|
*
|
||||||
|
* @param activity root activity
|
||||||
|
* @param requestCode request code to launch new activity
|
||||||
|
* @param resultCode result code of the last consent launch
|
||||||
|
* @param data result data from the last consent launch
|
||||||
|
* @return true if a consent activity was launched or false when complete
|
||||||
|
*/
|
||||||
|
public boolean launchNext(@NonNull Activity activity, int requestCode, int resultCode,
|
||||||
|
@Nullable Intent data) {
|
||||||
|
if (data != null) {
|
||||||
|
switch (data.getIntExtra(EXTRA_KEY_MODALITY, TYPE_NONE)) {
|
||||||
|
case TYPE_FACE:
|
||||||
|
mConsentFace = isConsent(resultCode, mConsentFace);
|
||||||
|
break;
|
||||||
|
case TYPE_FINGERPRINT:
|
||||||
|
mConsentFingerprint = isConsent(resultCode, mConsentFingerprint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return launchNext(activity, requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Boolean isConsent(int resultCode, @Nullable Boolean defaultValue) {
|
||||||
|
switch (resultCode) {
|
||||||
|
case RESULT_CONSENT_GRANTED:
|
||||||
|
return true;
|
||||||
|
case RESULT_CONSENT_DENIED:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see #launchNext(Activity, int, int, Intent) */
|
||||||
|
public boolean launchNext(@NonNull Activity activity, int requestCode) {
|
||||||
|
final Intent intent = getNextConsentIntent(activity);
|
||||||
|
if (intent != null) {
|
||||||
|
WizardManagerHelper.copyWizardManagerExtras(activity.getIntent(), intent);
|
||||||
|
if (mGkPwHandle != 0) {
|
||||||
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
|
||||||
|
}
|
||||||
|
activity.startActivityForResult(intent, requestCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Intent getNextConsentIntent(@NonNull Context context) {
|
||||||
|
if (mRequireFace && mConsentFace == null) {
|
||||||
|
return new Intent(context, FaceEnrollParentalConsent.class);
|
||||||
|
}
|
||||||
|
if (mRequireFingerprint && mConsentFingerprint == null) {
|
||||||
|
return new Intent(context, FingerprintEnrollParentalConsent.class);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the result of all consent requests.
|
||||||
|
*
|
||||||
|
* This should be called when {@link #launchNext(Activity, int, int, Intent)} returns false
|
||||||
|
* to indicate that all responses have been recorded.
|
||||||
|
*
|
||||||
|
* @return The aggregate consent status.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Bundle getConsentResult() {
|
||||||
|
final Bundle result = new Bundle();
|
||||||
|
result.putBoolean(KEY_FACE_CONSENT, mConsentFace != null ? mConsentFace : false);
|
||||||
|
result.putBoolean(KEY_FINGERPRINT_CONSENT,
|
||||||
|
mConsentFingerprint != null ? mConsentFingerprint : false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return If the result bundle contains consent for face authentication. */
|
||||||
|
public static boolean hasFaceConsent(@NonNull Bundle bundle) {
|
||||||
|
return bundle.getBoolean(KEY_FACE_CONSENT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return If the result bundle contains consent for fingerprint authentication. */
|
||||||
|
public static boolean hasFingerprintConsent(@NonNull Bundle bundle) {
|
||||||
|
return bundle.getBoolean(KEY_FINGERPRINT_CONSENT, false);
|
||||||
|
}
|
||||||
|
}
|
@@ -76,30 +76,70 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
|||||||
|
|
||||||
final ImageView iconGlasses = findViewById(R.id.icon_glasses);
|
final ImageView iconGlasses = findViewById(R.id.icon_glasses);
|
||||||
final ImageView iconLooking = findViewById(R.id.icon_looking);
|
final ImageView iconLooking = findViewById(R.id.icon_looking);
|
||||||
final ImageView iconSecurity = findViewById(R.id.icon_security);
|
|
||||||
iconGlasses.getBackground().setColorFilter(getIconColorFilter());
|
iconGlasses.getBackground().setColorFilter(getIconColorFilter());
|
||||||
iconLooking.getBackground().setColorFilter(getIconColorFilter());
|
iconLooking.getBackground().setColorFilter(getIconColorFilter());
|
||||||
iconSecurity.getBackground().setColorFilter(getIconColorFilter());
|
|
||||||
|
final TextView infoMessageGlasses = findViewById(R.id.info_message_glasses);
|
||||||
|
final TextView infoMessageLooking = findViewById(R.id.info_message_looking);
|
||||||
|
final TextView howMessage = findViewById(R.id.how_message);
|
||||||
|
final TextView inControlTitle = findViewById(R.id.title_in_control);
|
||||||
|
final TextView inControlMessage = findViewById(R.id.message_in_control);
|
||||||
|
infoMessageGlasses.setText(getInfoMessageGlasses());
|
||||||
|
infoMessageLooking.setText(getInfoMessageLooking());
|
||||||
|
howMessage.setText(getHowMessage());
|
||||||
|
inControlTitle.setText(getInControlTitle());
|
||||||
|
inControlMessage.setText(getInControlMessage());
|
||||||
|
|
||||||
mFaceManager = Utils.getFaceManagerOrNull(this);
|
mFaceManager = Utils.getFaceManagerOrNull(this);
|
||||||
mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
|
mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
|
||||||
.getFaceFeatureProvider();
|
.getFaceFeatureProvider();
|
||||||
|
|
||||||
|
|
||||||
// This path is an entry point for SetNewPasswordController, e.g.
|
// This path is an entry point for SetNewPasswordController, e.g.
|
||||||
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
|
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
|
||||||
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
||||||
|
if (generateChallengeOnCreate()) {
|
||||||
mFooterBarMixin.getPrimaryButton().setEnabled(false);
|
mFooterBarMixin.getPrimaryButton().setEnabled(false);
|
||||||
// We either block on generateChallenge, or need to gray out the "next" button until
|
// 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.
|
// the challenge is ready. Let's just do this for now.
|
||||||
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
|
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
|
||||||
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
|
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId,
|
||||||
|
challenge);
|
||||||
mSensorId = sensorId;
|
mSensorId = sensorId;
|
||||||
mChallenge = challenge;
|
mChallenge = challenge;
|
||||||
mFooterBarMixin.getPrimaryButton().setEnabled(true);
|
mFooterBarMixin.getPrimaryButton().setEnabled(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean generateChallengeOnCreate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getInfoMessageGlasses() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_info_glasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getInfoMessageLooking() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_info_looking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getHowMessage() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_how_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getInControlTitle() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_control_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getInControlMessage() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_control_message;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isDisabledByAdmin() {
|
protected boolean isDisabledByAdmin() {
|
||||||
|
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.biometrics.face;
|
||||||
|
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays parental consent information for face authentication.
|
||||||
|
*
|
||||||
|
* TODO(b/188847063): swap strings for consent screen
|
||||||
|
*/
|
||||||
|
public class FaceEnrollParentalConsent extends FaceEnrollIntroduction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setDescriptionText(R.string.security_settings_face_enroll_introduction_consent_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNextButtonClick(View view) {
|
||||||
|
onConsentResult(true /* granted */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSkipButtonClick(View view) {
|
||||||
|
onConsentResult(false /* granted */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onConsentResult(boolean granted) {
|
||||||
|
final Intent result = new Intent();
|
||||||
|
result.putExtra(EXTRA_KEY_MODALITY, TYPE_FACE);
|
||||||
|
setResult(granted ? RESULT_CONSENT_GRANTED : RESULT_CONSENT_DENIED, result);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onSetOrConfirmCredentials(@Nullable Intent data) {
|
||||||
|
// prevent challenge from being generated by default
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean generateChallengeOnCreate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StringRes
|
||||||
|
protected int getInfoMessageGlasses() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_info_consent_glasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StringRes
|
||||||
|
protected int getInfoMessageLooking() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_info_consent_looking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StringRes
|
||||||
|
protected int getHowMessage() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_how_consent_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StringRes
|
||||||
|
protected int getInControlTitle() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_control_consent_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@StringRes
|
||||||
|
protected int getInControlMessage() {
|
||||||
|
return R.string.security_settings_face_enroll_introduction_control_consent_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getHeaderResDefault() {
|
||||||
|
return R.string.security_settings_face_enroll_consent_introduction_title;
|
||||||
|
}
|
||||||
|
}
|
@@ -64,21 +64,62 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
final ImageView iconFingerprint = findViewById(R.id.icon_fingerprint);
|
final ImageView iconFingerprint = findViewById(R.id.icon_fingerprint);
|
||||||
final ImageView iconLocked = findViewById(R.id.icon_locked);
|
|
||||||
final ImageView iconDelete = findViewById(R.id.icon_delete);
|
|
||||||
final ImageView iconInfo = findViewById(R.id.icon_info);
|
final ImageView iconInfo = findViewById(R.id.icon_info);
|
||||||
final ImageView iconLink = findViewById(R.id.icon_link);
|
final ImageView iconLink = findViewById(R.id.icon_link);
|
||||||
iconFingerprint.getDrawable().setColorFilter(getIconColorFilter());
|
iconFingerprint.getDrawable().setColorFilter(getIconColorFilter());
|
||||||
iconLocked.getDrawable().setColorFilter(getIconColorFilter());
|
|
||||||
iconDelete.getDrawable().setColorFilter(getIconColorFilter());
|
|
||||||
iconInfo.getDrawable().setColorFilter(getIconColorFilter());
|
iconInfo.getDrawable().setColorFilter(getIconColorFilter());
|
||||||
iconLink.getDrawable().setColorFilter(getIconColorFilter());
|
iconLink.getDrawable().setColorFilter(getIconColorFilter());
|
||||||
|
|
||||||
|
final TextView footerMessage2 = findViewById(R.id.footer_message_2);
|
||||||
|
final TextView footerMessage3 = findViewById(R.id.footer_message_3);
|
||||||
|
final TextView footerMessage4 = findViewById(R.id.footer_message_4);
|
||||||
|
final TextView footerMessage5 = findViewById(R.id.footer_message_5);
|
||||||
|
footerMessage2.setText(getFooterMessage2());
|
||||||
|
footerMessage3.setText(getFooterMessage3());
|
||||||
|
footerMessage4.setText(getFooterMessage4());
|
||||||
|
footerMessage5.setText(getFooterMessage5());
|
||||||
|
|
||||||
|
final TextView footerTitle1 = findViewById(R.id.footer_title_1);
|
||||||
|
final TextView footerTitle2 = findViewById(R.id.footer_title_2);
|
||||||
|
footerTitle1.setText(getFooterTitle1());
|
||||||
|
footerTitle2.setText(getFooterTitle2());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
int getNegativeButtonTextId() {
|
int getNegativeButtonTextId() {
|
||||||
return R.string.security_settings_fingerprint_enroll_introduction_skip;
|
return R.string.security_settings_fingerprint_enroll_introduction_skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterTitle1() {
|
||||||
|
return R.string.security_settings_fingerprint_enroll_introduction_footer_title_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterTitle2() {
|
||||||
|
return R.string.security_settings_fingerprint_enroll_introduction_footer_title_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage2() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage3() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage4() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage5() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_5;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isDisabledByAdmin() {
|
protected boolean isDisabledByAdmin() {
|
||||||
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
||||||
|
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.biometrics.fingerprint;
|
||||||
|
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays parental consent information for fingerprint authentication.
|
||||||
|
*
|
||||||
|
* TODO(b/188847063): swap strings for consent screen
|
||||||
|
*/
|
||||||
|
public class FingerprintEnrollParentalConsent extends FingerprintEnrollIntroduction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setDescriptionText(
|
||||||
|
R.string.security_settings_fingerprint_enroll_introduction_consent_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNextButtonClick(View view) {
|
||||||
|
onConsentResult(true /* granted */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSkipButtonClick(View view) {
|
||||||
|
onConsentResult(false /* granted */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onConsentResult(boolean granted) {
|
||||||
|
final Intent result = new Intent();
|
||||||
|
result.putExtra(EXTRA_KEY_MODALITY, TYPE_FINGERPRINT);
|
||||||
|
setResult(granted ? RESULT_CONSENT_GRANTED : RESULT_CONSENT_DENIED, result);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onSetOrConfirmCredentials(@Nullable Intent data) {
|
||||||
|
// prevent challenge from being generated by default
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
@Override
|
||||||
|
protected int getFooterTitle1() {
|
||||||
|
return R.string.security_settings_fingerprint_enroll_introduction_footer_title_consent_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
@Override
|
||||||
|
protected int getFooterMessage2() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
@Override
|
||||||
|
protected int getFooterMessage3() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage4() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
protected int getFooterMessage5() {
|
||||||
|
return R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_consent_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getHeaderResDefault() {
|
||||||
|
return R.string.security_settings_fingerprint_enroll_consent_introduction_title;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.biometrics;
|
||||||
|
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
|
||||||
|
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
|
||||||
|
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_MODALITY;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_DENIED;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_GRANTED;
|
||||||
|
|
||||||
|
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.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.hardware.biometrics.BiometricAuthenticator;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.settings.biometrics.face.FaceEnrollParentalConsent;
|
||||||
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollParentalConsent;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ParentalConsentHelperTest {
|
||||||
|
|
||||||
|
private static final int REQUEST_CODE = 12;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mMocks = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Activity mRootActivity;
|
||||||
|
@Mock
|
||||||
|
private Intent mRootActivityIntent;
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<Intent> mLastStarted;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
when(mRootActivity.getIntent()).thenAnswer(invocation -> mRootActivityIntent);
|
||||||
|
when(mRootActivityIntent.getBundleExtra(any())).thenAnswer(invocation -> null);
|
||||||
|
when(mRootActivityIntent.getStringExtra(any())).thenAnswer(invocation -> null);
|
||||||
|
when(mRootActivityIntent.getBooleanExtra(any(), anyBoolean()))
|
||||||
|
.thenAnswer(invocation -> invocation.getArguments()[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_and_fingerprint_all_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, true /* grantFace */,
|
||||||
|
true /* requireFingerprint */, true /* grantFace */,
|
||||||
|
90 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_nothing_to_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
false /* requireFace */, false /* grantFace */,
|
||||||
|
false /* requireFingerprint */, false /* grantFace */,
|
||||||
|
80 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_and_fingerprint_no_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, false /* grantFace */,
|
||||||
|
true /* requireFingerprint */, false /* grantFace */,
|
||||||
|
70 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_and_fingerprint_only_face_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, true /* grantFace */,
|
||||||
|
true /* requireFingerprint */, false /* grantFace */,
|
||||||
|
60 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_and_fingerprint_only_fingerprint_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, false /* grantFace */,
|
||||||
|
true /* requireFingerprint */, true /* grantFace */,
|
||||||
|
50 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_with_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, true /* grantFace */,
|
||||||
|
false /* requireFingerprint */, false /* grantFace */,
|
||||||
|
40 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_face_without_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
true /* requireFace */, false /* grantFace */,
|
||||||
|
false /* requireFingerprint */, false /* grantFace */,
|
||||||
|
30 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_fingerprint_with_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
false /* requireFace */, false /* grantFace */,
|
||||||
|
true /* requireFingerprint */, true /* grantFace */,
|
||||||
|
20 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLaunchNext_fingerprint_without_consent() {
|
||||||
|
testLaunchNext(
|
||||||
|
false /* requireFace */, false /* grantFace */,
|
||||||
|
true /* requireFingerprint */, false /* grantFace */,
|
||||||
|
10 /* gkpw */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testLaunchNext(
|
||||||
|
boolean requireFace, boolean grantFace,
|
||||||
|
boolean requireFingerprint, boolean grantFingerprint,
|
||||||
|
long gkpw) {
|
||||||
|
final List<Pair<String, Boolean>> expectedLaunches = new ArrayList<>();
|
||||||
|
if (requireFace) {
|
||||||
|
expectedLaunches.add(new Pair(FaceEnrollParentalConsent.class.getName(), grantFace));
|
||||||
|
}
|
||||||
|
if (requireFingerprint) {
|
||||||
|
expectedLaunches.add(
|
||||||
|
new Pair(FingerprintEnrollParentalConsent.class.getName(), grantFingerprint));
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial consent status
|
||||||
|
final ParentalConsentHelper helper =
|
||||||
|
new ParentalConsentHelper(requireFace, requireFingerprint, gkpw);
|
||||||
|
assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult()))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult()))
|
||||||
|
.isFalse();
|
||||||
|
|
||||||
|
// check expected launches
|
||||||
|
for (int i = 0; i <= expectedLaunches.size(); i++) {
|
||||||
|
final Pair<String, Boolean> expected = i > 0 ? expectedLaunches.get(i - 1) : null;
|
||||||
|
final boolean launchedNext = i == 0
|
||||||
|
? helper.launchNext(mRootActivity, REQUEST_CODE)
|
||||||
|
: helper.launchNext(mRootActivity, REQUEST_CODE,
|
||||||
|
expected.second ? RESULT_CONSENT_GRANTED : RESULT_CONSENT_DENIED,
|
||||||
|
getResultIntent(getStartedModality(expected.first)));
|
||||||
|
assertThat(launchedNext).isEqualTo(i < expectedLaunches.size());
|
||||||
|
}
|
||||||
|
verify(mRootActivity, times(expectedLaunches.size()))
|
||||||
|
.startActivityForResult(mLastStarted.capture(), eq(REQUEST_CODE));
|
||||||
|
assertThat(mLastStarted.getAllValues()
|
||||||
|
.stream().map(i -> i.getComponent().getClassName()).collect(Collectors.toList()))
|
||||||
|
.containsExactlyElementsIn(
|
||||||
|
expectedLaunches.stream().map(i -> i.first).collect(Collectors.toList()))
|
||||||
|
.inOrder();
|
||||||
|
if (!expectedLaunches.isEmpty()) {
|
||||||
|
assertThat(mLastStarted.getAllValues()
|
||||||
|
.stream().map(BiometricUtils::getGatekeeperPasswordHandle).distinct()
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.containsExactly(gkpw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// final consent status
|
||||||
|
assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult()))
|
||||||
|
.isEqualTo(requireFace && grantFace);
|
||||||
|
assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult()))
|
||||||
|
.isEqualTo(requireFingerprint && grantFingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Intent getResultIntent(@BiometricAuthenticator.Modality int modality) {
|
||||||
|
final Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_KEY_MODALITY, modality);
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BiometricAuthenticator.Modality
|
||||||
|
private static int getStartedModality(String name) {
|
||||||
|
if (name.equals(FaceEnrollParentalConsent.class.getName())) {
|
||||||
|
return TYPE_FACE;
|
||||||
|
}
|
||||||
|
if (name.equals(FingerprintEnrollParentalConsent.class.getName())) {
|
||||||
|
return TYPE_FINGERPRINT;
|
||||||
|
}
|
||||||
|
return TYPE_NONE;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user