• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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.managedprovisioning.preprovisioning;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE;
20 import static android.app.admin.DevicePolicyManager.ACTION_GET_PROVISIONING_MODE;
21 
22 import static com.android.managedprovisioning.model.ProvisioningParams.PROVISIONING_MODE_FULLY_MANAGED_DEVICE_LEGACY;
23 
24 import android.annotation.IntDef;
25 import android.annotation.Nullable;
26 import android.app.Activity;
27 import android.app.ActivityManager;
28 import android.app.DialogFragment;
29 import android.content.ComponentName;
30 import android.content.Intent;
31 import android.os.Bundle;
32 import android.os.UserHandle;
33 import android.provider.Settings;
34 import android.view.ContextMenu;
35 import android.view.ContextMenu.ContextMenuInfo;
36 import android.view.View;
37 import android.widget.TextView;
38 
39 import androidx.annotation.VisibleForTesting;
40 
41 import com.android.managedprovisioning.R;
42 import com.android.managedprovisioning.common.AccessibilityContextMenuMaker;
43 import com.android.managedprovisioning.common.LogoUtils;
44 import com.android.managedprovisioning.common.ProvisionLogger;
45 import com.android.managedprovisioning.common.SetupGlifLayoutActivity;
46 import com.android.managedprovisioning.common.SimpleDialog;
47 import com.android.managedprovisioning.common.Utils;
48 import com.android.managedprovisioning.model.CustomizationParams;
49 import com.android.managedprovisioning.model.ProvisioningParams;
50 import com.android.managedprovisioning.preprovisioning.PreProvisioningController.UiParams;
51 import com.android.managedprovisioning.preprovisioning.consent.ConsentUiHelperFactory;
52 import com.android.managedprovisioning.preprovisioning.consent.ConsentUiHelper;
53 import com.android.managedprovisioning.preprovisioning.consent.ConsentUiHelperCallback;
54 import com.android.managedprovisioning.provisioning.LandingActivity;
55 import com.android.managedprovisioning.provisioning.ProvisioningActivity;
56 import com.google.android.setupcompat.util.WizardManagerHelper;
57 
58 import java.lang.annotation.Retention;
59 import java.lang.annotation.RetentionPolicy;
60 
61 public class PreProvisioningActivity extends SetupGlifLayoutActivity implements
62         SimpleDialog.SimpleDialogListener, PreProvisioningController.Ui, ConsentUiHelperCallback {
63 
64     private static final String KEY_ACTIVITY_STATE = "activity-state";
65 
66     private static final int ENCRYPT_DEVICE_REQUEST_CODE = 1;
67     @VisibleForTesting
68     protected static final int PROVISIONING_REQUEST_CODE = 2;
69     private static final int WIFI_REQUEST_CODE = 3;
70     private static final int CHANGE_LAUNCHER_REQUEST_CODE = 4;
71     private static final int ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE = 5;
72     private static final int GET_PROVISIONING_MODE_REQUEST_CODE = 6;
73 
74     // Note: must match the constant defined in HomeSettings
75     private static final String EXTRA_SUPPORT_MANAGED_PROFILES = "support_managed_profiles";
76     private static final String SAVED_PROVISIONING_PARAMS = "saved_provisioning_params";
77 
78     private static final String ERROR_AND_CLOSE_DIALOG = "PreProvErrorAndCloseDialog";
79     private static final String BACK_PRESSED_DIALOG_RESET = "PreProvBackPressedDialogReset";
80     private static final String BACK_PRESSED_DIALOG_CLOSE_ACTIVITY =
81             "PreProvBackPressedDialogCloseActivity";
82     private static final String LAUNCHER_INVALID_DIALOG = "PreProvCurrentLauncherInvalidDialog";
83     private static final String DELETE_MANAGED_PROFILE_DIALOG = "PreProvDeleteManagedProfileDialog";
84 
85     private PreProvisioningController mController;
86     private ControllerProvider mControllerProvider;
87     private final AccessibilityContextMenuMaker mContextMenuMaker;
88     private ConsentUiHelper mConsentUiHelper;
89 
90     static final int STATE_PREPROVISIONING_INTIIALIZING = 1;
91     static final int STATE_PROVISIONING_STARTED = 2;
92     static final int STATE_PROVISIONING_FINALIZED = 3;
93 
94     @Retention(RetentionPolicy.SOURCE)
95     @IntDef({STATE_PREPROVISIONING_INTIIALIZING,
96             STATE_PROVISIONING_STARTED,
97             STATE_PROVISIONING_FINALIZED})
98     private @interface PreProvisioningState {}
99 
100     private @PreProvisioningState int mState;
101 
102     private static final String ERROR_DIALOG_RESET = "ErrorDialogReset";
103 
PreProvisioningActivity()104     public PreProvisioningActivity() {
105         this(activity -> new PreProvisioningController(activity, activity), null, new Utils());
106     }
107 
108     @VisibleForTesting
PreProvisioningActivity(ControllerProvider controllerProvider, AccessibilityContextMenuMaker contextMenuMaker, Utils utils)109     public PreProvisioningActivity(ControllerProvider controllerProvider,
110             AccessibilityContextMenuMaker contextMenuMaker, Utils utils) {
111         super(utils);
112         mControllerProvider = controllerProvider;
113         mContextMenuMaker =
114                 contextMenuMaker != null ? contextMenuMaker : new AccessibilityContextMenuMaker(
115                         this);
116     }
117 
118     @Override
onCreate(Bundle savedInstanceState)119     protected void onCreate(Bundle savedInstanceState) {
120         super.onCreate(savedInstanceState);
121 
122         mState = savedInstanceState == null
123                 ? STATE_PREPROVISIONING_INTIIALIZING
124                 : savedInstanceState.getInt(KEY_ACTIVITY_STATE, STATE_PREPROVISIONING_INTIIALIZING);
125 
126         mController = mControllerProvider.getInstance(this);
127         mConsentUiHelper = ConsentUiHelperFactory.getInstance(
128                 /* activity */ this, /* contextMenuMaker */ mContextMenuMaker,
129                 /* callback */ this, /* utils */ mUtils, mController.getSettingsFacade());
130         if (mState == STATE_PREPROVISIONING_INTIIALIZING) {
131             ProvisioningParams params = savedInstanceState == null ? null
132                     : savedInstanceState.getParcelable(SAVED_PROVISIONING_PARAMS);
133             mController.initiateProvisioning(getIntent(), params, getCallingPackage());
134         }
135     }
136 
137     @Override
finish()138     public void finish() {
139         // The user has backed out of provisioning, so we perform the necessary clean up steps.
140         LogoUtils.cleanUp(this);
141         ProvisioningParams params = mController.getParams();
142         if (params != null) {
143             params.cleanUp();
144         }
145         EncryptionController.getInstance(this).cancelEncryptionReminder();
146         super.finish();
147     }
148 
149     @Override
onSaveInstanceState(Bundle outState)150     protected void onSaveInstanceState(Bundle outState) {
151         super.onSaveInstanceState(outState);
152         outState.putParcelable(SAVED_PROVISIONING_PARAMS, mController.getParams());
153         outState.putInt(KEY_ACTIVITY_STATE, mState);
154     }
155 
156     @Override
onActivityResult(int requestCode, int resultCode, Intent data)157     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
158         switch (requestCode) {
159             case ENCRYPT_DEVICE_REQUEST_CODE:
160                 if (resultCode == RESULT_CANCELED) {
161                     ProvisionLogger.loge("User canceled device encryption.");
162                 }
163                 break;
164             case PROVISIONING_REQUEST_CODE:
165                 mState = STATE_PROVISIONING_FINALIZED;
166                 setResult(resultCode);
167                 finish();
168                 break;
169             case CHANGE_LAUNCHER_REQUEST_CODE:
170                 mController.continueProvisioningAfterUserConsent();
171                 break;
172             case WIFI_REQUEST_CODE:
173                 if (resultCode == RESULT_CANCELED) {
174                     ProvisionLogger.loge("User canceled wifi picking.");
175                     setResult(resultCode);
176                     finish();
177                 } else {
178                     if (resultCode == RESULT_OK) {
179                         ProvisionLogger.logd("Wifi request result is OK");
180                     }
181                     mController.initiateProvisioning(getIntent(), null /* cached params */,
182                             getCallingPackage());
183                 }
184                 break;
185             case ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE:
186                 if (resultCode == RESULT_OK) {
187                     maybeShowAdminGetProvisioningModeScreen();
188                 } else {
189                     setResult(resultCode);
190                     finish();
191                 }
192                 break;
193             case GET_PROVISIONING_MODE_REQUEST_CODE:
194                 if (resultCode == RESULT_OK) {
195                     if(data != null && mController.updateProvisioningParamsFromIntent(data)) {
196                         mController.showUserConsentScreen();
197                     } else {
198                         showFactoryResetDialog(R.string.cant_set_up_device,
199                                 R.string.contact_your_admin_for_help);
200                     }
201                 } else {
202                     showFactoryResetDialog(R.string.cant_set_up_device,
203                             R.string.contact_your_admin_for_help);
204                 }
205                 break;
206             default:
207                 ProvisionLogger.logw("Unknown result code :" + resultCode);
208                 break;
209         }
210     }
211 
212     @Override
showErrorAndClose(Integer titleId, int messageId, String logText)213     public void showErrorAndClose(Integer titleId, int messageId, String logText) {
214         ProvisionLogger.loge(logText);
215 
216         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
217                 .setTitle(titleId)
218                 .setMessage(messageId)
219                 .setCancelable(false)
220                 .setPositiveButtonMessage(R.string.device_owner_error_ok);
221         showDialog(dialogBuilder, ERROR_AND_CLOSE_DIALOG);
222     }
223 
224     @Override
onNegativeButtonClick(DialogFragment dialog)225     public void onNegativeButtonClick(DialogFragment dialog) {
226         switch (dialog.getTag()) {
227             case BACK_PRESSED_DIALOG_CLOSE_ACTIVITY:
228             case BACK_PRESSED_DIALOG_RESET:
229                 // user chose to continue. Do nothing
230                 break;
231             case LAUNCHER_INVALID_DIALOG:
232                 dialog.dismiss();
233                 break;
234             case DELETE_MANAGED_PROFILE_DIALOG:
235                 setResult(Activity.RESULT_CANCELED);
236                 finish();
237                 break;
238             default:
239                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
240         }
241     }
242 
243     @Override
onPositiveButtonClick(DialogFragment dialog)244     public void onPositiveButtonClick(DialogFragment dialog) {
245         switch (dialog.getTag()) {
246             case ERROR_AND_CLOSE_DIALOG:
247             case BACK_PRESSED_DIALOG_CLOSE_ACTIVITY:
248                 onProvisioningAborted();
249                 break;
250             case BACK_PRESSED_DIALOG_RESET:
251                 mUtils.sendFactoryResetBroadcast(this,
252                         "Provisioning cancelled by user on consent screen");
253                 onProvisioningAborted();
254                 break;
255             case LAUNCHER_INVALID_DIALOG:
256                 requestLauncherPick();
257                 break;
258             case DELETE_MANAGED_PROFILE_DIALOG:
259                 DeleteManagedProfileDialog d = (DeleteManagedProfileDialog) dialog;
260                 mController.removeUser(d.getUserId());
261                 mController.initiateProvisioning(getIntent(), /* cached params */ null,
262                         getCallingPackage());
263                 break;
264             case ERROR_DIALOG_RESET:
265                 getUtils().sendFactoryResetBroadcast(this, "Error during preprovisioning");
266                 setResult(Activity.RESULT_CANCELED);
267                 finish();
268                 break;
269             default:
270                 SimpleDialog.throwButtonClickHandlerNotImplemented(dialog);
271         }
272     }
273 
onProvisioningAborted()274     private void onProvisioningAborted() {
275         setResult(Activity.RESULT_CANCELED);
276         mController.logPreProvisioningCancelled();
277         finish();
278     }
279 
280     @Override
requestEncryption(ProvisioningParams params)281     public void requestEncryption(ProvisioningParams params) {
282         Intent encryptIntent = new Intent(this, EncryptDeviceActivity.class);
283         WizardManagerHelper.copyWizardManagerExtras(getIntent(), encryptIntent);
284         encryptIntent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
285         startActivityForResult(encryptIntent, ENCRYPT_DEVICE_REQUEST_CODE);
286     }
287 
288     @Override
requestWifiPick()289     public void requestWifiPick() {
290         final Intent intent = mUtils.getWifiPickIntent();
291         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
292         startActivityForResult(intent, WIFI_REQUEST_CODE);
293     }
294 
295     @Override
showCurrentLauncherInvalid()296     public void showCurrentLauncherInvalid() {
297         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
298                 .setCancelable(false)
299                 .setTitle(R.string.change_device_launcher)
300                 .setMessage(R.string.launcher_app_cant_be_used_by_work_profile)
301                 .setNegativeButtonMessage(R.string.cancel_provisioning)
302                 .setPositiveButtonMessage(R.string.pick_launcher);
303         showDialog(dialogBuilder, LAUNCHER_INVALID_DIALOG);
304     }
305 
requestLauncherPick()306     private void requestLauncherPick() {
307         Intent changeLauncherIntent = new Intent(Settings.ACTION_HOME_SETTINGS);
308         changeLauncherIntent.putExtra(EXTRA_SUPPORT_MANAGED_PROFILES, true);
309         startActivityForResult(changeLauncherIntent, CHANGE_LAUNCHER_REQUEST_CODE);
310     }
311 
startProvisioning(int userId, ProvisioningParams params)312     public void startProvisioning(int userId, ProvisioningParams params) {
313         mState = STATE_PROVISIONING_STARTED;
314         Intent intent = new Intent(this, ProvisioningActivity.class);
315         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
316         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
317         startActivityForResultAsUser(intent, PROVISIONING_REQUEST_CODE, new UserHandle(userId));
318         overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
319     }
320 
maybeShowAdminGetProvisioningModeScreen()321     private void maybeShowAdminGetProvisioningModeScreen() {
322         final String adminPackage = mController.getParams().inferDeviceAdminPackageName();
323         final Intent intentGetMode = new Intent(ACTION_GET_PROVISIONING_MODE);
324         intentGetMode.setPackage(adminPackage);
325         final Intent intentPolicy = new Intent(ACTION_ADMIN_POLICY_COMPLIANCE);
326         intentPolicy.setPackage(adminPackage);
327         final ActivityManager activityManager = getSystemService(ActivityManager.class);
328         if (!activityManager.isLowRamDevice()
329                 && !mController.getParams().isNfc
330                 && intentGetMode.resolveActivity(getPackageManager()) != null
331                 && intentPolicy.resolveActivity(getPackageManager()) != null) {
332             mController.putExtrasIntoGetModeIntent(intentGetMode);
333             startActivityForResult(intentGetMode, GET_PROVISIONING_MODE_REQUEST_CODE);
334         } else {
335             startManagedDeviceLegacyFlow();
336         }
337     }
338 
startManagedDeviceLegacyFlow()339     private void startManagedDeviceLegacyFlow() {
340         mController.setProvisioningMode(PROVISIONING_MODE_FULLY_MANAGED_DEVICE_LEGACY);
341         mController.showUserConsentScreen();
342     }
343 
344     @Override
showFactoryResetDialog(Integer titleId, int messageId)345     public void showFactoryResetDialog(Integer titleId, int messageId) {
346         SimpleDialog.Builder dialogBuilder = new SimpleDialog.Builder()
347                 .setTitle(titleId)
348                 .setMessage(messageId)
349                 .setCancelable(false)
350                 .setPositiveButtonMessage(R.string.reset);
351 
352         showDialog(dialogBuilder, ERROR_DIALOG_RESET);
353     }
354 
355     @Override
initiateUi(UiParams uiParams)356     public void initiateUi(UiParams uiParams) {
357         mConsentUiHelper.initiateUi(uiParams);
358     }
359 
360     @Override
prepareAdminIntegratedFlow(ProvisioningParams params)361     public void prepareAdminIntegratedFlow(ProvisioningParams params) {
362         Intent intent = new Intent(this, LandingActivity.class);
363         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
364         intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
365         startActivityForResult(intent, ADMIN_INTEGRATED_FLOW_PREPARE_REQUEST_CODE);
366     }
367 
368     @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)369     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
370         super.onCreateContextMenu(menu, v, menuInfo);
371         if (v instanceof TextView) {
372             mContextMenuMaker.populateMenuContent(menu, (TextView) v);
373         }
374     }
375 
376     @Override
showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName, int userId)377     public void showDeleteManagedProfileDialog(ComponentName mdmPackageName, String domainName,
378             int userId) {
379         showDialog(() -> DeleteManagedProfileDialog.newInstance(userId,
380                 mdmPackageName, domainName), DELETE_MANAGED_PROFILE_DIALOG);
381     }
382 
383     @Override
onBackPressed()384     public void onBackPressed() {
385         if (mController.getParams().isOrganizationOwnedProvisioning) {
386             showDialog(mUtils.createCancelProvisioningResetDialogBuilder(),
387                     BACK_PRESSED_DIALOG_RESET);
388         } else {
389             showDialog(mUtils.createCancelProvisioningDialogBuilder(),
390                     BACK_PRESSED_DIALOG_CLOSE_ACTIVITY);
391         }
392     }
393 
394     @Override
onStart()395     protected void onStart() {
396         super.onStart();
397         mConsentUiHelper.onStart();
398     }
399 
400     @Override
onStop()401     protected void onStop() {
402         super.onStop();
403         mConsentUiHelper.onStop();
404     }
405 
406     @Override
nextAfterUserConsent()407     public void nextAfterUserConsent() {
408         mController.continueProvisioningAfterUserConsent();
409     }
410 
411     @Override
initializeLayoutParams(int layoutResourceId, @Nullable Integer headerResourceId, CustomizationParams params)412     public void initializeLayoutParams(int layoutResourceId, @Nullable Integer headerResourceId,
413             CustomizationParams params) {
414         super.initializeLayoutParams(layoutResourceId, headerResourceId, params);
415     }
416 
417     /**
418      * Constructs {@link PreProvisioningController} for a given {@link PreProvisioningActivity}
419      */
420     interface ControllerProvider {
421         /**
422          * Constructs {@link PreProvisioningController} for a given {@link PreProvisioningActivity}
423          */
getInstance(PreProvisioningActivity activity)424         PreProvisioningController getInstance(PreProvisioningActivity activity);
425     }
426 }