Skip to content

Commit

Permalink
[Auto Pin Confirm]: Changes to allow PIN auto confirm feature to be c…
Browse files Browse the repository at this point in the history
…ontrollable by the user

- Add SwitchPreference to allow user to control the pin auto confirm feature
- Add Checkbox option during the PIN setup in Security app
- Disable the opt-in checkbox during SUW entry point for PIN setup
- Update SwitchPreference availability appropriately according to current PIN length
- Update the pin_auto_confirm setting appropriately according to state of switchPreference or checkbox state (in PIN setup)
- Update the error-message when PIN Too short to let user know six digit is recommended

Bug: 262926000
Bug: 262936383
Bug: 262934702
Bug: 262935305
Test: Manual Test
Test: atest SettingsRoboTests
Change-Id: Ib9e09bd5ce44652158e77f80e8be19c4dd50f3bf
  • Loading branch information
Avinash Vadlamudi committed Jan 30, 2023
1 parent 5135787 commit 4c8ad8f
Show file tree
Hide file tree
Showing 12 changed files with 551 additions and 4 deletions.
24 changes: 24 additions & 0 deletions res/drawable/checkbox_circle_shape.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:drawable="@drawable/ic_check_circle_filled_24dp" />
<item
android:state_checked="false"
android:drawable="@drawable/ic_circle_outline_24dp" />
</selector>
27 changes: 27 additions & 0 deletions res/drawable/ic_check_circle_filled_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?androidprv:attr/colorAccentPrimaryVariant">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM10.59,16.6l-4.24,-4.24l1.41,-1.41l2.83,2.83l5.66,-5.66l1.41,1.41L10.59,16.6z"/>
</vector>
26 changes: 26 additions & 0 deletions res/drawable/ic_circle_outline_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
23 changes: 23 additions & 0 deletions res/layout/choose_lock_password.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<CheckBox
android:id="@+id/auto_pin_confirm_enabler"
android:layout_marginTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:paddingLeft="14dp"
android:text="@string/auto_pin_confirm_user_message"
android:textSize="16sp"
android:button="@drawable/checkbox_circle_shape"
android:visibility="gone" />

</LinearLayout>

<TextView
android:id="@+id/auto_pin_confirm_security_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/auto_pin_confirm_opt_in_security_message"
android:textSize="16sp"
android:visibility="gone" />

<Button
android:id="@+id/screen_lock_options"
style="@style/SudGlifButton.Tertiary"
Expand Down
15 changes: 15 additions & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,15 @@
<!-- Title for dialog in screen lock settings, allowing users to choose other types of screen locks. [CHAR LIMIT=40] -->
<string name="setup_lock_settings_options_dialog_title">Screen lock options</string>

<!-- Title of the lock screen auto pin confirm setting. [CHAR LIMIT=NONE] -->
<string name="lock_screen_auto_pin_confirm_title">Auto-confirm unlock</string>
<!-- Summary of the lock screen auto pin confirm setting. [CHAR LIMIT=NONE] -->
<string name="lock_screen_auto_pin_confirm_summary">Unlock automatically if you input a correct PIN of 6 digits or more. This is slightly less secure than tapping Enter to confirm.</string>
<!-- Message shown to check auto pin confirmation feature when the user is updating the PIN. [CHAR LIMIT=NONE] -->
<string name="auto_pin_confirm_user_message">Auto-confirm correct PIN</string>
<!-- Message shown to explain the security concern if a user opts-in to the auto-pin feature. [CHAR LIMIT=NONE] -->
<string name="auto_pin_confirm_opt_in_security_message">Confirming your PIN by tapping Enter is more secure than using auto-confirm</string>

<!-- Main Security lock settings --><skip />
<!-- Title for PreferenceScreen to launch picker for security method when there is none [CHAR LIMIT=22] -->
<string name="unlock_set_unlock_launch_picker_title">Screen lock</string>
Expand Down Expand Up @@ -1250,6 +1259,12 @@
other {PIN must be at least # digits}
}</string>

