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.RemoteServiceException.MissingRequestPasswordComplexityPermissionException;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.Bundle;
28 import android.os.IBinder;
29 import android.os.UserHandle;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 
34 import androidx.fragment.app.Fragment;
35 import androidx.preference.Preference;
36 import androidx.preference.PreferenceFragmentCompat;
37 import androidx.recyclerview.widget.RecyclerView;
38 
39 import com.android.internal.widget.LockPatternUtils;
40 import com.android.settings.R;
41 import com.android.settings.SetupEncryptionInterstitial;
42 import com.android.settings.SetupWizardUtils;
43 import com.android.settings.utils.SettingsDividerItemDecoration;
44 
45 import com.google.android.setupdesign.GlifPreferenceLayout;
46 import com.google.android.setupdesign.util.ThemeHelper;
47 
48 /**
49  * Setup Wizard's version of ChooseLockGeneric screen. It inherits the logic and basic structure
50  * from ChooseLockGeneric class, and should remain similar to that behaviorally. This class should
51  * only overload base methods for minor theme and behavior differences specific to Setup Wizard.
52  * Other changes should be done to ChooseLockGeneric class instead and let this class inherit
53  * those changes.
54  */
55 // TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only
56 public class SetupChooseLockGeneric extends ChooseLockGeneric {
57 
58     private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
59 
60     @Override
isValidFragment(String fragmentName)61     protected boolean isValidFragment(String fragmentName) {
62         return SetupChooseLockGenericFragment.class.getName().equals(fragmentName);
63     }
64 
65     @Override
getFragmentClass()66     /* package */ Class<? extends PreferenceFragmentCompat> getFragmentClass() {
67         return SetupChooseLockGenericFragment.class;
68     }
69 
70     @Override
onCreate(Bundle savedInstance)71     protected void onCreate(Bundle savedInstance) {
72         setTheme(SetupWizardUtils.getTheme(this, getIntent()));
73         ThemeHelper.trySetDynamicColor(this);
74         super.onCreate(savedInstance);
75 
76         if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
77             IBinder activityToken = getActivityToken();
78             boolean hasPermission = PasswordUtils.isCallingAppPermitted(
79                     this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
80             if (!hasPermission) {
81                 PasswordUtils.crashCallingApplication(activityToken,
82                         "Must have permission " + REQUEST_PASSWORD_COMPLEXITY
83                                 + " to use extra " + EXTRA_PASSWORD_COMPLEXITY,
84                         MissingRequestPasswordComplexityPermissionException.TYPE_ID);
85                 finish();
86                 return;
87             }
88         }
89 
90         findViewById(R.id.content_parent).setFitsSystemWindows(false);
91     }
92 
93     @Override
isToolbarEnabled()94     protected boolean isToolbarEnabled() {
95         // Hide the action bar from this page.
96         return 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         @Override
alwaysHideInsecureScreenLockTypes()167         protected boolean alwaysHideInsecureScreenLockTypes() {
168             // At this part of the flow, the user has already indicated they want to add a pin,
169             // pattern or password, so don't show "None" or "Slide". We disable them here.
170             // This only happens for setup wizard.
171             return true;
172         }
173 
174         @Override
addPreferences()175         protected void addPreferences() {
176             if (isForBiometric()) {
177                 super.addPreferences();
178             } else {
179                 addPreferencesFromResource(R.xml.setup_security_settings_picker);
180             }
181         }
182 
183         @Override
onPreferenceTreeClick(Preference preference)184         public boolean onPreferenceTreeClick(Preference preference) {
185             final String key = preference.getKey();
186             if (KEY_UNLOCK_SET_DO_LATER.equals(key)) {
187                 // show warning.
188                 SetupSkipDialog dialog = SetupSkipDialog.newInstance(
189                         getActivity().getIntent()
190                                 .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
191                         /* isPatternMode= */ false,
192                         /* isAlphaMode= */ false,
193                         /* forFingerprint= */ false,
194                         /* forFace= */ false,
195                         /* forBiometrics= */ false
196                 );
197                 dialog.show(getFragmentManager());
198                 return true;
199             }
200             return super.onPreferenceTreeClick(preference);
201         }
202 
203         @Override
getLockPasswordIntent(int quality)204         protected Intent getLockPasswordIntent(int quality) {
205             final Intent intent = SetupChooseLockPassword.modifyIntentForSetup(
206                     getContext(), super.getLockPasswordIntent(quality));
207             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
208             return intent;
209         }
210 
211         @Override
getLockPatternIntent()212         protected Intent getLockPatternIntent() {
213             final Intent intent = SetupChooseLockPattern.modifyIntentForSetup(
214                     getContext(), super.getLockPatternIntent());
215             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
216             return intent;
217         }
218 
219         @Override
getEncryptionInterstitialIntent(Context context, int quality, boolean required, Intent unlockMethodIntent)220         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
221                 boolean required, Intent unlockMethodIntent) {
222             Intent intent = SetupEncryptionInterstitial.createStartIntent(context, quality,
223                     required, unlockMethodIntent);
224             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
225             return intent;
226         }
227 
228         @Override
getBiometricEnrollIntent(Context context)229         protected Intent getBiometricEnrollIntent(Context context) {
230             final Intent intent = super.getBiometricEnrollIntent(context);
231             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
232             return intent;
233         }
234 
isForBiometric()235         private boolean isForBiometric() {
236             return mForFingerprint || mForFace || mForBiometrics;
237         }
238     }
239 
240     public static class InternalActivity extends ChooseLockGeneric.InternalActivity {
241         @Override
isValidFragment(String fragmentName)242         protected boolean isValidFragment(String fragmentName) {
243             return InternalSetupChooseLockGenericFragment.class.getName().equals(fragmentName);
244         }
245 
246         @Override
getFragmentClass()247         /* package */ Class<? extends Fragment> getFragmentClass() {
248             return InternalSetupChooseLockGenericFragment.class;
249         }
250 
251         public static class InternalSetupChooseLockGenericFragment
252                 extends ChooseLockGenericFragment {
253             @Override
canRunBeforeDeviceProvisioned()254             protected boolean canRunBeforeDeviceProvisioned() {
255                 return true;
256             }
257         }
258     }
259 }
260