1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.password; 18 19 import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; 20 import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY; 21 22 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; 23 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; 24 25 import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.graphics.Color; 29 import android.graphics.drawable.ColorDrawable; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.UserHandle; 33 import android.view.LayoutInflater; 34 import android.view.View; 35 import android.view.ViewGroup; 36 37 import androidx.fragment.app.Fragment; 38 import androidx.preference.Preference; 39 import androidx.preference.PreferenceFragmentCompat; 40 import androidx.recyclerview.widget.RecyclerView; 41 42 import com.android.internal.widget.LockPatternUtils; 43 import com.android.settings.R; 44 import com.android.settings.SetupWizardUtils; 45 import com.android.settings.utils.SettingsDividerItemDecoration; 46 47 import com.google.android.setupcompat.util.WizardManagerHelper; 48 import com.google.android.setupdesign.GlifPreferenceLayout; 49 import com.google.android.setupdesign.util.ThemeHelper; 50 51 import org.jetbrains.annotations.NotNull; 52 53 /** 54 * Setup Wizard's version of ChooseLockGeneric screen. It inherits the logic and basic structure 55 * from ChooseLockGeneric class, and should remain similar to that behaviorally. This class should 56 * only overload base methods for minor theme and behavior differences specific to Setup Wizard. 57 * Other changes should be done to ChooseLockGeneric class instead and let this class inherit 58 * those changes. 59 */ 60 // TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only 61 public class SetupChooseLockGeneric extends ChooseLockGeneric { 62 63 private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later"; 64 65 @Override isValidFragment(String fragmentName)66 protected boolean isValidFragment(String fragmentName) { 67 return SetupChooseLockGenericFragment.class.getName().equals(fragmentName); 68 } 69 70 @Override getFragmentClass()71 /* package */ Class<? extends PreferenceFragmentCompat> getFragmentClass() { 72 return SetupChooseLockGenericFragment.class; 73 } 74 75 @Override onCreate(Bundle savedInstance)76 protected void onCreate(Bundle savedInstance) { 77 setTheme(SetupWizardUtils.getTheme(this, getIntent())); 78 ThemeHelper.trySetDynamicColor(this); 79 super.onCreate(savedInstance); 80 81 if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) { 82 IBinder activityToken = getActivityToken(); 83 boolean hasPermission = PasswordUtils.isCallingAppPermitted( 84 this, activityToken, REQUEST_PASSWORD_COMPLEXITY); 85 if (!hasPermission) { 86 PasswordUtils.crashCallingApplication(activityToken, 87 "Must have permission " + REQUEST_PASSWORD_COMPLEXITY 88 + " to use extra " + EXTRA_PASSWORD_COMPLEXITY, 89 MissingRequestPasswordComplexityPermissionException.TYPE_ID); 90 finish(); 91 return; 92 } 93 } 94 95 findViewById(R.id.content_parent).setFitsSystemWindows(false); 96 } 97 98 @Override isToolbarEnabled()99 protected boolean isToolbarEnabled() { 100 // Hide the action bar from this page. 101 return false; 102 } 103 104 public static class SetupChooseLockGenericFragment extends ChooseLockGenericFragment { 105 106 public static final String EXTRA_PASSWORD_QUALITY = ":settings:password_quality"; 107 108 @Override onViewCreated(View view, Bundle savedInstanceState)109 public void onViewCreated(View view, Bundle savedInstanceState) { 110 super.onViewCreated(view, savedInstanceState); 111 112 GlifPreferenceLayout layout = (GlifPreferenceLayout) view; 113 layout.setDescriptionText(loadDescriptionText()); 114 layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext())); 115 layout.setDividerInset(getContext().getResources().getDimensionPixelSize( 116 R.dimen.sud_items_glif_text_divider_inset)); 117 118 layout.setIcon(getContext().getDrawable(R.drawable.ic_lock)); 119 120 int titleResource = isForBiometric() ? 121 R.string.lock_settings_picker_title : R.string.setup_lock_settings_picker_title; 122 if (getActivity() != null) { 123 getActivity().setTitle(titleResource); 124 } 125 126 layout.setHeaderText(titleResource); 127 // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in 128 // PreferenceFragment. 129 setDivider(null); 130 } 131 132 @Override addHeaderView()133 protected void addHeaderView() { 134 // The original logic has been moved to onViewCreated and 135 // uses GlifLayout#setDescriptionText instead, 136 // keep empty body here since we won't call super method. 137 } 138 139 @Override onActivityResult(int requestCode, int resultCode, Intent data)140 public void onActivityResult(int requestCode, int resultCode, Intent data) { 141 if (data == null) { 142 data = new Intent(); 143 } 144 // Add the password quality extra to the intent data that will be sent back for 145 // Setup Wizard. 146 LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity()); 147 data.putExtra(EXTRA_PASSWORD_QUALITY, 148 lockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId())); 149 150 super.onActivityResult(requestCode, resultCode, data); 151 } 152 153 @Override onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)154 public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, 155 Bundle savedInstanceState) { 156 GlifPreferenceLayout layout = (GlifPreferenceLayout) parent; 157 return layout.onCreateRecyclerView(inflater, parent, savedInstanceState); 158 } 159 160 @Override canRunBeforeDeviceProvisioned()161 protected boolean canRunBeforeDeviceProvisioned() { 162 return true; 163 } 164 165 @Override getInternalActivityClass()166 protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() { 167 return SetupChooseLockGeneric.InternalActivity.class; 168 } 169 170 @Override alwaysHideInsecureScreenLockTypes()171 protected boolean alwaysHideInsecureScreenLockTypes() { 172 // At this part of the flow, the user has already indicated they want to add a pin, 173 // pattern or password, so don't show "None" or "Slide". We disable them here. 174 // This only happens for setup wizard. 175 return true; 176 } 177 178 @Override addPreferences()179 protected void addPreferences() { 180 if (isForBiometric()) { 181 super.addPreferences(); 182 } else { 183 addPreferencesFromResource(R.xml.setup_security_settings_picker); 184 } 185 } 186 187 @Override onPreferenceTreeClick(Preference preference)188 public boolean onPreferenceTreeClick(Preference preference) { 189 final String key = preference.getKey(); 190 if (KEY_UNLOCK_SET_DO_LATER.equals(key)) { 191 // show warning. 192 final Intent intent = getActivity().getIntent(); 193 SetupSkipDialog dialog = SetupSkipDialog.newInstance( 194 CREDENTIAL_TYPE_NONE, 195 intent.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false), 196 /* forFingerprint= */ false, 197 /* forFace= */ false, 198 /* forBiometrics= */ false, 199 WizardManagerHelper.isAnySetupWizard(intent) 200 ); 201 dialog.show(getFragmentManager()); 202 return true; 203 } 204 return super.onPreferenceTreeClick(preference); 205 } 206 207 @Override getLockPasswordIntent(int quality)208 protected Intent getLockPasswordIntent(int quality) { 209 final Intent intent = SetupChooseLockPassword.modifyIntentForSetup( 210 getContext(), super.getLockPasswordIntent(quality)); 211 SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); 212 return intent; 213 } 214 215 @Override getLockPatternIntent()216 protected Intent getLockPatternIntent() { 217 final Intent intent = SetupChooseLockPattern.modifyIntentForSetup( 218 getContext(), super.getLockPatternIntent()); 219 SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); 220 return intent; 221 } 222 223 @Override getBiometricEnrollIntent(Context context)224 protected Intent getBiometricEnrollIntent(Context context) { 225 final Intent intent = super.getBiometricEnrollIntent(context); 226 SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); 227 return intent; 228 } 229 isForBiometric()230 private boolean isForBiometric() { 231 return mForFingerprint || mForFace || mForBiometrics; 232 } 233 loadDescriptionText()234 String loadDescriptionText() { 235 return getString(isForBiometric() 236 ? R.string.lock_settings_picker_biometrics_added_security_message 237 : R.string.setup_lock_settings_picker_message); 238 } 239 } 240 241 public static class InternalActivity extends ChooseLockGeneric.InternalActivity { 242 @Override onCreate(Bundle savedState)243 protected void onCreate(Bundle savedState) { 244 setTheme(SetupWizardUtils.getTheme(this, getIntent())); 245 ThemeHelper.trySetDynamicColor(this); 246 super.onCreate(savedState); 247 } 248 249 @Override isValidFragment(String fragmentName)250 protected boolean isValidFragment(String fragmentName) { 251 return InternalSetupChooseLockGenericFragment.class.getName().equals(fragmentName); 252 } 253 254 @Override getFragmentClass()255 /* package */ Class<? extends Fragment> getFragmentClass() { 256 return InternalSetupChooseLockGenericFragment.class; 257 } 258 259 public static class InternalSetupChooseLockGenericFragment 260 extends ChooseLockGenericFragment { 261 @Override canRunBeforeDeviceProvisioned()262 protected boolean canRunBeforeDeviceProvisioned() { 263 return true; 264 } 265 266 @Override onViewCreated(@otNull View view, Bundle savedInstanceState)267 public void onViewCreated(@NotNull View view, Bundle savedInstanceState) { 268 super.onViewCreated(view, savedInstanceState); 269 270 GlifPreferenceLayout layout = (GlifPreferenceLayout) view; 271 int titleResource = R.string.lock_settings_picker_new_lock_title; 272 273 layout.setHeaderText(titleResource); 274 setDivider(new ColorDrawable(Color.TRANSPARENT)); 275 setDividerHeight(0); 276 getHeaderView().setVisible(false); 277 } 278 279 @Override getLockPasswordIntent(int quality)280 protected Intent getLockPasswordIntent(int quality) { 281 final Intent intent = SetupChooseLockPassword.modifyIntentForSetup( 282 getContext(), super.getLockPasswordIntent(quality)); 283 SetupWizardUtils.copySetupExtras(getIntent(), intent); 284 return intent; 285 } 286 287 @Override getLockPatternIntent()288 protected Intent getLockPatternIntent() { 289 final Intent intent = SetupChooseLockPattern.modifyIntentForSetup( 290 getContext(), super.getLockPatternIntent()); 291 SetupWizardUtils.copySetupExtras(getIntent(), intent); 292 return intent; 293 } 294 295 @Override getBiometricEnrollIntent(Context context)296 protected Intent getBiometricEnrollIntent(Context context) { 297 final Intent intent = super.getBiometricEnrollIntent(context); 298 SetupWizardUtils.copySetupExtras(getIntent(), intent); 299 return intent; 300 } 301 302 @Override onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)303 public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, 304 Bundle savedInstanceState) { 305 GlifPreferenceLayout layout = (GlifPreferenceLayout) parent; 306 return layout.onCreateRecyclerView(inflater, parent, savedInstanceState); 307 } 308 } 309 } 310 } 311