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_PROVISION_FINANCED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
23 import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
24 import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
25 import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
26 import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
27 import static android.app.admin.DevicePolicyManager.CODE_OK;
28 import static android.app.admin.DevicePolicyManager.CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS;
29 import static android.app.admin.DevicePolicyManager.CODE_USER_SETUP_COMPLETED;
30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES;
33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMERS;
34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_IMEI;
35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION;
36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED;
37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE;
38 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME;
39 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT;
40 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SERIAL_NUMBER;
41 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS;
42 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
43 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE;
44 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
45 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_DEVICE_OWNER;
46 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED;
47 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE;
48 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
49 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
50 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
51 
52 import static com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker.CANCELLED_BEFORE_PROVISIONING;
53 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
54 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED;
55 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT;
56 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION;
57 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED;
58 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED;
59 import static com.android.managedprovisioning.model.ProvisioningParams.FLOW_TYPE_LEGACY;
60 
61 import static java.util.Objects.requireNonNull;
62 
63 import android.accounts.Account;
64 import android.annotation.NonNull;
65 import android.annotation.Nullable;
66 import android.app.Activity;
67 import android.app.KeyguardManager;
68 import android.app.admin.DevicePolicyManager;
69 import android.content.ComponentName;
70 import android.content.Context;
71 import android.content.Intent;
72 import android.content.pm.PackageInfo;
73 import android.content.pm.PackageManager;
74 import android.content.pm.UserInfo;
75 import android.net.ConnectivityManager;
76 import android.os.Build;
77 import android.os.Bundle;
78 import android.os.PersistableBundle;
79 import android.os.SystemClock;
80 import android.os.UserManager;
81 import android.service.persistentdata.PersistentDataBlockManager;
82 import android.telephony.TelephonyManager;
83 import android.text.TextUtils;
84 
85 import androidx.activity.ComponentActivity;
86 import androidx.lifecycle.LiveData;
87 import androidx.lifecycle.ViewModelProvider;
88 
89 import com.android.internal.annotations.VisibleForTesting;
90 import com.android.managedprovisioning.ManagedProvisioningBaseApplication;
91 import com.android.managedprovisioning.ManagedProvisioningScreens;
92 import com.android.managedprovisioning.R;
93 import com.android.managedprovisioning.analytics.MetricsWriterFactory;
94 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
95 import com.android.managedprovisioning.common.GetProvisioningModeUtils;
96 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
97 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences;
98 import com.android.managedprovisioning.common.PolicyComplianceUtils;
99 import com.android.managedprovisioning.common.ProvisionLogger;
100 import com.android.managedprovisioning.common.SettingsFacade;
101 import com.android.managedprovisioning.common.StoreUtils;
102 import com.android.managedprovisioning.common.Utils;
103 import com.android.managedprovisioning.model.CustomizationParams;
104 import com.android.managedprovisioning.model.DisclaimersParam;
105 import com.android.managedprovisioning.model.ProvisioningParams;
106 import com.android.managedprovisioning.model.ProvisioningParams.FlowType;
107 import com.android.managedprovisioning.parser.DisclaimerParser;
108 import com.android.managedprovisioning.parser.DisclaimersParserImpl;
109 import com.android.managedprovisioning.preprovisioning.PreProvisioningViewModel.PreProvisioningViewModelFactory;
110 
111 import java.util.IllformedLocaleException;
112 import java.util.List;
113 import java.util.function.BiFunction;
114 
115 /**
116  * Controller which contains business logic related to provisioning preparation.
117  *
118  * @see PreProvisioningActivity
119  */
120 public class PreProvisioningActivityController {
121     private final Context mContext;
122     private final Ui mUi;
123     private final Utils mUtils;
124     private final PolicyComplianceUtils mPolicyComplianceUtils;
125     private final GetProvisioningModeUtils mGetProvisioningModeUtils;
126     private final SettingsFacade mSettingsFacade;
127 
128     // used system services
129     private final DevicePolicyManager mDevicePolicyManager;
130     private final UserManager mUserManager;
131     private final PackageManager mPackageManager;
132     private final KeyguardManager mKeyguardManager;
133     private final PersistentDataBlockManager mPdbManager;
134     private final ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
135     private final ManagedProvisioningSharedPreferences mSharedPreferences;
136 
137     private final PreProvisioningViewModel mViewModel;
138     private final BiFunction<Context, Long, DisclaimerParser> mDisclaimerParserProvider;
139 
PreProvisioningActivityController( @onNull ComponentActivity activity, @NonNull Ui ui)140     public PreProvisioningActivityController(
141             @NonNull ComponentActivity activity,
142             @NonNull Ui ui) {
143         this(activity, ui,
144                 new Utils(), new SettingsFacade(),
145                 new ManagedProvisioningSharedPreferences(activity),
146                 new PolicyComplianceUtils(),
147                 new GetProvisioningModeUtils(),
148                 new ViewModelProvider(
149                         activity,
150                         new PreProvisioningViewModelFactory(
151                                 (ManagedProvisioningBaseApplication) activity.getApplication()))
152                                         .get(PreProvisioningViewModel.class),
153                 DisclaimersParserImpl::new);
154     }
155     @VisibleForTesting
PreProvisioningActivityController( @onNull Context context, @NonNull Ui ui, @NonNull Utils utils, @NonNull SettingsFacade settingsFacade, @NonNull ManagedProvisioningSharedPreferences sharedPreferences, @NonNull PolicyComplianceUtils policyComplianceUtils, @NonNull GetProvisioningModeUtils getProvisioningModeUtils, @NonNull PreProvisioningViewModel viewModel, @NonNull BiFunction<Context, Long, DisclaimerParser> disclaimerParserProvider)156     PreProvisioningActivityController(
157             @NonNull Context context,
158             @NonNull Ui ui,
159             @NonNull Utils utils,
160             @NonNull SettingsFacade settingsFacade,
161             @NonNull ManagedProvisioningSharedPreferences sharedPreferences,
162             @NonNull PolicyComplianceUtils policyComplianceUtils,
163             @NonNull GetProvisioningModeUtils getProvisioningModeUtils,
164             @NonNull PreProvisioningViewModel viewModel,
165             @NonNull BiFunction<Context, Long, DisclaimerParser> disclaimerParserProvider) {
166         mContext = requireNonNull(context, "Context must not be null");
167         mUi = requireNonNull(ui, "Ui must not be null");
168         mSettingsFacade = requireNonNull(settingsFacade);
169         mUtils = requireNonNull(utils, "Utils must not be null");
170         mPolicyComplianceUtils = requireNonNull(policyComplianceUtils,
171                 "PolicyComplianceUtils cannot be null");
172         mGetProvisioningModeUtils = requireNonNull(getProvisioningModeUtils,
173                 "GetProvisioningModeUtils cannot be null");
174         mSharedPreferences = requireNonNull(sharedPreferences);
175         mViewModel = requireNonNull(viewModel);
176 
177         mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
178         mUserManager = mContext.getSystemService(UserManager.class);
179         mPackageManager = mContext.getPackageManager();
180         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
181         mPdbManager = (PersistentDataBlockManager) mContext.getSystemService(
182                 Context.PERSISTENT_DATA_BLOCK_SERVICE);
183         mProvisioningAnalyticsTracker = new ProvisioningAnalyticsTracker(
184                 MetricsWriterFactory.getMetricsWriter(mContext, mSettingsFacade),
185                 mSharedPreferences);
186         mDisclaimerParserProvider = requireNonNull(disclaimerParserProvider);
187     }
188 
189     interface Ui {
190         /**
191          * Show an error message and cancel provisioning.
192          * @param titleId resource id used to form the user facing error title
193          * @param messageId resource id used to form the user facing error message
194          * @param errorMessage an error message that gets logged for debugging
195          */
showErrorAndClose(Integer titleId, int messageId, String errorMessage)196         void showErrorAndClose(Integer titleId, int messageId, String errorMessage);
197 
198         /**
199          * Request the user to encrypt the device.
200          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
201          */
requestEncryption(ProvisioningParams params)202         void requestEncryption(ProvisioningParams params);
203 
204         /**
205          * Request the user to choose a wifi network.
206          */
requestWifiPick()207         void requestWifiPick();
208 
209         /**
210          * Start provisioning.
211          * @param params the {@link ProvisioningParams} object related to the ongoing provisioning
212          */
startProvisioning(ProvisioningParams params)213         void startProvisioning(ProvisioningParams params);
214 
215         /**
216          * Show an error dialog indicating that the current launcher does not support managed
217          * profiles and ask the user to choose a different one.
218          */
showCurrentLauncherInvalid()219         void showCurrentLauncherInvalid();
220 
showOwnershipDisclaimerScreen(ProvisioningParams params)221         void showOwnershipDisclaimerScreen(ProvisioningParams params);
222 
prepareFinancedDeviceFlow(ProvisioningParams params)223         void prepareFinancedDeviceFlow(ProvisioningParams params);
224 
showFactoryResetDialog(Integer titleId, int messageId)225         void showFactoryResetDialog(Integer titleId, int messageId);
226 
initiateUi(UiParams uiParams)227         void initiateUi(UiParams uiParams);
228 
229         /**
230          *  Abort provisioning and close app
231          */
abortProvisioning()232         void abortProvisioning();
233 
prepareAdminIntegratedFlow(ProvisioningParams params)234         void prepareAdminIntegratedFlow(ProvisioningParams params);
235     }
236 
237     /**
238      * Wrapper which holds information related to the consent screen.
239      * <p>Does not implement {@link Object#equals(Object)}, {@link Object#hashCode()}
240      * or {@link Object#toString()}.
241      */
242     public static class UiParams {
243         /**
244          * Admin application package name.
245          */
246         public String packageName;
247         /**
248          * Various organization-defined customizations, e.g. colors, organization name.
249          */
250         public CustomizationParams customization;
251         /**
252          * List of headings for the organization-provided terms and conditions.
253          */
254         public List<String> disclaimerHeadings;
255         public boolean isDeviceManaged;
256         /**
257          * The original provisioning action, kept for backwards compatibility.
258          */
259         public String provisioningAction;
260         public boolean isOrganizationOwnedProvisioning;
261     }
262 
263     /**
264      * Initiates Profile owner and device owner provisioning.
265      * @param intent Intent that started provisioning.
266      * @param callingPackage Package that started provisioning.
267      */
initiateProvisioning(Intent intent, String callingPackage)268     public void initiateProvisioning(Intent intent, String callingPackage) {
269         mSharedPreferences.writeProvisioningStartedTimestamp(SystemClock.elapsedRealtime());
270         mProvisioningAnalyticsTracker.logProvisioningSessionStarted(mContext);
271 
272         if (!tryParseParameters(intent)) {
273             return;
274         }
275 
276         ProvisioningParams params = mViewModel.getParams();
277         if (!checkFactoryResetProtection(params, callingPackage)) {
278             return;
279         }
280 
281         if (!verifyActionAndCaller(intent, callingPackage)) {
282             return;
283         }
284 
285         // Check whether provisioning is allowed for the current action. This check needs to happen
286         // before any actions that might affect the state of the device.
287         // Note that checkDevicePolicyPreconditions takes care of calling
288         // showProvisioningErrorAndClose. So we only need to show the factory reset dialog (if
289         // applicable) and return.
290         if (!checkDevicePolicyPreconditions()) {
291             return;
292         }
293 
294         if (!isIntentActionValid(intent.getAction())) {
295             ProvisionLogger.loge(
296                     ACTION_PROVISION_MANAGED_DEVICE + " is no longer a supported intent action.");
297             mUi.abortProvisioning();
298             return;
299         }
300 
301         if (isDeviceOwnerProvisioning()) {
302             // TODO: make a general test based on deviceAdminDownloadInfo field
303             // PO doesn't ever initialize that field, so OK as a general case
304             if (shouldShowWifiPicker(intent)) {
305                 // Have the user pick a wifi network if necessary.
306                 // It is not possible to ask the user to pick a wifi network if
307                 // the screen is locked.
308                 // TODO: remove this check once we know the screen will not be locked.
309                 if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
310                     // TODO: decide on what to do in that case; fail? retry on screen unlock?
311                     ProvisionLogger.logi("Cannot pick wifi because the screen is locked.");
312                 } else if (canRequestWifiPick()) {
313                     // we resume this method after a successful WiFi pick
314                     // TODO: refactor as evil - logic should be less spread out
315                     mUi.requestWifiPick();
316                     return;
317                 } else {
318                     mUi.showErrorAndClose(R.string.cant_set_up_device,
319                             R.string.contact_your_admin_for_help,
320                             "Cannot pick WiFi because there is no handler to the intent");
321                 }
322             }
323         }
324 
325         mViewModel.getTimeLogger().start();
326         mProvisioningAnalyticsTracker.logPreProvisioningStarted(mContext, intent);
327         mViewModel.onProvisioningInitiated();
328 
329         if (mUtils.checkAdminIntegratedFlowPreconditions(params)) {
330             if (mUtils.shouldShowOwnershipDisclaimerScreen(params)) {
331                 mUi.showOwnershipDisclaimerScreen(params);
332             } else {
333                 mUi.prepareAdminIntegratedFlow(params);
334             }
335             mViewModel.onAdminIntegratedFlowInitiated();
336         } else if (mUtils.isFinancedDeviceAction(params.provisioningAction)) {
337             mUi.prepareFinancedDeviceFlow(params);
338         } else if (params.isNfc) {
339             // TODO(b/177849035): Remove NFC-specific logic
340             if (mUtils.shouldShowOwnershipDisclaimerScreen(params)) {
341                 mUi.showOwnershipDisclaimerScreen(params);
342             } else {
343                 startNfcFlow();
344             }
345         } else if (isProfileOwnerProvisioning()) {
346             startManagedProfileFlow();
347         } else if (isDpcTriggeredManagedDeviceProvisioning(intent)) {
348             // TODO(b/175678720): Fail provisioning if flow started by PROVISION_MANAGED_DEVICE
349             startManagedDeviceFlow();
350         }
351     }
352 
isIntentActionValid(String action)353     private boolean isIntentActionValid(String action) {
354         return !ACTION_PROVISION_MANAGED_DEVICE.equals(action);
355     }
356 
startNfcFlow()357     void startNfcFlow() {
358         ProvisionLogger.logi("Starting the NFC provisioning flow.");
359         updateProvisioningFlowState(FLOW_TYPE_LEGACY);
360         showUserConsentScreen();
361     }
362 
startManagedProfileFlow()363     private void startManagedProfileFlow() {
364         ProvisionLogger.logi("Starting the managed profile flow.");
365         showUserConsentScreen();
366     }
367 
startManagedDeviceFlow()368     private void startManagedDeviceFlow() {
369         ProvisionLogger.logi("Starting the legacy managed device flow.");
370         showUserConsentScreen();
371     }
372 
isDpcTriggeredManagedDeviceProvisioning(Intent intent)373     private boolean isDpcTriggeredManagedDeviceProvisioning(Intent intent) {
374         return ACTION_PROVISION_MANAGED_DEVICE.equals(intent.getAction());
375     }
376 
isNfcProvisioning(Intent intent)377     private boolean isNfcProvisioning(Intent intent) {
378         return ACTION_NDEF_DISCOVERED.equals(intent.getAction());
379     }
380 
isQrCodeProvisioning(Intent intent)381     private boolean isQrCodeProvisioning(Intent intent) {
382         if (!ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())) {
383             return false;
384         }
385         final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER,
386                 PROVISIONING_TRIGGER_UNSPECIFIED);
387         return provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE;
388     }
389 
shouldShowWifiPicker(Intent intent)390     private boolean shouldShowWifiPicker(Intent intent) {
391         ProvisioningParams params = mViewModel.getParams();
392         if (params.wifiInfo != null) {
393             return false;
394         }
395         if (params.deviceAdminDownloadInfo == null) {
396             return false;
397         }
398         if (mUtils.isNetworkTypeConnected(mContext, ConnectivityManager.TYPE_WIFI,
399                 ConnectivityManager.TYPE_ETHERNET)) {
400             return false;
401         }
402         // we intentionally disregard whether mobile is connected for QR and NFC
403         // provisioning. b/153442588 for context
404         if (params.useMobileData
405                 && (isQrCodeProvisioning(intent) || isNfcProvisioning(intent))) {
406             return false;
407         }
408         if (params.useMobileData) {
409             return !mUtils.isMobileNetworkConnectedToInternet(mContext);
410         }
411         return true;
412     }
413 
showUserConsentScreen()414     void showUserConsentScreen() {
415         // Check whether provisioning is allowed for the current action
416         if (!checkDevicePolicyPreconditions()) {
417             return;
418         }
419 
420         if (mViewModel.getParams().provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)
421                 && mViewModel.getParams().isOrganizationOwnedProvisioning) {
422             mProvisioningAnalyticsTracker.logOrganizationOwnedManagedProfileProvisioning();
423         }
424 
425         CustomizationParams customization =
426                 CustomizationParams.createInstance(mViewModel.getParams(), mContext, mUtils);
427 
428         // show UI so we can get user's consent to continue
429         final String packageName = mViewModel.getParams().inferDeviceAdminPackageName();
430         final UiParams uiParams = new UiParams();
431         uiParams.customization = customization;
432         uiParams.provisioningAction = mViewModel.getParams().provisioningAction;
433         uiParams.packageName = packageName;
434         uiParams.isDeviceManaged = mDevicePolicyManager.isDeviceManaged();
435         uiParams.isOrganizationOwnedProvisioning =
436                 mViewModel.getParams().isOrganizationOwnedProvisioning;
437 
438         mUi.initiateUi(uiParams);
439         mViewModel.onShowUserConsent();
440     }
441 
updateProvisioningParamsFromIntent(Intent resultIntent)442     boolean updateProvisioningParamsFromIntent(Intent resultIntent) {
443         final int provisioningMode = resultIntent.getIntExtra(
444                 DevicePolicyManager.EXTRA_PROVISIONING_MODE, 0);
445         if (!mViewModel.getParams().allowedProvisioningModes.contains(provisioningMode)) {
446             ProvisionLogger.loge("Invalid provisioning mode chosen by the DPC: " + provisioningMode
447                     + ", but expected one of "
448                     + mViewModel.getParams().allowedProvisioningModes.toString());
449             return false;
450         }
451         switch (provisioningMode) {
452             case DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE:
453                 updateParamsPostProvisioningModeDecision(
454                         resultIntent,
455                         ACTION_PROVISION_MANAGED_DEVICE,
456                         /* isOrganizationOwnedProvisioning */ true,
457                         /* updateAccountToMigrate */ false);
458                 return true;
459             case DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE:
460                 updateParamsPostProvisioningModeDecision(
461                         resultIntent,
462                         ACTION_PROVISION_MANAGED_PROFILE,
463                         mUtils.isOrganizationOwnedAllowed(mViewModel.getParams()),
464                         /* updateAccountToMigrate */ true);
465                 return true;
466             case PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE:
467                 updateParamsPostProvisioningModeDecision(
468                         resultIntent,
469                         ACTION_PROVISION_MANAGED_PROFILE,
470                         /* isOrganizationOwnedProvisioning */ false,
471                         /* updateAccountToMigrate */ true);
472                 return true;
473             default:
474                 ProvisionLogger.logw("Unknown returned provisioning mode:"
475                         + provisioningMode);
476                 return false;
477         }
478     }
479 
updateParamsPostProvisioningModeDecision(Intent resultIntent, String provisioningAction, boolean isOrganizationOwnedProvisioning, boolean updateAccountToMigrate)480     private void updateParamsPostProvisioningModeDecision(Intent resultIntent,
481             String provisioningAction, boolean isOrganizationOwnedProvisioning,
482             boolean updateAccountToMigrate) {
483         ProvisioningParams.Builder builder = mViewModel.getParams().toBuilder();
484         builder.setFlowType(FLOW_TYPE_ADMIN_INTEGRATED);
485         builder.setProvisioningAction(provisioningAction);
486         builder.setIsOrganizationOwnedProvisioning(isOrganizationOwnedProvisioning);
487         maybeUpdateAdminExtrasBundle(builder, resultIntent);
488         maybeUpdateSkipEducationScreens(builder, resultIntent);
489         maybeUpdateDisclaimers(builder, resultIntent);
490         maybeUpdateSkipEncryption(builder, resultIntent);
491         if (updateAccountToMigrate) {
492             maybeUpdateAccountToMigrate(builder, resultIntent);
493         }
494         if (provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
495             maybeUpdateKeepAccountMigrated(builder, resultIntent);
496             maybeUpdateLeaveAllSystemAppsEnabled(builder, resultIntent);
497         }
498         else if (provisioningAction.equals(ACTION_PROVISION_MANAGED_DEVICE)){
499             maybeUpdateDeviceOwnerPermissionGrantOptOut(builder, resultIntent);
500             maybeUpdateLocale(builder, resultIntent);
501             maybeUpdateLocalTime(builder, resultIntent);
502             maybeUpdateTimeZone(builder, resultIntent);
503         }
504         mViewModel.updateParams(builder.build());
505     }
506 
maybeUpdateDeviceOwnerPermissionGrantOptOut( ProvisioningParams.Builder builder, Intent resultIntent)507     private void maybeUpdateDeviceOwnerPermissionGrantOptOut(
508             ProvisioningParams.Builder builder, Intent resultIntent) {
509         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT)) {
510             builder.setDeviceOwnerPermissionGrantOptOut(resultIntent.getBooleanExtra(
511                     EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT,
512                     DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT));
513         }
514     }
515 
maybeUpdateSkipEncryption( ProvisioningParams.Builder builder, Intent resultIntent)516     private void maybeUpdateSkipEncryption(
517             ProvisioningParams.Builder builder, Intent resultIntent) {
518         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION)) {
519             builder.setSkipEncryption(resultIntent.getBooleanExtra(
520                     EXTRA_PROVISIONING_SKIP_ENCRYPTION,
521                     DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION));
522         }
523     }
524 
maybeUpdateTimeZone(ProvisioningParams.Builder builder, Intent resultIntent)525     private void maybeUpdateTimeZone(ProvisioningParams.Builder builder, Intent resultIntent) {
526         if (resultIntent.hasExtra(EXTRA_PROVISIONING_TIME_ZONE)) {
527             builder.setTimeZone(resultIntent.getStringExtra(EXTRA_PROVISIONING_TIME_ZONE));
528         }
529     }
530 
maybeUpdateLocalTime(ProvisioningParams.Builder builder, Intent resultIntent)531     private void maybeUpdateLocalTime(ProvisioningParams.Builder builder, Intent resultIntent) {
532         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LOCAL_TIME)) {
533             builder.setLocalTime(resultIntent.getLongExtra(
534                     EXTRA_PROVISIONING_LOCAL_TIME, ProvisioningParams.DEFAULT_LOCAL_TIME));
535         }
536     }
537 
maybeUpdateLocale(ProvisioningParams.Builder builder, Intent resultIntent)538     private void maybeUpdateLocale(ProvisioningParams.Builder builder, Intent resultIntent) {
539         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LOCALE)) {
540             try {
541                 builder.setLocale(StoreUtils.stringToLocale(
542                         resultIntent.getStringExtra(EXTRA_PROVISIONING_LOCALE)));
543             } catch (IllformedLocaleException e) {
544                 ProvisionLogger.loge("Could not parse locale.", e);
545             }
546         }
547     }
548 
maybeUpdateDisclaimers(ProvisioningParams.Builder builder, Intent resultIntent)549     private void maybeUpdateDisclaimers(ProvisioningParams.Builder builder, Intent resultIntent) {
550         if (resultIntent.hasExtra(EXTRA_PROVISIONING_DISCLAIMERS)) {
551             try {
552                 DisclaimersParam disclaimersParam = mDisclaimerParserProvider.apply(
553                         mContext,
554                         mSharedPreferences.getProvisioningId())
555                         .parse(resultIntent.getParcelableArrayExtra(
556                                 EXTRA_PROVISIONING_DISCLAIMERS));
557                 builder.setDisclaimersParam(disclaimersParam);
558             } catch (ClassCastException e) {
559                 ProvisionLogger.loge("Could not parse disclaimer params.", e);
560             }
561         }
562     }
563 
maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder, Intent resultIntent)564     private void maybeUpdateSkipEducationScreens(ProvisioningParams.Builder builder,
565             Intent resultIntent) {
566         if (resultIntent.hasExtra(EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS)) {
567             builder.setSkipEducationScreens(resultIntent.getBooleanExtra(
568                     EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, /* defaultValue */ false));
569         }
570     }
571 
maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder, Intent resultIntent)572     private void maybeUpdateAccountToMigrate(ProvisioningParams.Builder builder,
573             Intent resultIntent) {
574         if (resultIntent.hasExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)) {
575             final Account account = resultIntent.getParcelableExtra(
576                     EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE);
577             builder.setAccountToMigrate(account);
578         }
579     }
580 
581     /**
582      * Appends the admin bundle in {@code resultIntent}, if provided, to the existing admin bundle,
583      * if it exists, and stores the result in {@code builder}.
584      */
maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder, Intent resultIntent)585     private void maybeUpdateAdminExtrasBundle(ProvisioningParams.Builder builder,
586             Intent resultIntent) {
587         if (resultIntent.hasExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) {
588             PersistableBundle resultBundle =
589                     resultIntent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE);
590             if (mViewModel.getParams().adminExtrasBundle != null) {
591                 PersistableBundle existingBundle =
592                         new PersistableBundle(mViewModel.getParams().adminExtrasBundle);
593                 existingBundle.putAll(resultBundle);
594                 resultBundle = existingBundle;
595             }
596             builder.setAdminExtrasBundle(resultBundle);
597         }
598     }
599 
maybeUpdateKeepAccountMigrated( ProvisioningParams.Builder builder, Intent resultIntent)600     private void maybeUpdateKeepAccountMigrated(
601             ProvisioningParams.Builder builder,
602             Intent resultIntent) {
603         if (resultIntent.hasExtra(EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION)) {
604             final boolean keepAccountMigrated = resultIntent.getBooleanExtra(
605                     EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION,
606                     DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED);
607             builder.setKeepAccountMigrated(keepAccountMigrated);
608         }
609     }
610 
maybeUpdateLeaveAllSystemAppsEnabled( ProvisioningParams.Builder builder, Intent resultIntent)611     private void maybeUpdateLeaveAllSystemAppsEnabled(
612             ProvisioningParams.Builder builder,
613             Intent resultIntent) {
614         if (resultIntent.hasExtra(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED)) {
615             final boolean leaveAllSystemAppsEnabled = resultIntent.getBooleanExtra(
616                     EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
617                     DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED);
618             builder.setLeaveAllSystemAppsEnabled(leaveAllSystemAppsEnabled);
619         }
620     }
621 
updateProvisioningFlowState(@lowType int flowType)622     void updateProvisioningFlowState(@FlowType int flowType) {
623         mViewModel.updateParams(mViewModel.getParams().toBuilder().setFlowType(flowType).build());
624     }
625 
getAdditionalExtrasForGetProvisioningModeIntent()626     Bundle getAdditionalExtrasForGetProvisioningModeIntent() {
627         Bundle bundle = new Bundle();
628         if (shouldPassPersonalDataToAdminApp()) {
629             final TelephonyManager telephonyManager = mContext.getSystemService(
630                     TelephonyManager.class);
631             bundle.putString(EXTRA_PROVISIONING_IMEI, telephonyManager.getImei());
632             bundle.putString(EXTRA_PROVISIONING_SERIAL_NUMBER, Build.getSerial());
633         }
634         ProvisioningParams params = mViewModel.getParams();
635         bundle.putParcelable(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
636                 params.adminExtrasBundle);
637         bundle.putIntegerArrayList(EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES,
638                 params.allowedProvisioningModes);
639 
640         if (params.allowedProvisioningModes.contains(
641                 DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE)) {
642             bundle.putBoolean(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT,
643                     params.deviceOwnerPermissionGrantOptOut);
644         }
645         return bundle;
646     }
647 
shouldPassPersonalDataToAdminApp()648     private boolean shouldPassPersonalDataToAdminApp() {
649         ProvisioningParams params = mViewModel.getParams();
650         return params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED
651                 || params.initiatorRequestedProvisioningModes == FLAG_SUPPORTED_MODES_DEVICE_OWNER;
652     }
653 
createViewTermsIntent()654     protected Intent createViewTermsIntent() {
655         return new Intent(mContext, getTermsActivityClass())
656                 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, mViewModel.getParams());
657     }
658 
getTermsActivityClass()659     private Class<? extends Activity> getTermsActivityClass() {
660         return getBaseApplication().getActivityClassForScreen(ManagedProvisioningScreens.TERMS);
661     }
662 
getBaseApplication()663     private ManagedProvisioningBaseApplication getBaseApplication() {
664         return (ManagedProvisioningBaseApplication) mContext.getApplicationContext();
665     }
666 
667     /**
668      * Start provisioning for real. In profile owner case, double check that the launcher
669      * supports managed profiles if necessary. In device owner case, possibly create a new user
670      * before starting provisioning.
671      */
continueProvisioningAfterUserConsent()672     public void continueProvisioningAfterUserConsent() {
673         mProvisioningAnalyticsTracker.logProvisioningAction(
674                 mContext, mViewModel.getParams().provisioningAction);
675 
676         // check if encryption is required
677         if (isEncryptionRequired()) {
678             if (mDevicePolicyManager.getStorageEncryptionStatus()
679                     == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
680                 mUi.showErrorAndClose(R.string.cant_set_up_device,
681                         R.string.device_doesnt_allow_encryption_contact_admin,
682                         "This device does not support encryption, and "
683                                 + DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION
684                                 + " was not passed.");
685             } else {
686                 mUi.requestEncryption(mViewModel.getParams());
687                 // we come back to this method after returning from encryption dialog
688                 // TODO: refactor as evil - logic should be less spread out
689             }
690             return;
691         }
692 
693         if (isProfileOwnerProvisioning()) { // PO case
694             // Check whether the current launcher supports managed profiles.
695             if (!mUtils.currentLauncherSupportsManagedProfiles(mContext)) {
696                 mUi.showCurrentLauncherInvalid();
697                 // we come back to this method after returning from launcher dialog
698                 // TODO: refactor as evil - logic should be less spread out
699                 return;
700             } else {
701                 // Cancel the boot reminder as provisioning has now started.
702                 mViewModel.getEncryptionController().cancelEncryptionReminder();
703                 stopTimeLogger();
704                 mUi.startProvisioning(mViewModel.getParams());
705             }
706         } else { // DO case
707             // Cancel the boot reminder as provisioning has now started.
708             mViewModel.getEncryptionController().cancelEncryptionReminder();
709             stopTimeLogger();
710             mUi.startProvisioning(mViewModel.getParams());
711         }
712 
713         mViewModel.onProvisioningStartedAfterUserConsent();
714     }
715 
716     /** @return False if condition preventing further provisioning */
717     @VisibleForTesting
checkFactoryResetProtection(ProvisioningParams params, String callingPackage)718     boolean checkFactoryResetProtection(ProvisioningParams params, String callingPackage) {
719         if (skipFactoryResetProtectionCheck(params, callingPackage)) {
720             return true;
721         }
722         if (factoryResetProtected()) {
723             mUi.showErrorAndClose(R.string.cant_set_up_device,
724                     R.string.device_has_reset_protection_contact_admin,
725                     "Factory reset protection blocks provisioning.");
726             return false;
727         }
728         return true;
729     }
730 
skipFactoryResetProtectionCheck( ProvisioningParams params, String callingPackage)731     private boolean skipFactoryResetProtectionCheck(
732             ProvisioningParams params, String callingPackage) {
733         if (TextUtils.isEmpty(callingPackage)) {
734             return false;
735         }
736         String persistentDataPackageName = mContext.getResources()
737                 .getString(com.android.internal.R.string.config_persistentDataPackageName);
738         try {
739             // Only skip the FRP check if the caller is the package responsible for maintaining FRP
740             // - i.e. if this is a flow for restoring device owner after factory reset.
741             PackageInfo callingPackageInfo = mPackageManager.getPackageInfo(callingPackage, 0);
742             return callingPackageInfo != null
743                     && callingPackageInfo.applicationInfo != null
744                     && callingPackageInfo.applicationInfo.isSystemApp()
745                     && !TextUtils.isEmpty(persistentDataPackageName)
746                     && callingPackage.equals(persistentDataPackageName)
747                     && params != null
748                     && params.startedByTrustedSource;
749         } catch (PackageManager.NameNotFoundException e) {
750             ProvisionLogger.loge("Calling package not found.", e);
751             return false;
752         }
753     }
754 
755     /** @return False if condition preventing further provisioning */
checkDevicePolicyPreconditions()756     @VisibleForTesting protected boolean checkDevicePolicyPreconditions() {
757         ProvisioningParams params = mViewModel.getParams();
758         int provisioningPreCondition = mDevicePolicyManager.checkProvisioningPreCondition(
759                 params.provisioningAction,
760                 params.inferDeviceAdminPackageName());
761         // Check whether provisioning is allowed for the current action.
762         if (provisioningPreCondition != CODE_OK) {
763             mProvisioningAnalyticsTracker.logProvisioningNotAllowed(mContext,
764                     provisioningPreCondition);
765             showProvisioningErrorAndClose(
766                     params.provisioningAction, provisioningPreCondition);
767             return false;
768         }
769         return true;
770     }
771 
772     /** @return False if condition preventing further provisioning */
tryParseParameters(Intent intent)773     private boolean tryParseParameters(Intent intent) {
774         try {
775             // Read the provisioning params from the provisioning intent
776             mViewModel.loadParamsIfNecessary(intent);
777         } catch (IllegalProvisioningArgumentException e) {
778             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
779                     e.getMessage());
780             return false;
781         }
782         return true;
783     }
784 
785     /** @return False if condition preventing further provisioning */
verifyActionAndCaller(Intent intent, String callingPackage)786     @VisibleForTesting protected boolean verifyActionAndCaller(Intent intent,
787             String callingPackage) {
788         if (verifyActionAndCallerInner(intent, callingPackage)) {
789             return true;
790         } else {
791             mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
792                     "invalid intent or calling package");
793             return false;
794         }
795     }
796 
verifyActionAndCallerInner(Intent intent, String callingPackage)797     private boolean verifyActionAndCallerInner(Intent intent, String callingPackage) {
798         // If this is a resume after encryption or trusted intent, we verify the activity alias.
799         // Otherwise, verify that the calling app is trying to set itself as Device/ProfileOwner
800         if (ACTION_RESUME_PROVISIONING.equals(intent.getAction())) {
801             return verifyActivityAlias(intent, "PreProvisioningActivityAfterEncryption");
802         } else if (ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
803             return verifyActivityAlias(intent, "PreProvisioningActivityViaNfc");
804         } else if (ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction())
805                 || ACTION_PROVISION_FINANCED_DEVICE.equals(intent.getAction())) {
806             return verifyActivityAlias(intent, "PreProvisioningActivityViaTrustedApp");
807         } else {
808             return verifyCaller(callingPackage);
809         }
810     }
811 
verifyActivityAlias(Intent intent, String activityAlias)812     private boolean verifyActivityAlias(Intent intent, String activityAlias) {
813         ComponentName componentName = intent.getComponent();
814         if (componentName == null || componentName.getClassName() == null) {
815             ProvisionLogger.loge("null class in component when verifying activity alias "
816                     + activityAlias);
817             return false;
818         }
819 
820         if (!componentName.getClassName().endsWith(activityAlias)) {
821             ProvisionLogger.loge("Looking for activity alias " + activityAlias + ", but got "
822                     + componentName.getClassName());
823             return false;
824         }
825 
826         return true;
827     }
828 
829     /**
830      * Verify that the caller is trying to set itself as owner.
831      * @return false if the caller is trying to set a different package as owner.
832      */
verifyCaller(@onNull String callingPackage)833     private boolean verifyCaller(@NonNull String callingPackage) {
834         if (callingPackage == null) {
835             ProvisionLogger.loge("Calling package is null. Was startActivityForResult used to "
836                     + "start this activity?");
837             return false;
838         }
839 
840         if (!callingPackage.equals(mViewModel.getParams().inferDeviceAdminPackageName())) {
841             ProvisionLogger.loge("Permission denied, "
842                     + "calling package tried to set a different package as owner. ");
843             return false;
844         }
845 
846         return true;
847     }
848 
849     /**
850      * Returns whether the device needs encryption.
851      */
isEncryptionRequired()852     private boolean isEncryptionRequired() {
853         return !mViewModel.getParams().skipEncryption && mUtils.isEncryptionRequired();
854     }
855 
856     /**
857      * Returns whether the device is frp protected during setup wizard.
858      */
factoryResetProtected()859     private boolean factoryResetProtected() {
860         // If we are started during setup wizard, check for factory reset protection.
861         // If the device is already setup successfully, do not check factory reset protection.
862         if (mSettingsFacade.isDeviceProvisioned(mContext)) {
863             ProvisionLogger.logd("Device is provisioned, FRP not required.");
864             return false;
865         }
866 
867         if (mPdbManager == null) {
868             ProvisionLogger.logd("Reset protection not supported.");
869             return false;
870         }
871         int size = mPdbManager.getDataBlockSize();
872         ProvisionLogger.logd("Data block size: " + size);
873         return size > 0;
874     }
875 
876     /**
877      * Returns whether activity to pick wifi can be requested or not.
878      */
canRequestWifiPick()879     private boolean canRequestWifiPick() {
880         return mPackageManager.resolveActivity(mUtils.getWifiPickIntent(), 0) != null;
881     }
882 
883     /**
884      * Returns whether the provisioning process is a profile owner provisioning process.
885      */
isProfileOwnerProvisioning()886     public boolean isProfileOwnerProvisioning() {
887         return mUtils.isProfileOwnerAction(mViewModel.getParams().provisioningAction);
888     }
889 
890     /**
891      * Returns whether the provisioning process is a device owner provisioning process.
892      */
isDeviceOwnerProvisioning()893     public boolean isDeviceOwnerProvisioning() {
894         return mUtils.isDeviceOwnerAction(mViewModel.getParams().provisioningAction);
895     }
896 
897 
898     @Nullable
getParams()899     public ProvisioningParams getParams() {
900         return mViewModel.getParams();
901     }
902 
903     /**
904      * Notifies the time logger to stop.
905      */
stopTimeLogger()906     public void stopTimeLogger() {
907         mViewModel.getTimeLogger().stop();
908     }
909 
910     /**
911      * Log if PreProvisioning was cancelled.
912      */
logPreProvisioningCancelled()913     public void logPreProvisioningCancelled() {
914         mProvisioningAnalyticsTracker.logProvisioningCancelled(mContext,
915                 CANCELLED_BEFORE_PROVISIONING);
916     }
917 
918     /**
919      * Logs the provisioning flow type.
920      */
logProvisioningFlowType()921     public void logProvisioningFlowType() {
922         mProvisioningAnalyticsTracker.logProvisioningFlowType(mViewModel.getParams());
923     }
924 
925     /**
926      * Removes a user profile. If we are in COMP case, and were blocked by having to delete a user,
927      * resumes COMP provisioning.
928      */
removeUser(int userProfileId)929     public void removeUser(int userProfileId) {
930         // There is a possibility that the DO has set the disallow remove managed profile user
931         // restriction, but is initiating the provisioning. In this case, we still want to remove
932         // the managed profile.
933         // We know that we can remove the managed profile because we checked
934         // DevicePolicyManager.checkProvisioningPreCondition
935         mUserManager.removeUserEvenWhenDisallowed(userProfileId);
936     }
937 
getSettingsFacade()938     SettingsFacade getSettingsFacade() {
939         return mSettingsFacade;
940     }
941 
getPolicyComplianceUtils()942     public PolicyComplianceUtils getPolicyComplianceUtils() {
943         return mPolicyComplianceUtils;
944     }
945 
getGetProvisioningModeUtils()946     public GetProvisioningModeUtils getGetProvisioningModeUtils() {
947         return mGetProvisioningModeUtils;
948     }
949 
onReturnFromProvisioning()950     void onReturnFromProvisioning() {
951         mViewModel.onReturnFromProvisioning();
952     }
953 
getState()954     LiveData<Integer> getState() {
955         return mViewModel.getState();
956     }
957 
showProvisioningErrorAndClose(String action, int provisioningPreCondition)958     private void showProvisioningErrorAndClose(String action, int provisioningPreCondition) {
959         // Try to show an error message explaining why provisioning is not allowed.
960         switch (action) {
961             case ACTION_PROVISION_MANAGED_PROFILE:
962                 showManagedProfileErrorAndClose(provisioningPreCondition);
963                 return;
964             case ACTION_PROVISION_MANAGED_DEVICE:
965                 showDeviceOwnerErrorAndClose(provisioningPreCondition);
966                 return;
967         }
968         // This should never be the case, as showProvisioningError is always called after
969         // verifying the supported provisioning actions.
970     }
971 
showManagedProfileErrorAndClose(int provisioningPreCondition)972     private void showManagedProfileErrorAndClose(int provisioningPreCondition) {
973         UserInfo userInfo = mUserManager.getUserInfo(mUserManager.getUserHandle());
974         ProvisionLogger.logw("DevicePolicyManager.checkProvisioningPreCondition returns code: "
975                 + provisioningPreCondition);
976         // If this is organization-owned provisioning, do not show any other error dialog, just
977         // show the factory reset dialog and return.
978         // This cannot be abused by regular apps to force a factory reset because
979         // isOrganizationOwnedProvisioning is only set to true if the provisioning action was
980         // from a trusted source. See Utils.isOrganizationOwnedProvisioning where we check for
981         // ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE which is guarded by the
982         // DISPATCH_PROVISIONING_MESSAGE system|privileged permission.
983         if (mUtils.isOrganizationOwnedAllowed(mViewModel.getParams())) {
984             ProvisionLogger.loge(
985                     "Provisioning preconditions failed for organization-owned provisioning.");
986             mUi.showFactoryResetDialog(R.string.cant_set_up_device,
987                     R.string.contact_your_admin_for_help);
988             return;
989         }
990         switch (provisioningPreCondition) {
991             case CODE_MANAGED_USERS_NOT_SUPPORTED:
992                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
993                         R.string.work_profile_cant_be_added_contact_admin,
994                         "Exiting managed profile provisioning, managed profiles "
995                                 + "feature is not available");
996                 break;
997             case CODE_CANNOT_ADD_MANAGED_PROFILE:
998                 if (!userInfo.canHaveProfile()) {
999                     mUi.showErrorAndClose(R.string.cant_add_work_profile,
1000                             R.string.work_profile_cant_be_added_contact_admin,
1001                             "Exiting managed profile provisioning, calling user cannot "
1002                                     + "have managed profiles");
1003                 } else if (!canAddManagedProfile()) {
1004                     mUi.showErrorAndClose(R.string.cant_add_work_profile,
1005                             R.string.work_profile_cant_be_added_contact_admin,
1006                             "Exiting managed profile provisioning, a managed profile "
1007                                     + "already exists");
1008                 } else {
1009                     mUi.showErrorAndClose(R.string.cant_add_work_profile,
1010                             R.string.work_profile_cant_be_added_contact_admin,
1011                             "Exiting managed profile provisioning, cannot add more managed "
1012                                     + "profiles");
1013                 }
1014                 break;
1015             case CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS:
1016                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
1017                         R.string.work_profile_cant_be_added_contact_admin,
1018                         "Exiting managed profile provisioning, "
1019                                 + "provisioning not allowed by OEM");
1020                 break;
1021             default:
1022                 mUi.showErrorAndClose(R.string.cant_add_work_profile,
1023                         R.string.contact_your_admin_for_help,
1024                         "Managed profile provisioning not allowed for an unknown "
1025                                 + "reason, code: " + provisioningPreCondition);
1026         }
1027     }
1028 
canAddManagedProfile()1029     private boolean canAddManagedProfile() {
1030         return mUserManager.canAddMoreManagedProfiles(
1031                 mContext.getUserId(), /* allowedToRemoveOne= */ false);
1032     }
1033 
showDeviceOwnerErrorAndClose(int provisioningPreCondition)1034     private void showDeviceOwnerErrorAndClose(int provisioningPreCondition) {
1035         switch (provisioningPreCondition) {
1036             case CODE_HAS_DEVICE_OWNER:
1037             case CODE_USER_SETUP_COMPLETED:
1038                 mUi.showErrorAndClose(R.string.device_already_set_up,
1039                         R.string.if_questions_contact_admin, "Device already provisioned.");
1040                 return;
1041             case CODE_NOT_SYSTEM_USER:
1042                 mUi.showErrorAndClose(R.string.cant_set_up_device,
1043                         R.string.contact_your_admin_for_help,
1044                         "Device owner can only be set up for USER_SYSTEM.");
1045                 return;
1046             case CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS:
1047                 mUi.showErrorAndClose(R.string.cant_set_up_device,
1048                         R.string.contact_your_admin_for_help,
1049                         "Provisioning not allowed by OEM");
1050                 return;
1051         }
1052         mUi.showErrorAndClose(R.string.cant_set_up_device, R.string.contact_your_admin_for_help,
1053                 "Device Owner provisioning not allowed for an unknown reason.");
1054     }
1055 }
1056