<!-- Hint shown in dialog screen when PIN is too short with Additional text indicating minAutoConfirmLen(eg: 6) digits PIN offer additional security -->
<string name="lockpassword_pin_too_short_autoConfirm_extra_message">{count, plural,
=1 {PIN must contain at least # digit, but a {minAutoConfirmLen}-digit PIN is recommended for added security}
other {PIN must be at least # digits, but a {minAutoConfirmLen}-digit PIN is recommended for added security}
}</string>

<!-- Error shown in popup when password is too long -->
<string name="lockpassword_password_too_long">{count, plural,
=1 {Must be fewer than # character}
Expand Down
6 changes: 6 additions & 0 deletions res/xml/screen_lock_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
android:key="visiblepattern"
android:title="@string/lockpattern_settings_enable_visible_pattern_title" />

<!-- available in pin -->
<SwitchPreference
android:key="auto_pin_confirm"
android:title="@string/lock_screen_auto_pin_confirm_title"
android:summary="@string/lock_screen_auto_pin_confirm_summary" />

<!-- available in pin/pattern/password -->
<com.android.settings.display.TimeoutListPreference
android:key="lock_after_timeout"
Expand Down
70 changes: 68 additions & 2 deletions src/com/android/settings/password/ChooseLockPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.CheckBox;
import android.widget.ImeAwareEditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
Expand Down Expand Up @@ -101,7 +102,9 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ChooseLockPassword extends SettingsActivity {
private static final String TAG = "ChooseLockPassword";
Expand Down Expand Up @@ -223,6 +226,8 @@ public static class ChooseLockPasswordFragment extends InstrumentedFragment
private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";

private static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6;

private LockscreenCredential mCurrentCredential;
private LockscreenCredential mChosenPassword;
private boolean mRequestGatekeeperPassword;
Expand Down Expand Up @@ -255,6 +260,9 @@ public static class ChooseLockPasswordFragment extends InstrumentedFragment
protected FooterButton mSkipOrClearButton;
private FooterButton mNextButton;
private TextView mMessage;
protected CheckBox mAutoPinConfirmOption;
protected TextView mAutoConfirmSecurityMessage;
protected boolean mIsAutoPinConfirmOptionSetManually;

private TextChangedHandler mTextChangedHandler;

Expand Down Expand Up @@ -515,6 +523,16 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
mPasswordEntry.requestFocus();
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);

// Fetch the AutoPinConfirmOption
mAutoPinConfirmOption = view.findViewById(R.id.auto_pin_confirm_enabler);
mAutoConfirmSecurityMessage = view.findViewById(R.id.auto_pin_confirm_security_message);
mIsAutoPinConfirmOptionSetManually = false;
setOnAutoConfirmOptionClickListener();
if (mAutoPinConfirmOption != null) {
mAutoPinConfirmOption.setVisibility(View.GONE);
mAutoPinConfirmOption.setChecked(false);
}

final Activity activity = getActivity();

int currentType = mPasswordEntry.getInputType();
Expand Down Expand Up @@ -808,10 +826,22 @@ String[] convertErrorCodeToMessages() {
R.string.lockpassword_password_requires_nonnumerical));
break;
case TOO_SHORT:
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
String message = StringUtil.getIcuPluralsString(getContext(),
error.requirement,
mIsAlphaMode
? R.string.lockpassword_password_too_short
: R.string.lockpassword_pin_too_short));
: R.string.lockpassword_pin_too_short);
if (mLockPatternUtils.isAutoPinConfirmFeatureAvailable()
&& !mIsAlphaMode
&& error.requirement < MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
Map<String, Object> arguments = new HashMap<>();
arguments.put("count", error.requirement);
arguments.put("minAutoConfirmLen", MIN_AUTO_PIN_REQUIREMENT_LENGTH);
message = StringUtil.getIcuPluralsString(getContext(),
arguments,
R.string.lockpassword_pin_too_short_autoConfirm_extra_message);
}
messages.add(message);
break;
case TOO_SHORT_WHEN_ALL_NUMERIC:
messages.add(
Expand Down Expand Up @@ -864,6 +894,8 @@ protected void updateUi() {
String[] messages = convertErrorCodeToMessages();
// Update the fulfillment of requirements.
mPasswordRequirementAdapter.setRequirements(messages);
// set the visibility of pin_auto_confirm option accordingly
setAutoPinConfirmOption(passwordCompliant, length);
// Enable/Disable the next button accordingly.
setNextEnabled(passwordCompliant);
} else {
Expand Down Expand Up @@ -896,6 +928,36 @@ protected int toVisibility(boolean visibleOrGone) {
return visibleOrGone ? View.VISIBLE : View.GONE;
}

private void setAutoPinConfirmOption(boolean enabled, int length) {
if (!mLockPatternUtils.isAutoPinConfirmFeatureAvailable()
|| mAutoPinConfirmOption == null) {
return;
}
if (enabled && !mIsAlphaMode && isAutoPinConfirmPossible(length)) {
mAutoPinConfirmOption.setVisibility(View.VISIBLE);
mAutoConfirmSecurityMessage.setVisibility(View.VISIBLE);
if (!mIsAutoPinConfirmOptionSetManually) {
mAutoPinConfirmOption.setChecked(length == MIN_AUTO_PIN_REQUIREMENT_LENGTH);
}
} else {
mAutoPinConfirmOption.setVisibility(View.GONE);
mAutoConfirmSecurityMessage.setVisibility(View.GONE);
mAutoPinConfirmOption.setChecked(false);
}
}

private boolean isAutoPinConfirmPossible(int currentPinLength) {
return currentPinLength >= MIN_AUTO_PIN_REQUIREMENT_LENGTH;
}

private void setOnAutoConfirmOptionClickListener() {
if (mAutoPinConfirmOption != null) {
mAutoPinConfirmOption.setOnClickListener((v) -> {
mIsAutoPinConfirmOptionSetManually = true;
});
}
}

private void setHeaderText(String text) {
// Only set the text if it is different than the existing one to avoid announcing again.
if (!TextUtils.isEmpty(mLayout.getHeaderText())
Expand Down Expand Up @@ -951,6 +1013,10 @@ private void startSaveAndFinish() {
}
mSaveAndFinishWorker.start(mLockPatternUtils, mRequestGatekeeperPassword,
mChosenPassword, mCurrentCredential, mUserId);
// update the pin_auto_confirm setting accordingly.
mLockPatternUtils.setAutoPinConfirm(
(mAutoPinConfirmOption != null && mAutoPinConfirmOption.isChecked()),
mUserId);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ protected void updateUi() {
mOptionsButton.setVisibility(
mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
}

// Visibility of auto pin confirm opt-in/out option should always be invisible.
if (mAutoPinConfirmOption != null) {
mAutoPinConfirmOption.setVisibility(View.GONE);
mAutoConfirmSecurityMessage.setVisibility(View.GONE);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.settings.security.screenlock;

import android.content.Context;

import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;

/**
* Preference controller for the pin_auto_confirm setting.
*/
public class AutoPinConfirmPreferenceController extends AbstractPreferenceController implements
PreferenceControllerMixin, Preference.OnPreferenceChangeListener {

private static final String PREF_KEY_PIN_AUTO_CONFIRM = "auto_pin_confirm";
private static final long MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6L;

private final int mUserId;
private final LockPatternUtils mLockPatternUtils;

public AutoPinConfirmPreferenceController(Context context, int userId,
LockPatternUtils lockPatternUtils) {
super(context);
mUserId = userId;
mLockPatternUtils = lockPatternUtils;
}

@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
setPinAutoConfirmSettingState((boolean) newValue);
return true;
}

@Override
public void updateState(Preference preference) {
((TwoStatePreference) preference).setChecked(getPinAutoConfirmSettingState());
}

@Override
public boolean isAvailable() {
return mLockPatternUtils.isAutoPinConfirmFeatureAvailable() && isPinLock()
&& isPinLengthEligibleForAutoConfirmation();
}

@Override
public String getPreferenceKey() {
return PREF_KEY_PIN_AUTO_CONFIRM;
}

private boolean isPinLock() {
return mLockPatternUtils.getCredentialTypeForUser(mUserId)
== LockPatternUtils.CREDENTIAL_TYPE_PIN;
}

private boolean isPinLengthEligibleForAutoConfirmation() {
return mLockPatternUtils.getPinLength(mUserId) >= MIN_AUTO_PIN_REQUIREMENT_LENGTH;
}

private boolean getPinAutoConfirmSettingState() {
return mLockPatternUtils.isAutoPinConfirmEnabled(mUserId);
}

private void setPinAutoConfirmSettingState(boolean state) {
mLockPatternUtils.setAutoPinConfirm(state, mUserId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ private static List<AbstractPreferenceController> buildPreferenceControllers(Con
context, MY_USER_ID, lockPatternUtils));
controllers.add(new LockAfterTimeoutPreferenceController(
context, MY_USER_ID, lockPatternUtils));
controllers.add(new AutoPinConfirmPreferenceController(
context, MY_USER_ID, lockPatternUtils));
controllers.add(new OwnerInfoPreferenceController(context, parent));
return controllers;
}
Expand Down
Loading

0 comments on commit 4c8ad8f

Please sign in to comment.