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