1 /*
2  * Copyright (C) 2016 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.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
21 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
22 import static android.app.admin.DevicePolicyManager.EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY;
23 import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
24 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
25 
26 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
27 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
28 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
29 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
30 
31 import android.app.Activity;
32 import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException;
33 import android.app.admin.DevicePolicyManager;
34 import android.app.admin.DevicePolicyManager.PasswordComplexity;
35 import android.app.admin.PasswordMetrics;
36 import android.app.settings.SettingsEnums;
37 import android.content.ComponentName;
38 import android.content.Intent;
39 import android.os.Bundle;
40 import android.os.IBinder;
41 import android.util.Log;
42 
43 import com.android.settings.overlay.FeatureFactory;
44 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
45 
46 import com.google.android.setupcompat.util.WizardManagerHelper;
47 
48 import java.util.List;
49 
50 /**
51  * Trampolines {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and
52  * {@link DevicePolicyManager#ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} intent to the appropriate UI
53  * activity for handling set new password.
54  */
55 public class SetNewPasswordActivity extends Activity implements SetNewPasswordController.Ui {
56     private static final String TAG = "SetNewPasswordActivity";
57     private String mNewPasswordAction;
58     private SetNewPasswordController mSetNewPasswordController;
59 
60     /**
61      * From intent extra {@link DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
62      *
63      * <p>This is used only if caller has the required permission and activity is launched by
64      * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}.
65      */
66     private @PasswordComplexity int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
67 
68     private boolean mDevicePasswordRequirementOnly = false;
69 
70     /**
71      * Label of the app which launches this activity.
72      *
73      * <p>Value would be {@code null} if launched from settings app.
74      */
75     private String mCallerAppName = null;
76 
77     @Override
onCreate(Bundle savedState)78     protected void onCreate(Bundle savedState) {
79         super.onCreate(savedState);
80         final Intent intent = getIntent();
81 
82         mNewPasswordAction = intent.getAction();
83         if (!ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
84                 && !ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(mNewPasswordAction)) {
85             Log.e(TAG, "Unexpected action to launch this activity");
86             finish();
87             return;
88         }
89         logSetNewPasswordIntent();
90 
91         final IBinder activityToken = getActivityToken();
92         mCallerAppName = (String) PasswordUtils.getCallingAppLabel(this, activityToken);
93         if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
94                 && intent.hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
95             final boolean hasPermission = PasswordUtils.isCallingAppPermitted(
96                     this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
97             if (hasPermission) {
98                 mRequestedMinComplexity =
99                         PasswordMetrics.sanitizeComplexityLevel(intent.getIntExtra(
100                                 EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE));
101             } else {
102                 PasswordUtils.crashCallingApplication(activityToken,
103                         "Must have permission "
104                                 + REQUEST_PASSWORD_COMPLEXITY + " to use extra "
105                                 + EXTRA_PASSWORD_COMPLEXITY,
106                         MissingRequestPasswordComplexityPermissionException.TYPE_ID);
107                 finish();
108                 return;
109             }
110         }
111         if (ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(mNewPasswordAction)) {
112             mDevicePasswordRequirementOnly = intent.getBooleanExtra(
113                     EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY, false);
114             Log.i(TAG, String.format("DEVICE_PASSWORD_REQUIREMENT_ONLY: %b",
115                     mDevicePasswordRequirementOnly));
116         }
117         mSetNewPasswordController = SetNewPasswordController.create(
118                 this, this, intent, activityToken);
119         mSetNewPasswordController.dispatchSetNewPasswordIntent();
120     }
121 
122     @Override
launchChooseLock(Bundle chooseLockFingerprintExtras)123     public void launchChooseLock(Bundle chooseLockFingerprintExtras) {
124         final boolean isInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
125         Intent intent = isInSetupWizard ? new Intent(this, SetupChooseLockGeneric.class)
126                 : new Intent(this, ChooseLockGeneric.class);
127         intent.setAction(mNewPasswordAction);
128         intent.putExtras(chooseLockFingerprintExtras);
129         if (mCallerAppName != null) {
130             intent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
131         }
132         if (mRequestedMinComplexity != PASSWORD_COMPLEXITY_NONE) {
133             intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, mRequestedMinComplexity);
134         }
135         if (isCallingAppAdmin()) {
136             intent.putExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, true);
137         }
138         intent.putExtra(EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY, mDevicePasswordRequirementOnly);
139         // Copy the setup wizard intent extra to the intent.
140         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
141         startActivity(intent);
142         finish();
143     }
144 
isCallingAppAdmin()145     private boolean isCallingAppAdmin() {
146         DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
147         String callingAppPackageName = PasswordUtils.getCallingAppPackageName(getActivityToken());
148         List<ComponentName> admins = devicePolicyManager.getActiveAdmins();
149         if (admins == null) {
150             return false;
151         }
152         for (ComponentName componentName : admins) {
153             if (componentName.getPackageName().equals(callingAppPackageName)) {
154                 return true;
155             }
156         }
157         return false;
158     }
159 
logSetNewPasswordIntent()160     private void logSetNewPasswordIntent() {
161         final String callingAppPackageName =
162                 PasswordUtils.getCallingAppPackageName(getActivityToken());
163 
164         // use int min value to denote absence of EXTRA_PASSWORD_COMPLEXITY
165         final int extraPasswordComplexity = getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)
166                 ? getIntent().getIntExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE)
167                 : Integer.MIN_VALUE;
168 
169         final boolean extraDevicePasswordRequirementOnly = getIntent().getBooleanExtra(
170                 EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY, false);
171 
172         // Use 30th bit to encode extraDevicePasswordRequirementOnly, since the top bit (31th bit)
173         // encodes whether EXTRA_PASSWORD_COMPLEXITY has been absent.
174         final int logValue = extraPasswordComplexity
175                 | (extraDevicePasswordRequirementOnly ? 1 << 30 : 0);
176         // this activity is launched by either ACTION_SET_NEW_PASSWORD or
177         // ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
178         final int action = ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
179                 ? SettingsEnums.ACTION_SET_NEW_PASSWORD
180                 : SettingsEnums.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
181 
182         final MetricsFeatureProvider metricsProvider =
183                 FeatureFactory.getFactory(this).getMetricsFeatureProvider();
184         metricsProvider.action(
185                 metricsProvider.getAttribution(this),
186                 action,
187                 SettingsEnums.SET_NEW_PASSWORD_ACTIVITY,
188                 callingAppPackageName,
189                 logValue);
190     }
191 }
192