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.model;
18 
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMERS;
24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION;
25 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED;
26 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE;
27 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME;
28 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ORGANIZATION_NAME;
29 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS;
30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SUPPORT_URL;
32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE;
33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_USE_MOBILE_DATA;
34 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_CLOUD_ENROLLMENT;
35 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_MANAGED_ACCOUNT;
36 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
37 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
38 
39 import static com.android.internal.util.Preconditions.checkArgument;
40 import static com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences.DEFAULT_PROVISIONING_ID;
41 import static com.android.managedprovisioning.common.StoreUtils.accountToPersistableBundle;
42 import static com.android.managedprovisioning.common.StoreUtils.getObjectAttrFromPersistableBundle;
43 import static com.android.managedprovisioning.common.StoreUtils.getStringAttrFromPersistableBundle;
44 import static com.android.managedprovisioning.common.StoreUtils.putPersistableBundlableIfNotNull;
45 
46 import static java.util.Objects.requireNonNull;
47 
48 import android.accounts.Account;
49 import android.annotation.IntDef;
50 import android.app.admin.DevicePolicyManager;
51 import android.content.ComponentName;
52 import android.content.Context;
53 import android.os.Parcel;
54 import android.os.Parcelable;
55 import android.os.PersistableBundle;
56 import android.util.AtomicFile;
57 import android.util.Xml;
58 
59 import androidx.annotation.Nullable;
60 
61 import com.android.internal.util.FastXmlSerializer;
62 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
63 import com.android.managedprovisioning.common.PersistableBundlable;
64 import com.android.managedprovisioning.common.ProvisionLogger;
65 import com.android.managedprovisioning.common.StoreUtils;
66 import com.android.managedprovisioning.common.Utils;
67 
68 import org.xmlpull.v1.XmlPullParser;
69 import org.xmlpull.v1.XmlPullParserException;
70 import org.xmlpull.v1.XmlSerializer;
71 
72 import java.io.File;
73 import java.io.FileInputStream;
74 import java.io.FileOutputStream;
75 import java.io.IOException;
76 import java.lang.annotation.Retention;
77 import java.lang.annotation.RetentionPolicy;
78 import java.nio.charset.StandardCharsets;
79 import java.util.ArrayList;
80 import java.util.Arrays;
81 import java.util.Locale;
82 import java.util.stream.Collectors;
83 
84 /**
85  * Provisioning parameters for Device Owner and Profile Owner provisioning.
86  */
87 public final class ProvisioningParams extends PersistableBundlable {
88     public static final long DEFAULT_LOCAL_TIME = -1;
89     public static final boolean DEFAULT_STARTED_BY_TRUSTED_SOURCE = false;
90     public static final boolean DEFAULT_IS_NFC = false;
91     public static final boolean DEFAULT_IS_QR_PROVISIONING = false;
92     public static final boolean DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED = false;
93     public static final boolean DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION = false;
94     public static final boolean DEFAULT_EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS = false;
95     public static final boolean DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED = false;
96     public static final boolean DEFAULT_EXTRA_PROVISIONING_USE_MOBILE_DATA = false;
97     public static final boolean DEFAULT_EXTRA_PROVISIONING_IS_ORGANIZATION_OWNED = false;
98     public static final ArrayList<Integer> DEFAULT_EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES =
99             new ArrayList<>();
100     public static final int DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES = 0;
101     public static final boolean DEFAULT_EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = false;
102     public static final boolean DEFAULT_EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = false;
103     public static final boolean DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT = false;
104     public static final boolean DEFAULT_EXTRA_ALLOW_OFFLINE = false;
105     public static final boolean DEFAULT_EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT = false;
106 
107 
108     // Intent extra used internally for passing data between activities and service.
109     public static final String EXTRA_PROVISIONING_PARAMS = "provisioningParams";
110 
111     public static final int FLOW_TYPE_UNSPECIFIED = 0;
112     public static final int FLOW_TYPE_LEGACY = 1;
113     public static final int FLOW_TYPE_ADMIN_INTEGRATED = 2;
114 
115     @IntDef(prefix = { "PROVISIONING_TRIGGER_" }, value = {
116             PROVISIONING_TRIGGER_UNSPECIFIED,
117             PROVISIONING_TRIGGER_CLOUD_ENROLLMENT,
118             PROVISIONING_TRIGGER_QR_CODE,
119             PROVISIONING_TRIGGER_MANAGED_ACCOUNT
120     })
121     @Retention(RetentionPolicy.SOURCE)
122     public @interface ProvisioningTrigger {}
123 
124     @IntDef(prefix = { "FLOW_TYPE_" }, value = {
125             FLOW_TYPE_UNSPECIFIED,
126             FLOW_TYPE_LEGACY,
127             FLOW_TYPE_ADMIN_INTEGRATED
128     })
129     @Retention(RetentionPolicy.SOURCE)
130     public @interface FlowType {}
131 
132     private static final String TAG_PROVISIONING_ID = "provisioning-id";
133     private static final String TAG_PROVISIONING_PARAMS = "provisioning-params";
134     private static final String TAG_WIFI_INFO = "wifi-info";
135     private static final String TAG_PACKAGE_DOWNLOAD_INFO = "download-info";
136     private static final String TAG_STARTED_BY_TRUSTED_SOURCE = "started-by-trusted-source";
137     private static final String TAG_IS_NFC = "started-is-nfc";
138     private static final String TAG_IS_QR_PROVISIONING = "is-qr-provisioning";
139     private static final String TAG_PROVISIONING_ACTION = "provisioning-action";
140     private static final String TAG_IS_ORGANIZATION_OWNED_PROVISIONING =
141             "is-organization-owned-provisioning";
142     private static final String TAG_ALLOWED_PROVISIONING_MODES =
143             "allowed-provisioning-modes";
144     private static final String TAG_INITIATOR_REQUESTED_PROVISIONING_MODES =
145             "initiator-requested-provisioning-modes";
146     private static final String TAG_FLOW_TYPE = "flow-type";
147     private static final String TAG_ALLOW_PROVISIONING_AFTER_USER_SETUP_COMPLETE =
148             "allow-provisioning-after-user-setup-complete";
149     private static final String TAG_PROVISIONING_TRIGGER = "provisioning-trigger";
150     private static final String TAG_SKIP_OWNERSHIP_DISCLAIMER = "skip-ownership-disclaimer";
151     private static final String TAG_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE =
152             "provisioning-return-before-policy-compliance";
153     private static final String TAG_DEVICE_OWNER_PERMISSION_GRANT_OPT_OUT =
154             "device-owner-opt-out-of-permission-grants";
155     private static final String TAG_ALLOW_OFFLINE = "allow-offline";
156     private static final String TAG_ROLE_HOLDER_PACKAGE_DOWNLOAD_INFO =
157             "role-holder-download-info";
158     private static final String TAG_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT =
159             "provisioning-should-launch-result-intent";
160 
161     public static final Parcelable.Creator<ProvisioningParams> CREATOR
162             = new Parcelable.Creator<ProvisioningParams>() {
163         @Override
164         public ProvisioningParams createFromParcel(Parcel in) {
165             return new ProvisioningParams(in);
166         }
167 
168         @Override
169         public ProvisioningParams[] newArray(int size) {
170             return new ProvisioningParams[size];
171         }
172     };
173 
174     public final long provisioningId;
175 
176     @Nullable
177     public final String timeZone;
178 
179     public final long localTime;
180 
181     @Nullable
182     public final Locale locale;
183 
184     /** WiFi configuration. */
185     @Nullable
186     public final WifiInfo wifiInfo;
187 
188     public final boolean useMobileData;
189 
190     /**
191      * Package name of the device admin package.
192      *
193      * <p>At least one one of deviceAdminPackageName and deviceAdminComponentName should be
194      * non-null.
195      * <p>
196      * In most cases, it is preferable to access the admin package name using
197      * {@link #inferDeviceAdminPackageName}.
198      */
199     @Deprecated
200     @Nullable
201     public final String deviceAdminPackageName;
202 
203     /**
204      * {@link ComponentName} of the device admin package.
205      *
206      * <p>At least one one of deviceAdminPackageName and deviceAdminComponentName should be
207      * non-null.
208      * <p>
209      * In most cases, it is preferable to access the admin component name using
210      * {@link #inferDeviceAdminComponentName(Utils, Context, int)} .
211      */
212     @Nullable
213     public final ComponentName deviceAdminComponentName;
214 
215     public final String organizationName;
216     public final String supportUrl;
217 
218     /** {@link Account} that should be migrated to the managed profile. */
219     @Nullable
220     public final Account accountToMigrate;
221 
222     /** True if the account will not be removed from the calling user after it is migrated. */
223     public final boolean keepAccountMigrated;
224 
225     /** Provisioning action comes along with the provisioning data. */
226     public final String provisioningAction;
227 
228     /** The download information of device admin package. */
229     @Nullable
230     public final PackageDownloadInfo deviceAdminDownloadInfo;
231 
232     /** List of disclaimers */
233     @Nullable
234     public final DisclaimersParam disclaimersParam;
235 
236     /**
237      * Custom key-value pairs from enterprise mobility management which are passed to device admin
238      * package after provisioning.
239      *
240      * <p>Note that {@link ProvisioningParams} is not immutable because this field is mutable.
241      */
242     @Nullable
243     public final PersistableBundle adminExtrasBundle;
244 
245     /**
246      * True iff provisioning flow was started by a trusted app. This includes Nfc bump and QR code.
247      */
248     public final boolean startedByTrustedSource;
249 
250     public final boolean isNfc;
251 
252     public final boolean isQrProvisioning;
253 
254     /** True if all system apps should be enabled after provisioning. */
255     public final boolean leaveAllSystemAppsEnabled;
256 
257     /** True if device encryption should be skipped. */
258     public final boolean skipEncryption;
259 
260     public final boolean skipEducationScreens;
261 
262     /**
263      * True if the provisioning is done on a device owned by the organization.
264      *
265      * <p>For the admin-integrated flow, this field is only set after the admin app
266      * picks a provisioning mode.
267      */
268     public final boolean isOrganizationOwnedProvisioning;
269 
270     /**
271      * {@link ArrayList} of {@link Integer} containing a subset of {{@link
272      * DevicePolicyManager#PROVISIONING_MODE_MANAGED_PROFILE}, {@link
273      * DevicePolicyManager#PROVISIONING_MODE_FULLY_MANAGED_DEVICE}, {@link
274      * DevicePolicyManager#PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}}.
275      **/
276     public final ArrayList<Integer> allowedProvisioningModes;
277 
278     /**
279      * Integer specifying what provisioning modes have been specified by the provisioning
280      * initiator.
281      *
282      * <p>Can be a combination of {@link
283      * DevicePolicyManager#FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}, {@link
284      * DevicePolicyManager#FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}, {@link
285      * DevicePolicyManager#FLAG_SUPPORTED_MODES_DEVICE_OWNER} or if not relevant to the
286      * admin-integrated flow, {@link ProvisioningParams#DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES}.
287      *
288      */
289     public final int initiatorRequestedProvisioningModes;
290 
291     /** True if provisioning after user setup complete should be allowed. */
292     public final boolean allowProvisioningAfterUserSetupComplete;
293 
294     /**
295      * The type of flow to be performed.
296      * <p>Must be one of {@link #FLOW_TYPE_UNSPECIFIED}, {@link #FLOW_TYPE_LEGACY} or {@link
297      * #FLOW_TYPE_ADMIN_INTEGRATED}.
298      **/
299     public final @FlowType int flowType;
300 
301     /**
302      * The way provisioning was started.
303      * <p>Can be one of {@link DevicePolicyManager#PROVISIONING_TRIGGER_CLOUD_ENROLLMENT}, {@link
304      * DevicePolicyManager#PROVISIONING_TRIGGER_QR_CODE}, {@link
305      * DevicePolicyManager#PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER} or {@link
306      * DevicePolicyManager#PROVISIONING_TRIGGER_UNSPECIFIED}.
307      */
308     public final @ProvisioningTrigger int provisioningTrigger;
309 
310     /**
311      * Whether to skip the ownership disclaimer.
312      */
313     public final boolean skipOwnershipDisclaimer;
314 
315     /**
316      * True if the provisioning flow should return before starting the admin app's {@link
317      * DevicePolicyManager#ACTION_ADMIN_POLICY_COMPLIANCE} handler. Default value is {@code true}.
318      */
319     public final boolean returnBeforePolicyCompliance;
320 
321     /**
322      * True if the device owner has opted out of controlling permission grants for
323      * sensors-related permissions. See {@link DevicePolicyManager#setPermissionGrantState}
324      */
325     public final boolean deviceOwnerPermissionGrantOptOut;
326 
327 
328     /**
329      * {@code true} if offline provisioning is allowed
330      *
331      * <p>In T this can also be used to force platform side provisioning.
332      *
333      * @see DevicePolicyManager#EXTRA_PROVISIONING_ALLOW_OFFLINE
334      */
335     public final boolean allowOffline;
336 
337     /**
338      * {@code true} if provisioning should launch the result intent returned by the
339      * device manager role holder.
340      *
341      * {@code false} by default.
342      *
343      * @see DevicePolicyManager#EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT
344      */
345     public final boolean provisioningShouldLaunchResultIntent;
346 
347     /** The download information of the role holder package. */
348     @Nullable
349     public final PackageDownloadInfo roleHolderDownloadInfo;
350 
inferStaticDeviceAdminPackageName(ComponentName deviceAdminComponentName, String deviceAdminPackageName)351     public static String inferStaticDeviceAdminPackageName(ComponentName deviceAdminComponentName,
352             String deviceAdminPackageName) {
353         if (deviceAdminComponentName != null) {
354             return deviceAdminComponentName.getPackageName();
355         }
356         return deviceAdminPackageName;
357     }
358 
inferDeviceAdminPackageName()359     public String inferDeviceAdminPackageName() {
360         return inferStaticDeviceAdminPackageName(deviceAdminComponentName, deviceAdminPackageName);
361     }
362 
363     /**
364      * Due to legacy reason, DPC is allowed to provide either package name or the component name.
365      * If component name is not {@code null}, we will return it right away. Otherwise, we will
366      * infer the component name.
367      * <p>
368      * In most cases, it is preferable to access the admin component name using this method.
369      * But if the purpose is to verify the device admin component name, you should use
370      * {@link Utils#findDeviceAdmin(String, ComponentName, Context, int)} instead.
371      */
inferDeviceAdminComponentName(Utils utils, Context context, int userId)372     public ComponentName inferDeviceAdminComponentName(Utils utils, Context context, int userId)
373             throws IllegalProvisioningArgumentException {
374         if (deviceAdminComponentName != null) {
375             return deviceAdminComponentName;
376         }
377         return utils.findDeviceAdmin(
378                 deviceAdminPackageName, deviceAdminComponentName, context, userId);
379     }
380 
ProvisioningParams(Builder builder)381     private ProvisioningParams(Builder builder) {
382         provisioningId = builder.mProvisioningId;
383         timeZone = builder.mTimeZone;
384         localTime = builder.mLocalTime;
385         locale = builder.mLocale;
386 
387         wifiInfo = builder.mWifiInfo;
388         useMobileData = builder.mUseMobileData;
389 
390         deviceAdminComponentName = builder.mDeviceAdminComponentName;
391         deviceAdminPackageName = builder.mDeviceAdminPackageName;
392         organizationName = builder.mOrganizationName;
393         supportUrl = builder.mSupportUrl;
394 
395         deviceAdminDownloadInfo = builder.mDeviceAdminDownloadInfo;
396         disclaimersParam = builder.mDisclaimersParam;
397 
398         adminExtrasBundle = builder.mAdminExtrasBundle;
399 
400         startedByTrustedSource = builder.mStartedByTrustedSource;
401         isNfc = builder.mIsNfc;
402         isQrProvisioning = builder.mIsQrProvisioning;
403         leaveAllSystemAppsEnabled = builder.mLeaveAllSystemAppsEnabled;
404         skipEncryption = builder.mSkipEncryption;
405         accountToMigrate = builder.mAccountToMigrate;
406         provisioningAction = builder.mProvisioningAction;
407         skipEducationScreens = builder.mSkipEducationScreens;
408         keepAccountMigrated = builder.mKeepAccountMigrated;
409 
410         isOrganizationOwnedProvisioning = builder.mIsOrganizationOwnedProvisioning;
411         allowedProvisioningModes = builder.mAllowedProvisioningModes;
412         initiatorRequestedProvisioningModes = builder.mInitiatorRequestedProvisioningModes;
413         flowType = builder.mFlowType;
414         allowProvisioningAfterUserSetupComplete = builder.mAllowProvisioningAfterUserSetupComplete;
415         provisioningTrigger = builder.mProvisioningTrigger;
416         skipOwnershipDisclaimer = builder.mSkipOwnershipDisclaimer;
417         returnBeforePolicyCompliance = builder.mReturnBeforePolicyCompliance;
418         deviceOwnerPermissionGrantOptOut = builder.mDeviceOwnerPermissionGrantOptOut;
419         allowOffline = builder.mAllowOffline;
420         roleHolderDownloadInfo = builder.mRoleHolderDownloadInfo;
421         provisioningShouldLaunchResultIntent = builder.mProvisioningShouldLaunchResultIntent;
422 
423         if (!builder.mSkipValidation) {
424             requireNonNull(provisioningAction);
425             validateFields();
426         }
427     }
428 
ProvisioningParams(Parcel in)429     private ProvisioningParams(Parcel in) {
430         this(createBuilderFromPersistableBundle(
431                 PersistableBundlable.getPersistableBundleFromParcel(in)));
432     }
433 
validateFields()434     private void validateFields() {
435         checkArgument(deviceAdminPackageName != null || deviceAdminComponentName != null);
436     }
437 
438     @Override
toPersistableBundle()439     public PersistableBundle toPersistableBundle() {
440         final PersistableBundle bundle = new PersistableBundle();
441 
442         bundle.putLong(TAG_PROVISIONING_ID, provisioningId);
443         bundle.putString(EXTRA_PROVISIONING_TIME_ZONE, timeZone);
444         bundle.putLong(EXTRA_PROVISIONING_LOCAL_TIME, localTime);
445         bundle.putString(EXTRA_PROVISIONING_LOCALE, StoreUtils.localeToString(locale));
446         putPersistableBundlableIfNotNull(bundle, TAG_WIFI_INFO, wifiInfo);
447         bundle.putBoolean(EXTRA_PROVISIONING_USE_MOBILE_DATA, useMobileData);
448         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, deviceAdminPackageName);
449         bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
450                 StoreUtils.componentNameToString(deviceAdminComponentName));
451         bundle.putString(EXTRA_PROVISIONING_ORGANIZATION_NAME, organizationName);
452         bundle.putString(EXTRA_PROVISIONING_SUPPORT_URL, supportUrl);
453         bundle.putPersistableBundle(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, accountToMigrate == null
454                 ? null : accountToPersistableBundle(accountToMigrate));
455         bundle.putString(TAG_PROVISIONING_ACTION, provisioningAction);
456         putPersistableBundlableIfNotNull(bundle, TAG_PACKAGE_DOWNLOAD_INFO,
457                 deviceAdminDownloadInfo);
458         putPersistableBundlableIfNotNull(bundle, EXTRA_PROVISIONING_DISCLAIMERS,
459                 disclaimersParam);
460         bundle.putPersistableBundle(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, adminExtrasBundle);
461         bundle.putBoolean(TAG_STARTED_BY_TRUSTED_SOURCE, startedByTrustedSource);
462         bundle.putBoolean(TAG_IS_NFC, isNfc);
463         bundle.putBoolean(TAG_IS_QR_PROVISIONING, isQrProvisioning);
464         bundle.putBoolean(EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
465                 leaveAllSystemAppsEnabled);
466         bundle.putBoolean(EXTRA_PROVISIONING_SKIP_ENCRYPTION, skipEncryption);
467         bundle.putBoolean(EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, skipEducationScreens);
468         bundle.putBoolean(EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION, keepAccountMigrated);
469         bundle.putBoolean(TAG_IS_ORGANIZATION_OWNED_PROVISIONING, isOrganizationOwnedProvisioning);
470         bundle.putIntArray(TAG_ALLOWED_PROVISIONING_MODES,
471                 integerArrayListToIntArray(allowedProvisioningModes));
472         bundle.putInt(TAG_INITIATOR_REQUESTED_PROVISIONING_MODES,
473                 initiatorRequestedProvisioningModes);
474         bundle.putInt(TAG_FLOW_TYPE, flowType);
475         bundle.putBoolean(TAG_ALLOW_PROVISIONING_AFTER_USER_SETUP_COMPLETE,
476                 allowProvisioningAfterUserSetupComplete);
477         bundle.putInt(TAG_PROVISIONING_TRIGGER, provisioningTrigger);
478         bundle.putBoolean(TAG_SKIP_OWNERSHIP_DISCLAIMER, skipOwnershipDisclaimer);
479         bundle.putBoolean(TAG_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE,
480                 returnBeforePolicyCompliance);
481         bundle.putBoolean(TAG_DEVICE_OWNER_PERMISSION_GRANT_OPT_OUT,
482                 deviceOwnerPermissionGrantOptOut);
483         bundle.putBoolean(TAG_ALLOW_OFFLINE, allowOffline);
484         putPersistableBundlableIfNotNull(bundle, TAG_ROLE_HOLDER_PACKAGE_DOWNLOAD_INFO,
485                 roleHolderDownloadInfo);
486         bundle.putBoolean(TAG_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT,
487                 provisioningShouldLaunchResultIntent);
488         return bundle;
489     }
490 
fromPersistableBundle(PersistableBundle bundle)491     /* package */ static ProvisioningParams fromPersistableBundle(PersistableBundle bundle) {
492         return createBuilderFromPersistableBundle(bundle).build();
493     }
494 
createBuilderFromPersistableBundle(PersistableBundle bundle)495     private static Builder createBuilderFromPersistableBundle(PersistableBundle bundle) {
496         Builder builder = new Builder(/* skipValidation= */ false);
497         builder.setProvisioningId(bundle.getLong(TAG_PROVISIONING_ID, DEFAULT_PROVISIONING_ID));
498         builder.setTimeZone(bundle.getString(EXTRA_PROVISIONING_TIME_ZONE));
499         builder.setLocalTime(bundle.getLong(EXTRA_PROVISIONING_LOCAL_TIME));
500         builder.setLocale(getStringAttrFromPersistableBundle(bundle,
501                 EXTRA_PROVISIONING_LOCALE, StoreUtils::stringToLocale));
502         builder.setUseMobileData(bundle.getBoolean(EXTRA_PROVISIONING_USE_MOBILE_DATA));
503         builder.setWifiInfo(getObjectAttrFromPersistableBundle(bundle,
504                 TAG_WIFI_INFO, WifiInfo::fromPersistableBundle));
505         builder.setDeviceAdminPackageName(bundle.getString(
506                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME));
507         builder.setDeviceAdminComponentName(getStringAttrFromPersistableBundle(bundle,
508                 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, StoreUtils::stringToComponentName));
509         builder.setOrganizationName(bundle.getString(EXTRA_PROVISIONING_ORGANIZATION_NAME));
510         builder.setSupportUrl(bundle.getString(EXTRA_PROVISIONING_SUPPORT_URL));
511         builder.setAccountToMigrate(getObjectAttrFromPersistableBundle(bundle,
512                 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, StoreUtils::persistableBundleToAccount));
513         builder.setProvisioningAction(bundle.getString(TAG_PROVISIONING_ACTION));
514         builder.setDeviceAdminDownloadInfo(getObjectAttrFromPersistableBundle(bundle,
515                 TAG_PACKAGE_DOWNLOAD_INFO, PackageDownloadInfo::fromPersistableBundle));
516         builder.setDisclaimersParam(getObjectAttrFromPersistableBundle(bundle,
517                 EXTRA_PROVISIONING_DISCLAIMERS, DisclaimersParam::fromPersistableBundle));
518         builder.setAdminExtrasBundle(bundle.getPersistableBundle(
519                 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE));
520         builder.setStartedByTrustedSource(bundle.getBoolean(TAG_STARTED_BY_TRUSTED_SOURCE));
521         builder.setIsNfc(bundle.getBoolean(TAG_IS_NFC));
522         builder.setIsQrProvisioning(bundle.getBoolean(TAG_IS_QR_PROVISIONING));
523         builder.setSkipEncryption(bundle.getBoolean(EXTRA_PROVISIONING_SKIP_ENCRYPTION));
524         builder.setLeaveAllSystemAppsEnabled(bundle.getBoolean(
525                 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED));
526         builder.setSkipEducationScreens(bundle.getBoolean(EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS));
527         builder.setKeepAccountMigrated(bundle.getBoolean(
528                 EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION));
529         builder.setIsOrganizationOwnedProvisioning(bundle.getBoolean(
530                 TAG_IS_ORGANIZATION_OWNED_PROVISIONING));
531         builder.setAllowedProvisioningModes(
532                 intArrayToIntegerArrayList(bundle.getIntArray(TAG_ALLOWED_PROVISIONING_MODES)));
533         builder.setInitiatorRequestedProvisioningModes(bundle.getInt(
534                 TAG_INITIATOR_REQUESTED_PROVISIONING_MODES));
535         builder.setFlowType(bundle.getInt(TAG_FLOW_TYPE));
536         builder.setAllowProvisioningAfterUserSetupComplete(bundle.getBoolean(
537                 TAG_ALLOW_PROVISIONING_AFTER_USER_SETUP_COMPLETE));
538         builder.setProvisioningTrigger(bundle.getInt(TAG_PROVISIONING_TRIGGER));
539         builder.setSkipOwnershipDisclaimer(bundle.getBoolean(TAG_SKIP_OWNERSHIP_DISCLAIMER));
540         builder.setReturnBeforePolicyCompliance(bundle.getBoolean(
541                 TAG_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE));
542         builder.setDeviceOwnerPermissionGrantOptOut(
543                 bundle.getBoolean(TAG_DEVICE_OWNER_PERMISSION_GRANT_OPT_OUT));
544         builder.setAllowOffline(bundle.getBoolean(TAG_ALLOW_OFFLINE));
545         builder.setRoleHolderDownloadInfo(getObjectAttrFromPersistableBundle(
546                 bundle,
547                 TAG_ROLE_HOLDER_PACKAGE_DOWNLOAD_INFO,
548                 PackageDownloadInfo::fromPersistableBundle));
549         builder.setProvisioningShouldLaunchResultIntent(
550                 bundle.getBoolean(TAG_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT));
551         return builder;
552     }
553 
intArrayToIntegerArrayList(int[] intArray)554     private static ArrayList<Integer> intArrayToIntegerArrayList(int[] intArray) {
555         return Arrays.stream(intArray).boxed().collect(Collectors.toCollection(ArrayList::new));
556     }
557 
integerArrayListToIntArray(ArrayList<Integer> arrayList)558     private static int[] integerArrayListToIntArray(ArrayList<Integer> arrayList) {
559         return arrayList.stream().mapToInt(Integer::valueOf).toArray();
560     }
561 
toBuilder()562     public Builder toBuilder() {
563         return createBuilderFromPersistableBundle(toPersistableBundle());
564     }
565 
566     @Override
toString()567     public String toString() {
568         return "ProvisioningParams values: " + toPersistableBundle().toString();
569     }
570 
571     /**
572      * Saves the ProvisioningParams to the specified file.
573      */
save(File file)574     public void save(File file) {
575         ProvisionLogger.logd("Saving ProvisioningParams to " + file);
576         AtomicFile atomicFile = null;
577         FileOutputStream stream = null;
578         try {
579             atomicFile = new AtomicFile(file);
580             stream = atomicFile.startWrite();
581             XmlSerializer serializer = new FastXmlSerializer();
582             serializer.setOutput(stream, StandardCharsets.UTF_8.name());
583             serializer.startDocument(null, true);
584             serializer.startTag(null, TAG_PROVISIONING_PARAMS);
585             toPersistableBundle().saveToXml(serializer);
586             serializer.endTag(null, TAG_PROVISIONING_PARAMS);
587             serializer.endDocument();
588             atomicFile.finishWrite(stream);
589         } catch (IOException | XmlPullParserException e) {
590             ProvisionLogger.loge("Caught exception while trying to save Provisioning Params to "
591                     + " file " + file, e);
592             file.delete();
593             if (atomicFile != null) {
594                 atomicFile.failWrite(stream);
595             }
596         }
597     }
598 
cleanUp()599     public void cleanUp() {
600         if (disclaimersParam != null) {
601             disclaimersParam.cleanUp();
602         }
603     }
604 
605     /**
606      * Loads the ProvisioningParams From the specified file.
607      */
load(File file)608     public static ProvisioningParams load(File file) {
609         if (!file.exists()) {
610             return null;
611         }
612         ProvisionLogger.logd("Loading ProvisioningParams from " + file);
613         try (FileInputStream stream = new FileInputStream(file)) {
614             XmlPullParser parser = Xml.newPullParser();
615             parser.setInput(stream, null);
616             return load(parser);
617         } catch (IOException | XmlPullParserException e) {
618             ProvisionLogger.loge("Caught exception while trying to load the provisioning params"
619                     + " from file " + file, e);
620             return null;
621         }
622     }
623 
load(XmlPullParser parser)624     private static ProvisioningParams load(XmlPullParser parser) throws XmlPullParserException,
625             IOException {
626         int type;
627         int outerDepth = parser.getDepth();
628         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
629                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
630              if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
631                  continue;
632              }
633              String tag = parser.getName();
634              switch (tag) {
635                  case TAG_PROVISIONING_PARAMS:
636                      return createBuilderFromPersistableBundle(
637                              PersistableBundle.restoreFromXml(parser)).build();
638              }
639         }
640         return new Builder(/* skipValidation= */ false).build();
641     }
642 
643     public final static class Builder {
644         private final boolean mSkipValidation;
645         private long mProvisioningId;
646         private String mTimeZone;
647         private long mLocalTime = DEFAULT_LOCAL_TIME;
648         private Locale mLocale;
649         private WifiInfo mWifiInfo;
650         private String mDeviceAdminPackageName;
651         private ComponentName mDeviceAdminComponentName;
652         private String mOrganizationName;
653         private String mSupportUrl;
654         private Account mAccountToMigrate;
655         private String mProvisioningAction;
656         private PackageDownloadInfo mDeviceAdminDownloadInfo;
657         private DisclaimersParam mDisclaimersParam;
658         private PersistableBundle mAdminExtrasBundle;
659         private boolean mStartedByTrustedSource = DEFAULT_STARTED_BY_TRUSTED_SOURCE;
660         private boolean mIsNfc = DEFAULT_IS_NFC;
661         private boolean mIsQrProvisioning = DEFAULT_IS_QR_PROVISIONING;
662         private boolean mLeaveAllSystemAppsEnabled = DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED;
663         private boolean mSkipEncryption = DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION;
664         private boolean mSkipEducationScreens = DEFAULT_EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS;
665         private boolean mKeepAccountMigrated = DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED;
666         private boolean mUseMobileData = DEFAULT_EXTRA_PROVISIONING_USE_MOBILE_DATA;
667         private boolean mIsOrganizationOwnedProvisioning =
668                 DEFAULT_EXTRA_PROVISIONING_IS_ORGANIZATION_OWNED;
669         private ArrayList<Integer> mAllowedProvisioningModes =
670                 DEFAULT_EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES;
671         private int mInitiatorRequestedProvisioningModes =
672                 DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES;
673         private @FlowType int mFlowType = FLOW_TYPE_UNSPECIFIED;
674         private boolean mAllowProvisioningAfterUserSetupComplete = false;
675         private @ProvisioningTrigger int mProvisioningTrigger = PROVISIONING_TRIGGER_UNSPECIFIED;
676         private boolean mSkipOwnershipDisclaimer =
677                 DEFAULT_EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER;
678         private boolean mReturnBeforePolicyCompliance =
679                 DEFAULT_EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE;
680         private boolean mDeviceOwnerPermissionGrantOptOut =
681                 DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT;
682         private boolean mAllowOffline = DEFAULT_EXTRA_ALLOW_OFFLINE;
683         public PackageDownloadInfo mRoleHolderDownloadInfo;
684         private boolean mProvisioningShouldLaunchResultIntent =
685                 DEFAULT_EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT;
686 
Builder()687         public Builder() {
688             this(/* skipValidation= */ false);
689         }
690 
Builder(boolean skipValidation)691         public Builder(boolean skipValidation) {
692             mSkipValidation = skipValidation;
693         }
694 
setProvisioningId(long provisioningId)695         public Builder setProvisioningId(long provisioningId) {
696             mProvisioningId = provisioningId;
697             return this;
698         }
699 
setTimeZone(String timeZone)700         public Builder setTimeZone(String timeZone) {
701             mTimeZone = timeZone;
702             return this;
703         }
704 
setLocalTime(long localTime)705         public Builder setLocalTime(long localTime) {
706             mLocalTime = localTime;
707             return this;
708         }
709 
setLocale(Locale locale)710         public Builder setLocale(Locale locale) {
711             mLocale = locale;
712             return this;
713         }
714 
setWifiInfo(WifiInfo wifiInfo)715         public Builder setWifiInfo(WifiInfo wifiInfo) {
716             mWifiInfo = wifiInfo;
717             return this;
718         }
719 
720         @Deprecated
setDeviceAdminPackageName(String deviceAdminPackageName)721         public Builder setDeviceAdminPackageName(String deviceAdminPackageName) {
722             mDeviceAdminPackageName = deviceAdminPackageName;
723             return this;
724         }
725 
setDeviceAdminComponentName(ComponentName deviceAdminComponentName)726         public Builder setDeviceAdminComponentName(ComponentName deviceAdminComponentName) {
727             mDeviceAdminComponentName = deviceAdminComponentName;
728             return this;
729         }
730 
setOrganizationName(String organizationName)731         public Builder setOrganizationName(String organizationName) {
732             mOrganizationName = organizationName;
733             return this;
734         }
735 
setSupportUrl(String supportUrl)736         public Builder setSupportUrl(String supportUrl) {
737             mSupportUrl = supportUrl;
738             return this;
739         }
740 
setAccountToMigrate(Account accountToMigrate)741         public Builder setAccountToMigrate(Account accountToMigrate) {
742             mAccountToMigrate = accountToMigrate;
743             return this;
744         }
745 
setProvisioningAction(String provisioningAction)746         public Builder setProvisioningAction(String provisioningAction) {
747             mProvisioningAction = provisioningAction;
748             return this;
749         }
750 
setDeviceAdminDownloadInfo(PackageDownloadInfo deviceAdminDownloadInfo)751         public Builder setDeviceAdminDownloadInfo(PackageDownloadInfo deviceAdminDownloadInfo) {
752             mDeviceAdminDownloadInfo = deviceAdminDownloadInfo;
753             return this;
754         }
755 
setDisclaimersParam(DisclaimersParam disclaimersParam)756         public Builder setDisclaimersParam(DisclaimersParam disclaimersParam) {
757             mDisclaimersParam = disclaimersParam;
758             return this;
759         }
760 
setAdminExtrasBundle(PersistableBundle adminExtrasBundle)761         public Builder setAdminExtrasBundle(PersistableBundle adminExtrasBundle) {
762             mAdminExtrasBundle = adminExtrasBundle;
763             return this;
764         }
765 
setStartedByTrustedSource(boolean startedByTrustedSource)766         public Builder setStartedByTrustedSource(boolean startedByTrustedSource) {
767             mStartedByTrustedSource = startedByTrustedSource;
768             return this;
769         }
770 
setIsNfc(boolean isNfc)771         public Builder setIsNfc(boolean isNfc) {
772             mIsNfc = isNfc;
773             return this;
774         }
775 
setIsQrProvisioning(boolean qrProvisioning)776         public Builder setIsQrProvisioning(boolean qrProvisioning) {
777             mIsQrProvisioning = qrProvisioning;
778             return this;
779         }
780 
setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled)781         public Builder setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled) {
782             mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
783             return this;
784         }
785 
setSkipEncryption(boolean skipEncryption)786         public Builder setSkipEncryption(boolean skipEncryption) {
787             mSkipEncryption = skipEncryption;
788             return this;
789         }
790 
setSkipEducationScreens(boolean skipEducationScreens)791         public Builder setSkipEducationScreens(boolean skipEducationScreens) {
792             mSkipEducationScreens = skipEducationScreens;
793             return this;
794         }
795 
setKeepAccountMigrated(boolean keepAccountMigrated)796         public Builder setKeepAccountMigrated(boolean keepAccountMigrated) {
797             mKeepAccountMigrated = keepAccountMigrated;
798             return this;
799         }
800 
setUseMobileData(boolean useMobileData)801         public Builder setUseMobileData(boolean useMobileData) {
802             mUseMobileData = useMobileData;
803             return this;
804         }
805 
setIsOrganizationOwnedProvisioning(boolean isOrganizationOwnedProvisioning)806         public Builder setIsOrganizationOwnedProvisioning(boolean isOrganizationOwnedProvisioning) {
807             mIsOrganizationOwnedProvisioning = isOrganizationOwnedProvisioning;
808             return this;
809         }
810 
setFlowType(@lowType int flowType)811         public Builder setFlowType(@FlowType int flowType) {
812             mFlowType = flowType;
813             return this;
814         }
815 
setAllowProvisioningAfterUserSetupComplete( boolean allowProvisioningAfterUserSetupComplete)816         public Builder setAllowProvisioningAfterUserSetupComplete(
817                 boolean allowProvisioningAfterUserSetupComplete) {
818             mAllowProvisioningAfterUserSetupComplete = allowProvisioningAfterUserSetupComplete;
819             return this;
820         }
821 
setProvisioningTrigger(@rovisioningTrigger int provisioningTrigger)822         public Builder setProvisioningTrigger(@ProvisioningTrigger int provisioningTrigger) {
823             mProvisioningTrigger = provisioningTrigger;
824             return this;
825         }
826 
setAllowedProvisioningModes(ArrayList<Integer> provisioningModes)827         public Builder setAllowedProvisioningModes(ArrayList<Integer> provisioningModes) {
828             mAllowedProvisioningModes = new ArrayList<>(provisioningModes);
829             return this;
830         }
831 
setInitiatorRequestedProvisioningModes( int initiatorRequestedProvisioningModes)832         public Builder setInitiatorRequestedProvisioningModes(
833                 int initiatorRequestedProvisioningModes) {
834             mInitiatorRequestedProvisioningModes = initiatorRequestedProvisioningModes;
835             return this;
836         }
837 
838         /**
839          * See {@link ProvisioningParams#skipOwnershipDisclaimer}.
840          */
setSkipOwnershipDisclaimer(boolean skipOwnershipDisclaimer)841         public Builder setSkipOwnershipDisclaimer(boolean skipOwnershipDisclaimer) {
842             mSkipOwnershipDisclaimer = skipOwnershipDisclaimer;
843             return this;
844         }
845 
846         /**
847          * Setter for {@link #returnBeforePolicyCompliance}.
848          */
setReturnBeforePolicyCompliance(boolean returnBeforePolicyCompliance)849         public Builder setReturnBeforePolicyCompliance(boolean returnBeforePolicyCompliance) {
850             mReturnBeforePolicyCompliance = returnBeforePolicyCompliance;
851             return this;
852         }
853 
854         /**
855          * Setter for whether the admin has opted out of controlling permission grants.
856          */
setDeviceOwnerPermissionGrantOptOut(boolean optout)857         public Builder setDeviceOwnerPermissionGrantOptOut(boolean optout) {
858             mDeviceOwnerPermissionGrantOptOut = optout;
859             return this;
860         }
861 
862         /**
863          * Setter for whether offline provisioning is allowed.
864          *
865          * @see DevicePolicyManager#EXTRA_PROVISIONING_ALLOW_OFFLINE
866          */
setAllowOffline(boolean allowOffline)867         public Builder setAllowOffline(boolean allowOffline) {
868             mAllowOffline = allowOffline;
869             return this;
870         }
871 
872         /**
873          * Setter for the role holder download info.
874          */
setRoleHolderDownloadInfo(PackageDownloadInfo roleHolderDownloadInfo)875         public Builder setRoleHolderDownloadInfo(PackageDownloadInfo roleHolderDownloadInfo) {
876             mRoleHolderDownloadInfo = roleHolderDownloadInfo;
877             return this;
878         }
879 
880         /**
881          * Setter for whether provisioning should launch the result intent returned by the
882          * device manager role holder.
883          *
884          * @see DevicePolicyManager#EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT
885          */
setProvisioningShouldLaunchResultIntent( boolean provisioningShouldLaunchResultIntent)886         public Builder setProvisioningShouldLaunchResultIntent(
887                 boolean provisioningShouldLaunchResultIntent) {
888             mProvisioningShouldLaunchResultIntent = provisioningShouldLaunchResultIntent;
889             return this;
890         }
891 
892         /**
893          * Builds the {@link ProvisioningParams} object. Note that {@link
894          * #setProvisioningAction(String)} and {@link #setDeviceAdminComponentName(ComponentName)}
895          * methods must be called with a non-null parameter before this is called.
896          */
build()897         public ProvisioningParams build() {
898             return new ProvisioningParams(this);
899         }
900 
builder()901         public static Builder builder() {
902             return new Builder();
903         }
904 
905         /**
906          * Creates a {@link Builder} with the option to skip validation.
907          */
builder(boolean skipValidation)908         public static Builder builder(boolean skipValidation) {
909             return new Builder(skipValidation);
910         }
911     }
912 }
913