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.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
23 
24 import android.app.admin.DevicePolicyManager;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.os.UserHandle;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.LinearLayout;
35 
36 import androidx.fragment.app.Fragment;
37 import androidx.preference.Preference;
38 import androidx.preference.PreferenceFragmentCompat;
39 import androidx.recyclerview.widget.RecyclerView;
40 
41 import com.android.internal.widget.LockPatternUtils;
42 import com.android.settings.R;
43 import com.android.settings.SetupEncryptionInterstitial;
44 import com.android.settings.SetupWizardUtils;
45 import com.android.settings.biometrics.BiometricEnrollActivity;
46 import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
47 import com.android.settings.utils.SettingsDividerItemDecoration;
48 
49 import com.google.android.setupdesign.GlifPreferenceLayout;
50 
51 /**
52  * Setup Wizard's version of ChooseLockGeneric screen. It inherits the logic and basic structure
53  * from ChooseLockGeneric class, and should remain similar to that behaviorally. This class should
54  * only overload base methods for minor theme and behavior differences specific to Setup Wizard.
55  * Other changes should be done to ChooseLockGeneric class instead and let this class inherit
56  * those changes.
57  */
58 // TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only
59 public class SetupChooseLockGeneric extends ChooseLockGeneric {
60 
61     private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
62 
63     @Override
isValidFragment(String fragmentName)64     protected boolean isValidFragment(String fragmentName) {
65         return SetupChooseLockGenericFragment.class.getName().equals(fragmentName);
66     }
67 
68     @Override
getFragmentClass()69     /* package */ Class<? extends PreferenceFragmentCompat> getFragmentClass() {
70         return SetupChooseLockGenericFragment.class;
71     }
72 
73     @Override
onApplyThemeResource(Resources.Theme theme, int resid, boolean first)74     protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
75         resid = SetupWizardUtils.getTheme(getIntent());
76         super.onApplyThemeResource(theme, resid, first);
77     }
78 
79     @Override
onCreate(Bundle savedInstance)80     protected void onCreate(Bundle savedInstance) {
81         super.onCreate(savedInstance);
82 
83         if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
84             IBinder activityToken = getActivityToken();
85             boolean hasPermission = PasswordUtils.isCallingAppPermitted(
86                     this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
87             if (!hasPermission) {
88                 PasswordUtils.crashCallingApplication(activityToken,
89                         "Must have permission " + REQUEST_PASSWORD_COMPLEXITY
90                                 + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
91                 finish();
92                 return;
93             }
94         }
95 
96         findViewById(R.id.content_parent).setFitsSystemWindows(false);
97     }
98 
99     public static class SetupChooseLockGenericFragment extends ChooseLockGenericFragment {
100 
101         public static final String EXTRA_PASSWORD_QUALITY = ":settings:password_quality";
102 
103         @Override
onViewCreated(View view, Bundle savedInstanceState)104         public void onViewCreated(View view, Bundle savedInstanceState) {
105             super.onViewCreated(view, savedInstanceState);
106 
107             GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
108             layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
109             layout.setDividerInset(getContext().getResources().getDimensionPixelSize(
110                     R.dimen.sud_items_glif_text_divider_inset));
111 
112             layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
113 
114             int titleResource = isForBiometric() ?
115                     R.string.lock_settings_picker_title : R.string.setup_lock_settings_picker_title;
116             if (getActivity() != null) {
117                 getActivity().setTitle(titleResource);
118             }
119 
120             layout.setHeaderText(titleResource);
121             // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
122             // PreferenceFragment.
123             setDivider(null);
124         }
125 
126         @Override
addHeaderView()127         protected void addHeaderView() {
128             if (isForBiometric()) {
129                 setHeaderView(R.layout.setup_choose_lock_generic_biometrics_header);
130             } else {
131                 setHeaderView(R.layout.setup_choose_lock_generic_header);
132             }
133         }
134 
135         @Override
onActivityResult(int requestCode, int resultCode, Intent data)136         public void onActivityResult(int requestCode, int resultCode, Intent data) {
137             if (data == null) {
138                 data = new Intent();
139             }
140             // Add the password quality extra to the intent data that will be sent back for
141             // Setup Wizard.
142             LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
143             data.putExtra(EXTRA_PASSWORD_QUALITY,
144                     lockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId()));
145 
146             super.onActivityResult(requestCode, resultCode, data);
147         }
148 
149         @Override
onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)150         public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
151                 Bundle savedInstanceState) {
152             GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
153             return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
154         }
155 
156         @Override
canRunBeforeDeviceProvisioned()157         protected boolean canRunBeforeDeviceProvisioned() {
158             return true;
159         }
160 
161         @Override
getInternalActivityClass()162         protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
163             return SetupChooseLockGeneric.InternalActivity.class;
164         }
165 
166         /***
167          * Disables preferences that are less secure than required quality and shows only secure
168          * screen lock options here.
169          *
170          * @param quality the requested quality.
171          */
172         @Override
disableUnusablePreferences(final int quality, boolean hideDisabled)173         protected void disableUnusablePreferences(final int quality, boolean hideDisabled) {
174             // At this part of the flow, the user has already indicated they want to add a pin,
175             // pattern or password, so don't show "None" or "Slide". We disable them here and set
176             // the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard.
177             // We do the following max check here since the device may already have a Device Admin
178             // installed with a policy we need to honor.
179             final int newQuality = Math.max(quality,
180                     DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
181             super.disableUnusablePreferencesImpl(newQuality, true /* hideDisabled */);
182         }
183 
184         @Override
addPreferences()185         protected void addPreferences() {
186             if (isForBiometric()) {
187                 super.addPreferences();
188             } else {
189                 addPreferencesFromResource(R.xml.setup_security_settings_picker);
190             }
191         }
192 
193         @Override
onPreferenceTreeClick(Preference preference)194         public boolean onPreferenceTreeClick(Preference preference) {
195             final String key = preference.getKey();
196             if (KEY_UNLOCK_SET_DO_LATER.equals(key)) {
197                 // show warning.
198                 SetupSkipDialog dialog = SetupSkipDialog.newInstance(
199                         getActivity().getIntent()
200                                 .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
201                         /* isPatternMode= */ false,
202                         /* isAlphaMode= */ false,
203                         /* isFingerprintSupported= */ false,
204                         /* isFaceSupported= */ false
205                 );
206                 dialog.show(getFragmentManager());
207                 return true;
208             }
209             return super.onPreferenceTreeClick(preference);
210         }
211 
212         @Override
getLockPasswordIntent(int quality)213         protected Intent getLockPasswordIntent(int quality) {
214             final Intent intent = SetupChooseLockPassword.modifyIntentForSetup(
215                     getContext(), super.getLockPasswordIntent(quality));
216             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
217             return intent;
218         }
219 
220         @Override
getLockPatternIntent()221         protected Intent getLockPatternIntent() {
222             final Intent intent = SetupChooseLockPattern.modifyIntentForSetup(
223                     getContext(), super.getLockPatternIntent());
224             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
225             return intent;
226         }
227 
228         @Override
getEncryptionInterstitialIntent(Context context, int quality, boolean required, Intent unlockMethodIntent)229         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
230                 boolean required, Intent unlockMethodIntent) {
231             Intent intent = SetupEncryptionInterstitial.createStartIntent(context, quality,
232                     required, unlockMethodIntent);
233             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
234             return intent;
235         }
236 
237         @Override
getBiometricEnrollIntent(Context context)238         protected Intent getBiometricEnrollIntent(Context context) {
239             final Intent intent = super.getBiometricEnrollIntent(context);
240             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
241             return intent;
242         }
243 
isForBiometric()244         private boolean isForBiometric() {
245             return mForFingerprint || mForFace;
246         }
247     }
248 
249     public static class InternalActivity extends ChooseLockGeneric.InternalActivity {
250         @Override
isValidFragment(String fragmentName)251         protected boolean isValidFragment(String fragmentName) {
252             return InternalSetupChooseLockGenericFragment.class.getName().equals(fragmentName);
253         }
254 
255         @Override
getFragmentClass()256         /* package */ Class<? extends Fragment> getFragmentClass() {
257             return InternalSetupChooseLockGenericFragment.class;
258         }
259 
260         public static class InternalSetupChooseLockGenericFragment
261                 extends ChooseLockGenericFragment {
262             @Override
canRunBeforeDeviceProvisioned()263             protected boolean canRunBeforeDeviceProvisioned() {
264                 return true;
265             }
266         }
267     }
268 }
269