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 com.android.internal.util.Preconditions.checkArgument;
20 import static com.android.internal.util.Preconditions.checkNotNull;
21 
22 
23 import android.accounts.Account;
24 import android.content.Context;
25 import android.content.ComponentName;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.os.PersistableBundle;
29 import android.support.annotation.Nullable;
30 import android.text.TextUtils;
31 
32 import java.util.Arrays;
33 import java.util.Locale;
34 import java.util.Objects;
35 import java.util.Set;
36 
37 import com.android.internal.annotations.Immutable;
38 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
39 import com.android.managedprovisioning.common.Utils;
40 
41 /**
42  * Provisioning parameters for Device Owner and Profile Owner provisioning.
43  */
44 public final class ProvisioningParams implements Parcelable {
45     public static final long DEFAULT_LOCAL_TIME = -1;
46     public static final Integer DEFAULT_MAIN_COLOR = null;
47     public static final boolean DEFAULT_STARTED_BY_TRUSTED_SOURCE = false;
48     public static final boolean DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED = false;
49     public static final boolean DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION = false;
50     public static final boolean DEFAULT_SKIP_USER_SETUP = true;
51     // Intent extra used internally for passing data between activities and service.
52     public static final String EXTRA_PROVISIONING_PARAMS = "provisioningParams";
53 
54     public static final Parcelable.Creator<ProvisioningParams> CREATOR
55             = new Parcelable.Creator<ProvisioningParams>() {
56         @Override
57         public ProvisioningParams createFromParcel(Parcel in) {
58             return new ProvisioningParams(in);
59         }
60 
61         @Override
62         public ProvisioningParams[] newArray(int size) {
63             return new ProvisioningParams[size];
64         }
65     };
66 
67     @Nullable
68     public final String timeZone;
69 
70     public final long localTime;
71 
72     @Nullable
73     public final Locale locale;
74 
75     /** WiFi configuration. */
76     @Nullable
77     public final WifiInfo wifiInfo;
78 
79     /**
80      * Package name of the device admin package.
81      *
82      * <p>At least one one of deviceAdminPackageName and deviceAdminComponentName should be
83      * non-null.
84      */
85     @Deprecated
86     public final String deviceAdminPackageName;
87 
88     /**
89      * {@link ComponentName} of the device admin package.
90      *
91      * <p>At least one one of deviceAdminPackageName and deviceAdminComponentName should be
92      * non-null.
93      */
94     public final ComponentName deviceAdminComponentName;
95 
96     /** {@link Account} that should be migrated to the managed profile. */
97     @Nullable
98     public final Account accountToMigrate;
99 
100     /** Provisioning action comes along with the provisioning data. */
101     public final String provisioningAction;
102 
103     /**
104      * The main color theme used in managed profile only.
105      *
106      * <p>{@code null} means the default value.
107      */
108     @Nullable
109     public final Integer mainColor;
110 
111     /** The download information of device admin package. */
112     @Nullable
113     public final PackageDownloadInfo deviceAdminDownloadInfo;
114 
115     /**
116      * Custom key-value pairs from enterprise mobility management which are passed to device admin
117      * package after provisioning.
118      *
119      * <p>Note that {@link ProvisioningParams} is not immutable because this field is mutable.
120      */
121     @Nullable
122     public final PersistableBundle adminExtrasBundle;
123 
124     /**
125      * True iff provisioning flow was started by a trusted app. This includes Nfc bump and QR code.
126      */
127     public final boolean startedByTrustedSource;
128 
129     /** True if all system apps should be enabled after provisioning. */
130     public final boolean leaveAllSystemAppsEnabled;
131 
132     /** True if device encryption should be skipped. */
133     public final boolean skipEncryption;
134 
135     /** True if user setup can be skipped. */
136     public final boolean skipUserSetup;
137 
138     // TODO (stevenckng): This shouldn't belong here. Remove this logic from ProvisioningParams.
139     private ComponentName inferedDeviceAdminComponentName;
140 
141     private final Utils mUtils = new Utils();
142 
inferDeviceAdminPackageName()143     public String inferDeviceAdminPackageName() {
144         if (deviceAdminComponentName != null) {
145             return deviceAdminComponentName.getPackageName();
146         }
147         return deviceAdminPackageName;
148     }
149 
150     // This should not be called if the app has not been installed yet.
inferDeviceAdminComponentName(Context c)151     public ComponentName inferDeviceAdminComponentName(Context c)
152             throws IllegalProvisioningArgumentException {
153         if (inferedDeviceAdminComponentName == null) {
154             inferedDeviceAdminComponentName = mUtils.findDeviceAdmin(
155                     deviceAdminPackageName, deviceAdminComponentName, c);
156         }
157         return inferedDeviceAdminComponentName;
158     }
159 
ProvisioningParams(Builder builder)160     private ProvisioningParams(Builder builder) {
161         timeZone = builder.mTimeZone;
162         localTime = builder.mLocalTime;
163         locale = builder.mLocale;
164 
165         wifiInfo = builder.mWifiInfo;
166 
167         deviceAdminComponentName = builder.mDeviceAdminComponentName;
168         deviceAdminPackageName = builder.mDeviceAdminPackageName;
169 
170         deviceAdminDownloadInfo = builder.mDeviceAdminDownloadInfo;
171 
172         adminExtrasBundle = builder.mAdminExtrasBundle;
173 
174         startedByTrustedSource = builder.mStartedByTrustedSource;
175         leaveAllSystemAppsEnabled = builder.mLeaveAllSystemAppsEnabled;
176         skipEncryption = builder.mSkipEncryption;
177         accountToMigrate = builder.mAccountToMigrate;
178         provisioningAction = checkNotNull(builder.mProvisioningAction);
179         mainColor = builder.mMainColor;
180         skipUserSetup = builder.mSkipUserSetup;
181 
182         validateFields();
183     }
184 
ProvisioningParams(Parcel in)185     private ProvisioningParams(Parcel in) {
186         timeZone = in.readString();
187         localTime = in.readLong();
188         locale = (Locale) in.readSerializable();
189 
190         wifiInfo = (WifiInfo) in.readParcelable(WifiInfo.class.getClassLoader());
191 
192         deviceAdminPackageName = in.readString();
193         deviceAdminComponentName = (ComponentName)
194                 in.readParcelable(null /* use default classloader */);
195 
196         deviceAdminDownloadInfo =
197                 (PackageDownloadInfo) in.readParcelable(PackageDownloadInfo.class.getClassLoader());
198 
199         adminExtrasBundle = in.readParcelable(null /* use default classloader */);
200 
201         startedByTrustedSource = in.readInt() == 1;
202         leaveAllSystemAppsEnabled = in.readInt() == 1;
203         skipEncryption = in.readInt() == 1;
204         accountToMigrate = (Account) in.readParcelable(null /* use default classloader */);
205         provisioningAction = checkNotNull(in.readString());
206         if (in.readInt() != 0) {
207             mainColor = in.readInt();
208         } else {
209             mainColor = null;
210         }
211         skipUserSetup = in.readInt() == 1;
212 
213         validateFields();
214     }
215 
validateFields()216     private void validateFields() {
217         checkArgument(deviceAdminPackageName != null || deviceAdminComponentName != null);
218     }
219 
220     @Override
describeContents()221     public int describeContents() {
222         return 0;
223     }
224 
225     @Override
writeToParcel(Parcel out, int flags)226     public void writeToParcel(Parcel out, int flags) {
227         out.writeString(timeZone);
228         out.writeLong(localTime);
229         out.writeSerializable(locale);
230 
231         out.writeParcelable(wifiInfo, 0 /* default */ );
232 
233         out.writeString(deviceAdminPackageName);
234         out.writeParcelable(deviceAdminComponentName, 0 /* default */);
235 
236         out.writeParcelable(deviceAdminDownloadInfo, 0 /* default */);
237 
238         out.writeParcelable(adminExtrasBundle, 0 /* default */);
239 
240         out.writeInt(startedByTrustedSource ? 1 : 0);
241         out.writeInt(leaveAllSystemAppsEnabled ? 1 : 0);
242         out.writeInt(skipEncryption ? 1 : 0);
243         out.writeParcelable(accountToMigrate, 0 /* default */);
244         out.writeString(provisioningAction);
245         if (mainColor != null) {
246             out.writeInt(1);
247             out.writeInt(mainColor);
248         } else {
249             out.writeInt(0);
250         }
251         out.writeInt(skipUserSetup ? 1 : 0);
252     }
253 
254     @Override
equals(Object o)255     public boolean equals(Object o) {
256         if (this == o) {
257             return true;
258         }
259         if (o == null || getClass() != o.getClass()) {
260             return false;
261         }
262         ProvisioningParams that = (ProvisioningParams) o;
263         return localTime == that.localTime
264                 && startedByTrustedSource == that.startedByTrustedSource
265                 && leaveAllSystemAppsEnabled == that.leaveAllSystemAppsEnabled
266                 && skipEncryption == that.skipEncryption
267                 && skipUserSetup == that.skipUserSetup
268                 && Objects.equals(timeZone, that.timeZone)
269                 && Objects.equals(locale, that.locale)
270                 && Objects.equals(wifiInfo, that.wifiInfo)
271                 && Objects.equals(deviceAdminPackageName, that.deviceAdminPackageName)
272                 && Objects.equals(deviceAdminComponentName, that.deviceAdminComponentName)
273                 && Objects.equals(accountToMigrate, that.accountToMigrate)
274                 && Objects.equals(provisioningAction, that.provisioningAction)
275                 && Objects.equals(mainColor, that.mainColor)
276                 && Objects.equals(deviceAdminDownloadInfo, that.deviceAdminDownloadInfo)
277                 && isPersistableBundleEquals(adminExtrasBundle, that.adminExtrasBundle)
278                 && Objects.equals(
279                         inferedDeviceAdminComponentName, that.inferedDeviceAdminComponentName);
280     }
281 
282     /**
283      * Compares two {@link PersistableBundle} objects are equals.
284      */
isPersistableBundleEquals( PersistableBundle obj1, PersistableBundle obj2)285     private static boolean isPersistableBundleEquals(
286             PersistableBundle obj1, PersistableBundle obj2) {
287         if (obj1 == obj2) {
288             return true;
289         }
290         if (obj1 == null || obj2 == null || obj1.size() != obj2.size()) {
291             return false;
292         }
293         Set<String> keys = obj1.keySet();
294         for (String key : keys) {
295             Object val1 = obj1.get(key);
296             Object val2 = obj2.get(key);
297             if (!isPersistableBundleSupportedValueEquals(val1, val2)) {
298                 return false;
299             }
300         }
301         return true;
302     }
303 
304     /**
305      * Compares two values which type is supported by {@link PersistableBundle}.
306      *
307      * <p>If the type isn't supported. The equality is done by {@link Object#equals(Object)}.
308      */
isPersistableBundleSupportedValueEquals(Object val1, Object val2)309     private static boolean isPersistableBundleSupportedValueEquals(Object val1, Object val2) {
310         if (val1 == val2) {
311             return true;
312         } else if (val1 == null || val2 == null || !val1.getClass().equals(val2.getClass())) {
313             return false;
314         } else if (val1 instanceof PersistableBundle && val2 instanceof PersistableBundle) {
315             return isPersistableBundleEquals((PersistableBundle) val1, (PersistableBundle) val2);
316         } else if (val1 instanceof int[]) {
317             return Arrays.equals((int[]) val1, (int[]) val2);
318         } else if (val1 instanceof long[]) {
319             return Arrays.equals((long[]) val1, (long[]) val2);
320         } else if (val1 instanceof double[]) {
321             return Arrays.equals((double[]) val1, (double[]) val2);
322         } else if (val1 instanceof boolean[]) {
323             return Arrays.equals((boolean[]) val1, (boolean[]) val2);
324         } else if (val1 instanceof String[]) {
325             return Arrays.equals((String[]) val1, (String[]) val2);
326         } else {
327             return Objects.equals(val1, val2);
328         }
329     }
330 
331     public final static class Builder {
332         private String mTimeZone;
333         private long mLocalTime = DEFAULT_LOCAL_TIME;
334         private Locale mLocale;
335         private WifiInfo mWifiInfo;
336         private String mDeviceAdminPackageName;
337         private ComponentName mDeviceAdminComponentName;
338         private Account mAccountToMigrate;
339         private String mProvisioningAction;
340         private Integer mMainColor = DEFAULT_MAIN_COLOR;
341         private PackageDownloadInfo mDeviceAdminDownloadInfo;
342         private PersistableBundle mAdminExtrasBundle;
343         private boolean mStartedByTrustedSource = DEFAULT_STARTED_BY_TRUSTED_SOURCE;
344         private boolean mLeaveAllSystemAppsEnabled = DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED;
345         private boolean mSkipEncryption = DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION;
346         private boolean mSkipUserSetup = DEFAULT_SKIP_USER_SETUP;
347 
setTimeZone(String timeZone)348         public Builder setTimeZone(String timeZone) {
349             mTimeZone = timeZone;
350             return this;
351         }
352 
setLocalTime(long localTime)353         public Builder setLocalTime(long localTime) {
354             mLocalTime = localTime;
355             return this;
356         }
357 
setLocale(Locale locale)358         public Builder setLocale(Locale locale) {
359             mLocale = locale;
360             return this;
361         }
362 
setWifiInfo(WifiInfo wifiInfo)363         public Builder setWifiInfo(WifiInfo wifiInfo) {
364             mWifiInfo = wifiInfo;
365             return this;
366         }
367 
368         @Deprecated
setDeviceAdminPackageName(String deviceAdminPackageName)369         public Builder setDeviceAdminPackageName(String deviceAdminPackageName) {
370             mDeviceAdminPackageName = deviceAdminPackageName;
371             return this;
372         }
373 
setDeviceAdminComponentName(ComponentName deviceAdminComponentName)374         public Builder setDeviceAdminComponentName(ComponentName deviceAdminComponentName) {
375             mDeviceAdminComponentName = deviceAdminComponentName;
376             return this;
377         }
378 
setAccountToMigrate(Account accountToMigrate)379         public Builder setAccountToMigrate(Account accountToMigrate) {
380             mAccountToMigrate = accountToMigrate;
381             return this;
382         }
383 
setProvisioningAction(String provisioningAction)384         public Builder setProvisioningAction(String provisioningAction) {
385             mProvisioningAction = provisioningAction;
386             return this;
387         }
388 
setMainColor(Integer mainColor)389         public Builder setMainColor(Integer mainColor) {
390             mMainColor = mainColor;
391             return this;
392         }
393 
setDeviceAdminDownloadInfo(PackageDownloadInfo deviceAdminDownloadInfo)394         public Builder setDeviceAdminDownloadInfo(PackageDownloadInfo deviceAdminDownloadInfo) {
395             mDeviceAdminDownloadInfo = deviceAdminDownloadInfo;
396             return this;
397         }
398 
setAdminExtrasBundle(PersistableBundle adminExtrasBundle)399         public Builder setAdminExtrasBundle(PersistableBundle adminExtrasBundle) {
400             mAdminExtrasBundle = adminExtrasBundle;
401             return this;
402         }
403 
setStartedByTrustedSource(boolean startedByTrustedSource)404         public Builder setStartedByTrustedSource(boolean startedByTrustedSource) {
405             mStartedByTrustedSource = startedByTrustedSource;
406             return this;
407         }
408 
setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled)409         public Builder setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled) {
410             mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
411             return this;
412         }
413 
setSkipEncryption(boolean skipEncryption)414         public Builder setSkipEncryption(boolean skipEncryption) {
415             mSkipEncryption = skipEncryption;
416             return this;
417         }
418 
setSkipUserSetup(boolean skipUserSetup)419         public Builder setSkipUserSetup(boolean skipUserSetup) {
420             mSkipUserSetup = skipUserSetup;
421             return this;
422         }
423 
build()424         public ProvisioningParams build() {
425             return new ProvisioningParams(this);
426         }
427 
builder()428         public static Builder builder() {
429             return new Builder();
430         }
431     }
432 }
433