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         setTheme(R.style.SettingsPreferenceTheme_SetupWizard);
79         ThemeHelper.trySetDynamicColor(this);
80         super.onCreate(savedInstance);
81 
82         if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
83             IBinder activityToken = getActivityToken();
84             boolean hasPermission = PasswordUtils.isCallingAppPermitted(
85                     this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
86             if (!hasPermission) {
87                 PasswordUtils.crashCallingApplication(activityToken,
88                         "Must have permission " + REQUEST_PASSWORD_COMPLEXITY
89                                 + " to use extra " + EXTRA_PASSWORD_COMPLEXITY,
90                         MissingRequestPasswordComplexityPermissionException.TYPE_ID);
91                 finish();
92                 return;
93             }
94         }
95 
96         findViewById(R.id.content_parent).setFitsSystemWindows(false);
97     }
98 
99     @Override
isToolbarEnabled()100     protected boolean isToolbarEnabled() {
101         // Hide the action bar from this page.
102         return false;
103     }
104 
105     public static class SetupChooseLockGenericFragment extends ChooseLockGenericFragment {
106 
107         public static final String EXTRA_PASSWORD_QUALITY = ":settings:password_quality";
108 
109         @Override
onViewCreated(View view, Bundle savedInstanceState)110         public void onViewCreated(View view, Bundle savedInstanceState) {
111             super.onViewCreated(view, savedInstanceState);
112 
113             GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
114             layout.setDescriptionText(loadDescriptionText());
115             layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
116             layout.setDividerInset(getContext().getResources().getDimensionPixelSize(
117                     com.google.android.setupdesign.R.dimen.sud_items_glif_text_divider_inset));
118 
119             layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
120 
121             int titleResource = isForBiometric() ?
122                     R.string.lock_settings_picker_title : R.string.setup_lock_settings_picker_title;
123             if (getActivity() != null) {
124                 getActivity().setTitle(titleResource);
125             }
126 
127             layout.setHeaderText(titleResource);
128             // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
129             // PreferenceFragment.
130             setDivider(null);
131         }
132 
133         @Override
addHeaderView()134         protected void addHeaderView() {
135             // The original logic has been moved to onViewCreated and
136             // uses GlifLayout#setDescriptionText instead,
137             // keep empty body here since we won't call super method.
138         }
139 
140         @Override
onActivityResult(int requestCode, int resultCode, Intent data)141         public void onActivityResult(int requestCode, int resultCode, Intent data) {
142             if (data == null) {
143                 data = new Intent();
144             }
145             // Add the password quality extra to the intent data that will be sent back for
146             // Setup Wizard.
147             LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
148             data.putExtra(EXTRA_PASSWORD_QUALITY,
149                     lockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId()));
150 
151             super.onActivityResult(requestCode, resultCode, data);
152         }
153 
154         @Override
onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)155         public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
156                 Bundle savedInstanceState) {
157             GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
158             return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
159         }
160 
161         @Override
canRunBeforeDeviceProvisioned()162         protected boolean canRunBeforeDeviceProvisioned() {
163             return true;
164         }
165 
166         @Override
getInternalActivityClass()167         protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
168             return SetupChooseLockGeneric.InternalActivity.class;
169         }
170 
171         @Override
alwaysHideInsecureScreenLockTypes()172         protected boolean alwaysHideInsecureScreenLockTypes() {
173             // At this part of the flow, the user has already indicated they want to add a pin,
174             // pattern or password, so don't show "None" or "Slide". We disable them here.
175             // This only happens for setup wizard.
176             return true;
177         }
178 
179         @Override
addPreferences()180         protected void addPreferences() {
181             if (isForBiometric()) {
182                 super.addPreferences();
183             } else {
184                 addPreferencesFromResource(R.xml.setup_security_settings_picker);
185             }
186         }
187 
188         @Override
onPreferenceTreeClick(Preference preference)189         public boolean onPreferenceTreeClick(Preference preference) {
190             final String key = preference.getKey();
191             if (KEY_UNLOCK_SET_DO_LATER.equals(key)) {
192                 // show warning.
193                 final Intent intent = getActivity().getIntent();
194                 SetupSkipDialog dialog = SetupSkipDialog.newInstance(
195                         CREDENTIAL_TYPE_NONE,
196                         intent.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
197                         /* forFingerprint= */ false,
198                         /* forFace= */ false,
199                         /* forBiometrics= */ false,
200                         WizardManagerHelper.isAnySetupWizard(intent)
201                 );
202                 dialog.show(getFragmentManager());
203                 return true;
204             }
205             return super.onPreferenceTreeClick(preference);
206         }
207 
208         @Override
getLockPasswordIntent(int quality)209         protected Intent getLockPasswordIntent(int quality) {
210             final Intent intent = SetupChooseLockPassword.modifyIntentForSetup(
211                     getContext(), super.getLockPasswordIntent(quality));
212             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
213             return intent;
214         }
215 
216         @Override
getLockPatternIntent()217         protected Intent getLockPatternIntent() {
218             final Intent intent = SetupChooseLockPattern.modifyIntentForSetup(
219                     getContext(), super.getLockPatternIntent());
220             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
221             return intent;
222         }
223 
224         @Override
getBiometricEnrollIntent(Context context)225         protected Intent getBiometricEnrollIntent(Context context) {
226             final Intent intent = super.getBiometricEnrollIntent(context);
227             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
228             return intent;
229         }
230 
isForBiometric()231         private boolean isForBiometric() {
232             return mForFingerprint || mForFace || mForBiometrics;
233         }
234 
loadDescriptionText()235         String loadDescriptionText() {
236             return getString(isForBiometric()
237                     ? R.string.lock_settings_picker_biometrics_added_security_message
238                     : R.string.setup_lock_settings_picker_message);
239         }
240     }
241 
242     public static class InternalActivity extends ChooseLockGeneric.InternalActivity {
243         @Override
onCreate(Bundle savedState)244         protected void onCreate(Bundle savedState) {
245             setTheme(SetupWizardUtils.getTheme(this, getIntent()));
246             ThemeHelper.trySetDynamicColor(this);
247             super.onCreate(savedState);
248         }
249 
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             @Override
onViewCreated(@otNull View view, Bundle savedInstanceState)268             public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
269                 super.onViewCreated(view, savedInstanceState);
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