diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f2c64cabee2..a1d8d8a9193 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3123,6 +3123,10 @@
android:enableOnBackInvokedCallback="false"
android:excludeFromRecents="true" />
+
+
+
+
+
diff --git a/res/drawable/ic_security_pattern_4x4.xml b/res/drawable/ic_security_pattern_4x4.xml
new file mode 100644
index 00000000000..92c580f5e2c
--- /dev/null
+++ b/res/drawable/ic_security_pattern_4x4.xml
@@ -0,0 +1,26 @@
+
+
+
+
diff --git a/res/drawable/ic_security_pattern_5x5.xml b/res/drawable/ic_security_pattern_5x5.xml
new file mode 100644
index 00000000000..7b4dabaad79
--- /dev/null
+++ b/res/drawable/ic_security_pattern_5x5.xml
@@ -0,0 +1,26 @@
+
+
+
+
diff --git a/res/drawable/ic_security_pattern_6x6.xml b/res/drawable/ic_security_pattern_6x6.xml
new file mode 100644
index 00000000000..1861284dbbf
--- /dev/null
+++ b/res/drawable/ic_security_pattern_6x6.xml
@@ -0,0 +1,26 @@
+
+
+
+
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 41a7cbb8c4f..286d50e8fd7 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -35,4 +35,11 @@
You have enabled development settings!
No need, you have already enabled development settings.
+
+
+ 3 \u00d7 3
+ 4 \u00d7 4
+ 5 \u00d7 5
+ 6 \u00d7 6
+ Choose a pattern size
diff --git a/res/values/lineage_styles.xml b/res/values/lineage_styles.xml
new file mode 100644
index 00000000000..1ce2e23597b
--- /dev/null
+++ b/res/values/lineage_styles.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/res/xml/security_settings_pattern_size.xml b/res/xml/security_settings_pattern_size.xml
new file mode 100644
index 00000000000..bb0cb238f2f
--- /dev/null
+++ b/res/xml/security_settings_pattern_size.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index ade56c979ad..24b79e69ae9 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -1109,7 +1109,8 @@ public class ChooseLockPassword extends SettingsActivity {
mUserId);
mSaveAndFinishWorker.start(mLockPatternUtils,
- mChosenPassword, mCurrentCredential, mUserId);
+ mChosenPassword, mCurrentCredential, mUserId,
+ mLockPatternUtils.getLockPatternSize(mUserId));
}
@Override
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 6207aa9feec..2c849b5e96b 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -102,7 +102,8 @@ public class ChooseLockPattern extends SettingsActivity {
private final Intent mIntent;
public IntentBuilder(Context context) {
- mIntent = new Intent(context, ChooseLockPattern.class);
+ mIntent = new Intent(context, ChooseLockPatternSize.class);
+ mIntent.putExtra("className", ChooseLockPattern.class.getName());
mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
}
@@ -219,19 +220,14 @@ public class ChooseLockPattern extends SettingsActivity {
protected FooterButton mSkipOrClearButton;
protected FooterButton mNextButton;
@VisibleForTesting protected LockscreenCredential mChosenPattern;
+ private byte mPatternSize = LockPatternUtils.PATTERN_SIZE_DEFAULT;
private ColorStateList mDefaultHeaderColorList;
private View mSudContent;
/**
* The patten used during the help screen to show how to draw a pattern.
*/
- private final List mAnimatePattern =
- Collections.unmodifiableList(Lists.newArrayList(
- LockPatternView.Cell.of(0, 0),
- LockPatternView.Cell.of(0, 1),
- LockPatternView.Cell.of(1, 1),
- LockPatternView.Cell.of(2, 1)
- ));
+ private List mAnimatePattern;
@Override
public void onActivityResult(int requestCode, int resultCode,
@@ -276,12 +272,13 @@ public class ChooseLockPattern extends SettingsActivity {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
}
- public void onPatternDetected(List pattern) {
+ public void onPatternDetected(List pattern,
+ byte patternSize) {
if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
if (mChosenPattern == null) throw new IllegalStateException(
"null chosen pattern in stage 'need to confirm");
try (LockscreenCredential confirmPattern =
- LockscreenCredential.createPattern(pattern)) {
+ LockscreenCredential.createPattern(pattern, patternSize)) {
if (mChosenPattern.equals(confirmPattern)) {
updateStage(Stage.ChoiceConfirmed);
} else {
@@ -292,7 +289,8 @@ public class ChooseLockPattern extends SettingsActivity {
if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
updateStage(Stage.ChoiceTooShort);
} else {
- mChosenPattern = LockscreenCredential.createPattern(pattern);
+ mChosenPattern = LockscreenCredential.createPattern(
+ pattern, patternSize);
updateStage(Stage.FirstChoiceValid);
}
} else {
@@ -550,6 +548,16 @@ public class ChooseLockPattern extends SettingsActivity {
mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
0);
+ mPatternSize = getActivity().getIntent().getByteExtra("pattern_size",
+ LockPatternUtils.PATTERN_SIZE_DEFAULT);
+ LockPatternView.Cell.updateSize(mPatternSize);
+ mAnimatePattern = Collections.unmodifiableList(Lists.newArrayList(
+ LockPatternView.Cell.of(0, 0, mPatternSize),
+ LockPatternView.Cell.of(0, 1, mPatternSize),
+ LockPatternView.Cell.of(1, 1, mPatternSize),
+ LockPatternView.Cell.of(2, 1, mPatternSize)
+ ));
+
return layout;
}
@@ -564,6 +572,8 @@ public class ChooseLockPattern extends SettingsActivity {
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
mLockPatternView.setFadePattern(false);
mLockPatternView.setClickable(false);
+ mLockPatternView.setLockPatternUtils(mLockPatternUtils);
+ mLockPatternView.setLockPatternSize(mPatternSize);
mFooterText = (TextView) view.findViewById(R.id.footerText);
@@ -610,6 +620,9 @@ public class ChooseLockPattern extends SettingsActivity {
// restore from previous state
mChosenPattern = savedInstanceState.getParcelable(KEY_PATTERN_CHOICE);
mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_PATTERN);
+ mLockPatternView.setPattern(DisplayMode.Correct,
+ LockPatternUtils.byteArrayToPattern(
+ mChosenPattern.getCredential(), mPatternSize));
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
@@ -867,7 +880,7 @@ public class ChooseLockPattern extends SettingsActivity {
}
}
mSaveAndFinishWorker.start(mLockPatternUtils,
- mChosenPattern, mCurrentCredential, mUserId);
+ mChosenPattern, mCurrentCredential, mUserId, mPatternSize);
}
@Override
diff --git a/src/com/android/settings/password/ChooseLockPatternSize.java b/src/com/android/settings/password/ChooseLockPatternSize.java
new file mode 100644
index 00000000000..eed899a16cb
--- /dev/null
+++ b/src/com/android/settings/password/ChooseLockPatternSize.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012-2013 The CyanogenMod 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.password;
+
+import android.content.Intent;
+import android.content.res.Resources.Theme;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.preference.Preference;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SetupWizardUtils;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.utils.SettingsDividerItemDecoration;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+import com.google.android.setupdesign.util.ThemeHelper;
+
+import org.lineageos.internal.logging.LineageMetricsLogger;
+
+public class ChooseLockPatternSize extends SettingsActivity {
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockPatternSizeFragment.class.getName());
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (ChooseLockPatternSizeFragment.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+
+ @Override
+ protected boolean isToolbarEnabled() {
+ return false;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(SetupWizardUtils.getTheme(this, getIntent()));
+ ThemeHelper.trySetDynamicColor(this);
+ super.onCreate(savedInstanceState);
+ findViewById(R.id.content_parent).setFitsSystemWindows(false);
+ }
+
+ public static class ChooseLockPatternSizeFragment extends SettingsPreferenceFragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (!(getActivity() instanceof ChooseLockPatternSize)) {
+ throw new SecurityException("Fragment contained in wrong activity");
+ }
+ addPreferencesFromResource(R.xml.security_settings_pattern_size);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ final String key = preference.getKey();
+
+ byte patternSize;
+ if ("lock_pattern_size_4".equals(key)) {
+ patternSize = 4;
+ } else if ("lock_pattern_size_5".equals(key)) {
+ patternSize = 5;
+ } else if ("lock_pattern_size_6".equals(key)) {
+ patternSize = 6;
+ } else {
+ patternSize = 3;
+ }
+
+ Bundle extras = getActivity().getIntent().getExtras();
+ Intent intent = new Intent();
+ intent.setClassName(getActivity(), extras.getString("className"));
+ intent.putExtras(extras);
+ intent.putExtra("pattern_size", patternSize);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+
+ finish();
+ return true;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
+ layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
+
+ layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
+
+ if (getActivity() != null) {
+ getActivity().setTitle(R.string.lock_settings_picker_pattern_size_message);
+ }
+
+ layout.setHeaderText(R.string.lock_settings_picker_pattern_size_message);
+
+ // Remove the padding on the start of the header text.
+ if (ThemeHelper.shouldApplyMaterialYouStyle(getContext())) {
+ final LinearLayout headerLayout = layout.findManagedViewById(
+ com.google.android.setupdesign.R.id.sud_layout_header);
+ if (headerLayout != null) {
+ headerLayout.setPadding(0, layout.getPaddingTop(), 0,
+ layout.getPaddingBottom());
+ }
+ }
+
+ // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
+ // PreferenceFragment.
+ setDivider(null);
+ }
+
+ @Override
+ public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
+ return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return LineageMetricsLogger.CHOOSE_LOCK_PATTERN_SIZE;
+ }
+ }
+}
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index 91875cc88d6..0f907cd0eb1 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -475,6 +475,9 @@ public final class ChooseLockSettingsHelper {
intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
+ if (userId == LockPatternUtils.USER_FRP) {
+ intent.putExtra("className", ConfirmLockPattern.class.getName());
+ }
Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() :
mActivity.getIntent();
@@ -555,7 +558,9 @@ public final class ChooseLockSettingsHelper {
? ConfirmLockPassword.InternalActivity.class
: ConfirmLockPassword.class);
case KeyguardManager.PATTERN:
- return Optional.of(returnCredentials || forceVerifyPath
+ return Optional.of(userId == LockPatternUtils.USER_FRP
+ ? ChooseLockPatternSize.class
+ : returnCredentials || forceVerifyPath
? ConfirmLockPattern.InternalActivity.class
: ConfirmLockPattern.class);
}
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index ee9e3171dc2..5d0c55ab10a 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -653,7 +653,8 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
mLockPatternUtils,
mRemoteLockscreenValidationFragment.getLockscreenCredential(),
/* currentCredential= */ null,
- mEffectiveUserId);
+ mEffectiveUserId,
+ mLockPatternUtils.getLockPatternSize(mEffectiveUserId));
} else {
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
/* timeoutMs= */ 0, mEffectiveUserId);
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 784e89884b8..93988d82166 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -118,6 +118,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
private DisappearAnimationUtils mDisappearAnimationUtils;
private boolean mIsManagedProfile;
+ private byte mPatternSize;
// required constructor for fragments
public ConfirmLockPatternFragment() {
@@ -144,6 +145,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
0);
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
+ mPatternSize = mLockPatternUtils.getLockPatternSize(mEffectiveUserId);
// make it so unhandled touch events within the unlock screen go to the
// lock pattern view.
@@ -158,6 +160,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mDetailsText = intent.getCharSequenceExtra(
ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
mCheckBoxLabel = intent.getCharSequenceExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
+ mPatternSize = intent.getByteExtra("pattern_size", mPatternSize);
}
if (TextUtils.isEmpty(mHeaderText) && mIsManagedProfile) {
mHeaderText = mDevicePolicyManager.getOrganizationNameForUser(mUserId);
@@ -165,6 +168,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
mEffectiveUserId));
+ mLockPatternView.setLockPatternSize(mPatternSize);
mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
mLockPatternView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
@@ -506,14 +510,15 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
}
- public void onPatternDetected(List pattern) {
+ public void onPatternDetected(List pattern, byte patternSize) {
if (mPendingLockCheck != null || mDisappearing) {
return;
}
mLockPatternView.setEnabled(false);
- final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
+ final LockscreenCredential credential = LockscreenCredential.createPattern(pattern,
+ patternSize);
if (mRemoteValidation) {
validateGuess(credential);
@@ -652,7 +657,8 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mLockPatternUtils,
mRemoteLockscreenValidationFragment.getLockscreenCredential(),
/* currentCredential= */ null,
- mEffectiveUserId);
+ mEffectiveUserId,
+ mLockPatternUtils.getLockPatternSize(mEffectiveUserId));
} else {
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
/* timeoutMs= */ 0, mEffectiveUserId);
diff --git a/src/com/android/settings/password/SaveAndFinishWorker.java b/src/com/android/settings/password/SaveAndFinishWorker.java
index 40054b77645..5592071e7a4 100644
--- a/src/com/android/settings/password/SaveAndFinishWorker.java
+++ b/src/com/android/settings/password/SaveAndFinishWorker.java
@@ -53,6 +53,7 @@ public class SaveAndFinishWorker extends Fragment {
private LockscreenCredential mUnificationProfileCredential;
private LockscreenCredential mChosenCredential;
private LockscreenCredential mCurrentCredential;
+ private byte mPatternSize;
private boolean mBlocking;
@@ -76,9 +77,10 @@ public class SaveAndFinishWorker extends Fragment {
@VisibleForTesting
void prepare(LockPatternUtils utils, LockscreenCredential chosenCredential,
- LockscreenCredential currentCredential, int userId) {
+ LockscreenCredential currentCredential, int userId, byte patternSize) {
mUtils = utils;
mUserId = userId;
+ mPatternSize = patternSize;
// This will be a no-op for non managed profiles.
mWasSecureBefore = mUtils.isSecure(mUserId);
mFinished = false;
@@ -90,8 +92,8 @@ public class SaveAndFinishWorker extends Fragment {
}
public void start(LockPatternUtils utils, LockscreenCredential chosenCredential,
- LockscreenCredential currentCredential, int userId) {
- prepare(utils, chosenCredential, currentCredential, userId);
+ LockscreenCredential currentCredential, int userId, byte patternSize) {
+ prepare(utils, chosenCredential, currentCredential, userId, patternSize);
if (mBlocking) {
finish(saveAndVerifyInBackground().second);
} else {
@@ -107,6 +109,7 @@ public class SaveAndFinishWorker extends Fragment {
@VisibleForTesting
Pair saveAndVerifyInBackground() {
final int userId = mUserId;
+ mUtils.setLockPatternSize(mPatternSize, userId);
try {
if (!mUtils.setLockCredential(mChosenCredential, mCurrentCredential, userId)) {
return Pair.create(false, null);
diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java
index 794104912e8..df49cdbd902 100644
--- a/src/com/android/settings/password/SetupChooseLockPattern.java
+++ b/src/com/android/settings/password/SetupChooseLockPattern.java
@@ -45,7 +45,8 @@ import com.google.android.setupcompat.util.WizardManagerHelper;
public class SetupChooseLockPattern extends ChooseLockPattern {
public static Intent modifyIntentForSetup(Context context, Intent chooseLockPatternIntent) {
- chooseLockPatternIntent.setClass(context, SetupChooseLockPattern.class);
+ chooseLockPatternIntent.setClass(context, ChooseLockPatternSize.class);
+ chooseLockPatternIntent.putExtra("className", SetupChooseLockPattern.class.getName());
return chooseLockPatternIntent;
}