1 /*
2  * Copyright (C) 2019 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.server.pm;
18 
19 import android.annotation.ColorRes;
20 import android.annotation.DrawableRes;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.StringRes;
24 import android.content.pm.UserInfo;
25 import android.content.pm.UserInfo.UserInfoFlag;
26 import android.content.pm.UserProperties;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.UserManager;
30 
31 import com.android.internal.util.Preconditions;
32 import com.android.server.BundleUtils;
33 
34 import java.io.PrintWriter;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 
39 /**
40  * Contains the details about a multiuser "user type", such as a
41  * {@link UserManager#USER_TYPE_PROFILE_MANAGED}.
42  *
43  * Tests are located in UserManagerServiceUserTypeTest.java.
44  * @hide
45  */
46 public final class UserTypeDetails {
47 
48     /** Indicates that there is no limit to the number of users allowed. */
49     public static final int UNLIMITED_NUMBER_OF_USERS = -1;
50 
51     /** Name of the user type, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. */
52     private final @NonNull String mName;
53 
54     /** Whether users of this type can be created. */
55     private final boolean mEnabled;
56 
57     /**
58      * Resource IDs ({@link StringRes}) of the user's labels. This might be used to label a
59      * user/profile in tabbed views, etc.
60      * The values are resource IDs referring to the strings not the strings themselves.
61      *
62      * <p>This is an array because, in general, there may be multiple users of the same user type.
63      * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
64      */
65     private final @Nullable int[] mLabels;
66 
67     /**
68      * Maximum number of this user type allowed on the device.
69      * Use {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
70      */
71     private final int mMaxAllowed;
72 
73     /**
74      * Maximum number of this user type allowed per parent (for user types, like profiles, that
75      * have parents).
76      * Use {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
77      */
78     // TODO(b/142482943): Should this also apply to restricted profiles?
79     private final int mMaxAllowedPerParent;
80 
81     // TODO(b/143784345): Update doc when we clean up UserInfo.
82     /** The {@link UserInfo.UserInfoFlag} representing the base type of this user. */
83     private final @UserInfoFlag int mBaseType;
84 
85     // TODO(b/143784345): Update doc/name when we clean up UserInfo.
86     /** The {@link UserInfoFlag}s to apply by default to newly created users of this type. */
87     private final @UserInfoFlag int mDefaultUserInfoPropertyFlags;
88 
89     /**
90      * List of User Restrictions to apply by default to newly created users of this type.
91      * <p>Does not apply to SYSTEM users (since they are not formally created); for them use
92      * {@link com.android.internal.R.array#config_defaultFirstUserRestrictions} instead.
93      * The Bundle is of the form used by {@link UserRestrictionsUtils}.
94      */
95     private final @Nullable Bundle mDefaultRestrictions;
96 
97     /**
98      * List of {@link android.provider.Settings.System} to apply by default to newly created users
99      * of this type.
100      */
101     private final @Nullable Bundle mDefaultSystemSettings;
102 
103     /**
104      * List of {@link android.provider.Settings.Secure} to apply by default to newly created users
105      * of this type.
106      */
107     private final @Nullable Bundle mDefaultSecureSettings;
108 
109     /**
110      * List of {@link DefaultCrossProfileIntentFilter} to allow by default for newly created
111      * profiles.
112      */
113     private final @Nullable List<DefaultCrossProfileIntentFilter> mDefaultCrossProfileIntentFilters;
114 
115 
116     // Fields for profiles only, controlling the nature of their badges.
117     // All badge information should be set if {@link #hasBadge()} is true.
118 
119     /** Resource ID of the badge put on icons. */
120     private @DrawableRes final int mIconBadge;
121     /** Resource ID of the badge. Should be set if mIconBadge is set. */
122     private @DrawableRes final int mBadgePlain;
123     /** Resource ID of the badge without a background. Should be set if mIconBadge is set. */
124     private @DrawableRes final int mBadgeNoBackground;
125 
126     /** Resource ID of the status bar icon. */
127     private @DrawableRes final int mStatusBarIcon;
128 
129     /**
130      * Resource ID ({@link StringRes}) of the labels to describe badged apps; should be the
131      * same format as com.android.internal.R.color.profile_badge_1. These are used for accessibility
132      * services.
133      *
134      * <p>This is an array because, in general, there may be multiple users of the same user type.
135      * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
136      *
137      * <p>Must be set if mIconBadge is set.
138      */
139     private final @Nullable int[] mBadgeLabels;
140 
141     /**
142      * Resource ID ({@link ColorRes}) of the colors badge put on icons.
143      * (The value is a resource ID referring to the color; it is not the color value itself).
144      *
145      * <p>This is an array because, in general, there may be multiple users of the same user type.
146      * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
147      *
148      * <p>Must be set if mIconBadge is set.
149      */
150     private final @Nullable int[] mBadgeColors;
151 
152     /**
153      * Resource ID ({@link ColorRes}) of the colors badge put on icons when in dark theme.
154      * (The value is a resource ID referring to the color; it is not the color value itself).
155      *
156      * <p>This is an array because, in general, there may be multiple users of the same user type.
157      * In this case, the user is indexed according to its {@link UserInfo#profileBadge}.
158      *
159      * <p>Must be set if mIconBadge is set.
160      */
161     private final @Nullable int[] mDarkThemeBadgeColors;
162 
163     /**
164      * Resource ID ({@link StringRes}) of the accessibility string that describes the user type.
165      * This is used by accessibility services like Talkback.
166      */
167     private final @StringRes int mAccessibilityString;
168 
169     /**
170      * The default {@link UserProperties} for the user type.
171      * <p> The uninitialized value of each property is implied by {@link UserProperties.Builder}.
172      */
173     private final @NonNull UserProperties mDefaultUserProperties;
174 
UserTypeDetails(@onNull String name, boolean enabled, int maxAllowed, @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, @Nullable int[] labels, int maxAllowedPerParent, int iconBadge, int badgePlain, int badgeNoBackground, int statusBarIcon, @Nullable int[] badgeLabels, @Nullable int[] badgeColors, @Nullable int[] darkThemeBadgeColors, @Nullable Bundle defaultRestrictions, @Nullable Bundle defaultSystemSettings, @Nullable Bundle defaultSecureSettings, @Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters, @StringRes int accessibilityString, @NonNull UserProperties defaultUserProperties)175     private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
176             @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags,
177             @Nullable int[] labels, int maxAllowedPerParent,
178             int iconBadge, int badgePlain, int badgeNoBackground,
179             int statusBarIcon,
180             @Nullable int[] badgeLabels, @Nullable int[] badgeColors,
181             @Nullable int[] darkThemeBadgeColors,
182             @Nullable Bundle defaultRestrictions,
183             @Nullable Bundle defaultSystemSettings,
184             @Nullable Bundle defaultSecureSettings,
185             @Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
186             @StringRes int accessibilityString,
187             @NonNull UserProperties defaultUserProperties) {
188         this.mName = name;
189         this.mEnabled = enabled;
190         this.mMaxAllowed = maxAllowed;
191         this.mMaxAllowedPerParent = maxAllowedPerParent;
192         this.mBaseType = baseType;
193         this.mDefaultUserInfoPropertyFlags = defaultUserInfoPropertyFlags;
194         this.mDefaultRestrictions = defaultRestrictions;
195         this.mDefaultSystemSettings = defaultSystemSettings;
196         this.mDefaultSecureSettings = defaultSecureSettings;
197         this.mDefaultCrossProfileIntentFilters = defaultCrossProfileIntentFilters;
198         this.mIconBadge = iconBadge;
199         this.mBadgePlain = badgePlain;
200         this.mBadgeNoBackground = badgeNoBackground;
201         this.mStatusBarIcon = statusBarIcon;
202         this.mLabels = labels;
203         this.mBadgeLabels = badgeLabels;
204         this.mBadgeColors = badgeColors;
205         this.mDarkThemeBadgeColors = darkThemeBadgeColors;
206         this.mAccessibilityString = accessibilityString;
207         this.mDefaultUserProperties = defaultUserProperties;
208     }
209 
210     /**
211      * Returns the name of the user type, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}.
212      */
getName()213     public String getName() {
214         return mName;
215     }
216 
217     /**
218      * Returns whether this user type is enabled.
219      * If it is not enabled, all future attempts to create users of this type will be rejected.
220      */
isEnabled()221     public boolean isEnabled() {
222         return mEnabled;
223     }
224 
225     /**
226      * Returns the maximum number of this user type allowed on the device.
227      * <p>Returns {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
228      */
getMaxAllowed()229     public int getMaxAllowed() {
230         return mMaxAllowed;
231     }
232 
233     /**
234      * Returns the maximum number of this user type allowed per parent (for user types, like
235      * profiles, that have parents).
236      * Under certain circumstances (such as after a change-user-type) the max value can actually
237      * be exceeded: this is allowed in order to keep the device in a usable state.
238      * An error is logged in {@link UserManagerService#upgradeProfileToTypeLU}
239      * <p>Returns {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
240      */
getMaxAllowedPerParent()241     public int getMaxAllowedPerParent() {
242         return mMaxAllowedPerParent;
243     }
244 
245     // TODO(b/143784345): Update comment when UserInfo is reorganized.
246     /** The {@link UserInfoFlag}s to apply by default to newly created users of this type. */
getDefaultUserInfoFlags()247     public int getDefaultUserInfoFlags() {
248         return mDefaultUserInfoPropertyFlags | mBaseType;
249     }
250 
251     /**
252      * Returns the resource ID corresponding to the badgeIndexth label name where the badgeIndex is
253      * expected to be the {@link UserInfo#profileBadge} of the user. If badgeIndex exceeds the
254      * number of labels, returns the label for the highest index.
255      */
getLabel(int badgeIndex)256     public @StringRes int getLabel(int badgeIndex) {
257         if (mLabels == null || mLabels.length == 0 || badgeIndex < 0) {
258             return Resources.ID_NULL;
259         }
260         return mLabels[Math.min(badgeIndex, mLabels.length - 1)];
261     }
262 
263     /** Returns whether users of this user type should be badged. */
hasBadge()264     public boolean hasBadge() {
265         return mIconBadge != Resources.ID_NULL;
266     }
267 
268     /** Resource ID of the badge to put on icons. */
getIconBadge()269     public @DrawableRes int getIconBadge() {
270         return mIconBadge;
271     }
272 
273     /** Resource ID of the badge. Used for {@link UserManager#getUserBadgeResId(int)}. */
getBadgePlain()274     public @DrawableRes int getBadgePlain() {
275         return mBadgePlain;
276     }
277 
278     /** Resource ID of the badge without a background. */
getBadgeNoBackground()279     public @DrawableRes int getBadgeNoBackground() {
280         return mBadgeNoBackground;
281     }
282 
283     /** Resource ID of the status bar icon. */
getStatusBarIcon()284     public @DrawableRes int getStatusBarIcon() {
285         return mStatusBarIcon;
286     }
287 
288     /**
289      * Returns the Resource ID of the badgeIndexth badge label, where the badgeIndex is expected
290      * to be the {@link UserInfo#profileBadge} of the user.
291      * If badgeIndex exceeds the number of labels, returns the label for the highest index.
292      */
getBadgeLabel(int badgeIndex)293     public @StringRes int getBadgeLabel(int badgeIndex) {
294         if (mBadgeLabels == null || mBadgeLabels.length == 0 || badgeIndex < 0) {
295             return Resources.ID_NULL;
296         }
297         return mBadgeLabels[Math.min(badgeIndex, mBadgeLabels.length - 1)];
298     }
299 
300     /**
301      * Returns the Resource ID of the badgeIndexth badge color, where the badgeIndex is expected
302      * to be the {@link UserInfo#profileBadge} of the user.
303      * If badgeIndex exceeds the number of colors, returns the color for the highest index.
304      */
getBadgeColor(int badgeIndex)305     public @ColorRes int getBadgeColor(int badgeIndex) {
306         if (mBadgeColors == null || mBadgeColors.length == 0 || badgeIndex < 0) {
307             return Resources.ID_NULL;
308         }
309         return mBadgeColors[Math.min(badgeIndex, mBadgeColors.length - 1)];
310     }
311 
312     /**
313      * Returns the Resource ID of the badgeIndexth dark theme badge color, where the badgeIndex is
314      * expected to be the {@link UserInfo#profileBadge} of the user.
315      * If dark theme badge colors haven't been set, use the light theme badge color.
316      * If badgeIndex exceeds the number of colors, returns the color for the highest index.
317      */
getDarkThemeBadgeColor(int badgeIndex)318     public @ColorRes int getDarkThemeBadgeColor(int badgeIndex) {
319         if (mDarkThemeBadgeColors == null || mDarkThemeBadgeColors.length == 0 || badgeIndex < 0) {
320             return getBadgeColor(badgeIndex);
321         }
322         return mDarkThemeBadgeColors[Math.min(badgeIndex, mDarkThemeBadgeColors.length - 1)];
323     }
324 
325 
326     /**
327      * Returns the reference to the default {@link UserProperties} for this type of user.
328      * This is not a copy. Do NOT modify this object.
329      */
getDefaultUserPropertiesReference()330     public @NonNull UserProperties getDefaultUserPropertiesReference() {
331         return mDefaultUserProperties;
332     }
333 
getAccessibilityString()334     public @StringRes int getAccessibilityString() {
335         return mAccessibilityString;
336     }
337 
isProfile()338     public boolean isProfile() {
339         return (mBaseType & UserInfo.FLAG_PROFILE) != 0;
340     }
341 
isFull()342     public boolean isFull() {
343         return (mBaseType & UserInfo.FLAG_FULL) != 0;
344     }
345 
isSystem()346     public boolean isSystem() {
347         return (mBaseType & UserInfo.FLAG_SYSTEM) != 0;
348     }
349 
350     /** Returns a {@link Bundle} representing the default user restrictions. */
getDefaultRestrictions()351     @NonNull Bundle getDefaultRestrictions() {
352         return BundleUtils.clone(mDefaultRestrictions);
353     }
354 
355     /** Adds the default user restrictions to the given bundle of restrictions. */
addDefaultRestrictionsTo(@onNull Bundle currentRestrictions)356     public void addDefaultRestrictionsTo(@NonNull Bundle currentRestrictions) {
357         UserRestrictionsUtils.merge(currentRestrictions, mDefaultRestrictions);
358     }
359 
360     /** Returns a {@link Bundle} representing the default system settings. */
getDefaultSystemSettings()361     @NonNull Bundle getDefaultSystemSettings() {
362         return BundleUtils.clone(mDefaultSystemSettings);
363     }
364 
365     /** Returns a {@link Bundle} representing the default secure settings. */
getDefaultSecureSettings()366     @NonNull Bundle getDefaultSecureSettings() {
367         return BundleUtils.clone(mDefaultSecureSettings);
368     }
369 
370     /** Returns a list of default cross profile intent filters. */
getDefaultCrossProfileIntentFilters()371     @NonNull List<DefaultCrossProfileIntentFilter> getDefaultCrossProfileIntentFilters() {
372         return mDefaultCrossProfileIntentFilters != null
373                 ? new ArrayList<>(mDefaultCrossProfileIntentFilters)
374                 : Collections.emptyList();
375     }
376 
377     /** Dumps details of the UserTypeDetails. Do not parse this. */
dump(PrintWriter pw, String prefix)378     public void dump(PrintWriter pw, String prefix) {
379         pw.print(prefix); pw.print("mName: "); pw.println(mName);
380         pw.print(prefix); pw.print("mBaseType: "); pw.println(UserInfo.flagsToString(mBaseType));
381         pw.print(prefix); pw.print("mEnabled: "); pw.println(mEnabled);
382         pw.print(prefix); pw.print("mMaxAllowed: "); pw.println(mMaxAllowed);
383         pw.print(prefix); pw.print("mMaxAllowedPerParent: "); pw.println(mMaxAllowedPerParent);
384         pw.print(prefix); pw.print("mDefaultUserInfoFlags: ");
385         pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
386         mDefaultUserProperties.println(pw, prefix);
387 
388         final String restrictionsPrefix = prefix + "    ";
389         if (isSystem()) {
390             pw.print(prefix); pw.println("config_defaultFirstUserRestrictions: ");
391             try {
392                 final Bundle restrictions = new Bundle();
393                 final String[] defaultFirstUserRestrictions = Resources.getSystem().getStringArray(
394                         com.android.internal.R.array.config_defaultFirstUserRestrictions);
395                 for (String userRestriction : defaultFirstUserRestrictions) {
396                     if (UserRestrictionsUtils.isValidRestriction(userRestriction)) {
397                         restrictions.putBoolean(userRestriction, true);
398                     }
399                 }
400                 UserRestrictionsUtils.dumpRestrictions(pw, restrictionsPrefix, restrictions);
401             } catch (Resources.NotFoundException e) {
402                 pw.print(restrictionsPrefix); pw.println("none - resource not found");
403             }
404         } else {
405             pw.print(prefix); pw.println("mDefaultRestrictions: ");
406             UserRestrictionsUtils.dumpRestrictions(pw, restrictionsPrefix, mDefaultRestrictions);
407         }
408 
409         pw.print(prefix); pw.print("mIconBadge: "); pw.println(mIconBadge);
410         pw.print(prefix); pw.print("mBadgePlain: "); pw.println(mBadgePlain);
411         pw.print(prefix); pw.print("mBadgeNoBackground: "); pw.println(mBadgeNoBackground);
412         pw.print(prefix); pw.print("mStatusBarIcon: "); pw.println(mStatusBarIcon);
413         pw.print(prefix); pw.print("mBadgeLabels.length: ");
414         pw.println(mBadgeLabels != null ? mBadgeLabels.length : "0(null)");
415         pw.print(prefix); pw.print("mBadgeColors.length: ");
416         pw.println(mBadgeColors != null ? mBadgeColors.length : "0(null)");
417         pw.print(prefix); pw.print("mDarkThemeBadgeColors.length: ");
418         pw.println(mDarkThemeBadgeColors != null ? mDarkThemeBadgeColors.length : "0(null)");
419         pw.print(prefix); pw.print("mLabels.length: ");
420         pw.println(mLabels != null ? mLabels.length : "0(null)");
421     }
422 
423     /** Builder for a {@link UserTypeDetails}; see that class for documentation. */
424     public static final class Builder {
425         // UserTypeDetails properties and their default values.
426         private String mName; // This MUST be explicitly set.
427         private int mBaseType; // This MUST be explicitly set.
428         private int mMaxAllowed = UNLIMITED_NUMBER_OF_USERS;
429         private int mMaxAllowedPerParent = UNLIMITED_NUMBER_OF_USERS;
430         private int mDefaultUserInfoPropertyFlags = 0;
431         private @Nullable Bundle mDefaultRestrictions = null;
432         private @Nullable Bundle mDefaultSystemSettings = null;
433         private @Nullable Bundle mDefaultSecureSettings = null;
434         private @Nullable List<DefaultCrossProfileIntentFilter> mDefaultCrossProfileIntentFilters =
435                 null;
436         private int mEnabled = 1;
437         private @Nullable int[] mLabels = null;
438         private @Nullable int[] mBadgeLabels = null;
439         private @Nullable int[] mBadgeColors = null;
440         private @Nullable int[] mDarkThemeBadgeColors = null;
441         private @DrawableRes int mIconBadge = Resources.ID_NULL;
442         private @DrawableRes int mBadgePlain = Resources.ID_NULL;
443         private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
444         private @DrawableRes int mStatusBarIcon = Resources.ID_NULL;
445         private @StringRes int mAccessibilityString = Resources.ID_NULL;
446         // Default UserProperties cannot be null but for efficiency we don't initialize it now.
447         // If it isn't set explicitly, {@link UserProperties.Builder#build()} will be used.
448         private @Nullable UserProperties mDefaultUserProperties = null;
449 
setName(String name)450         public Builder setName(String name) {
451             mName = name;
452             return this;
453         }
454 
setEnabled(int enabled)455         public Builder setEnabled(int enabled) {
456             mEnabled = enabled;
457             return this;
458         }
459 
setMaxAllowed(int maxAllowed)460         public Builder setMaxAllowed(int maxAllowed) {
461             mMaxAllowed = maxAllowed;
462             return this;
463         }
464 
setMaxAllowedPerParent(int maxAllowedPerParent)465         public Builder setMaxAllowedPerParent(int maxAllowedPerParent) {
466             mMaxAllowedPerParent = maxAllowedPerParent;
467             return this;
468         }
469 
setBaseType(@serInfoFlag int baseType)470         public Builder setBaseType(@UserInfoFlag int baseType) {
471             mBaseType = baseType;
472             return this;
473         }
474 
setDefaultUserInfoPropertyFlags(@serInfoFlag int flags)475         public Builder setDefaultUserInfoPropertyFlags(@UserInfoFlag int flags) {
476             mDefaultUserInfoPropertyFlags = flags;
477             return this;
478         }
479 
setBadgeLabels(@tringRes int ... badgeLabels)480         public Builder setBadgeLabels(@StringRes int ... badgeLabels) {
481             mBadgeLabels = badgeLabels;
482             return this;
483         }
484 
setBadgeColors(@olorRes int ... badgeColors)485         public Builder setBadgeColors(@ColorRes int ... badgeColors) {
486             mBadgeColors = badgeColors;
487             return this;
488         }
489 
490         /**
491          * The badge colors when the badge is on a dark background.
492          */
setDarkThemeBadgeColors(@olorRes int ... darkThemeBadgeColors)493         public Builder setDarkThemeBadgeColors(@ColorRes int ... darkThemeBadgeColors) {
494             mDarkThemeBadgeColors = darkThemeBadgeColors;
495             return this;
496         }
497 
setIconBadge(@rawableRes int badgeIcon)498         public Builder setIconBadge(@DrawableRes int badgeIcon) {
499             mIconBadge = badgeIcon;
500             return this;
501         }
502 
setBadgePlain(@rawableRes int badgePlain)503         public Builder setBadgePlain(@DrawableRes int badgePlain) {
504             mBadgePlain = badgePlain;
505             return this;
506         }
507 
setBadgeNoBackground(@rawableRes int badgeNoBackground)508         public Builder setBadgeNoBackground(@DrawableRes int badgeNoBackground) {
509             mBadgeNoBackground = badgeNoBackground;
510             return this;
511         }
512 
setStatusBarIcon(@rawableRes int statusBarIcon)513         public Builder setStatusBarIcon(@DrawableRes int statusBarIcon) {
514             mStatusBarIcon = statusBarIcon;
515             return this;
516         }
517 
setLabels(@tringRes int ... labels)518         public Builder setLabels(@StringRes int ... labels) {
519             mLabels = labels;
520             return this;
521         }
522 
setDefaultRestrictions(@ullable Bundle restrictions)523         public Builder setDefaultRestrictions(@Nullable Bundle restrictions) {
524             mDefaultRestrictions = restrictions;
525             return this;
526         }
527 
setDefaultSystemSettings(@ullable Bundle settings)528         public Builder setDefaultSystemSettings(@Nullable Bundle settings) {
529             mDefaultSystemSettings = settings;
530             return this;
531         }
532 
setDefaultSecureSettings(@ullable Bundle settings)533         public Builder setDefaultSecureSettings(@Nullable Bundle settings) {
534             mDefaultSecureSettings = settings;
535             return this;
536         }
537 
setDefaultCrossProfileIntentFilters( @ullable List<DefaultCrossProfileIntentFilter> intentFilters)538         public Builder setDefaultCrossProfileIntentFilters(
539                 @Nullable List<DefaultCrossProfileIntentFilter> intentFilters) {
540             mDefaultCrossProfileIntentFilters = intentFilters;
541             return this;
542         }
543 
544         /**
545          * Sets the accessibility label associated with the user
546          */
setAccessibilityString(@tringRes int accessibilityString)547         public Builder setAccessibilityString(@StringRes int accessibilityString) {
548             mAccessibilityString = accessibilityString;
549             return this;
550         }
551 
552         /**
553          * Sets (replacing if necessary) the default UserProperties object for this user type.
554          * Takes a builder, rather than a built object, to efficiently ensure that a fresh copy of
555          * properties is stored (since it later might be modified by UserProperties#updateFromXml).
556          */
setDefaultUserProperties(UserProperties.Builder userPropertiesBuilder)557         public Builder setDefaultUserProperties(UserProperties.Builder userPropertiesBuilder) {
558             mDefaultUserProperties = userPropertiesBuilder.build();
559             return this;
560         }
561 
getDefaultUserProperties()562         public @NonNull UserProperties getDefaultUserProperties() {
563             if (mDefaultUserProperties == null) {
564                 mDefaultUserProperties = new UserProperties.Builder().build();
565             }
566             return mDefaultUserProperties;
567         }
568 
getBaseType()569         @UserInfoFlag int getBaseType() {
570             return mBaseType;
571         }
572 
createUserTypeDetails()573         public UserTypeDetails createUserTypeDetails() {
574             Preconditions.checkArgument(mName != null,
575                     "Cannot create a UserTypeDetails with no name.");
576             Preconditions.checkArgument(hasValidBaseType(),
577                     "UserTypeDetails " + mName + " has invalid baseType: " + mBaseType);
578             Preconditions.checkArgument(hasValidPropertyFlags(),
579                     "UserTypeDetails " + mName + " has invalid flags: "
580                             + Integer.toHexString(mDefaultUserInfoPropertyFlags));
581             checkSystemAndMainUserPreconditions();
582             if (hasBadge()) {
583                 Preconditions.checkArgument(mBadgeLabels != null && mBadgeLabels.length != 0,
584                         "UserTypeDetails " + mName + " has badge but no badgeLabels.");
585                 Preconditions.checkArgument(mBadgeColors != null && mBadgeColors.length != 0,
586                         "UserTypeDetails " + mName + " has badge but no badgeColors.");
587             }
588             if (!isProfile()) {
589                 Preconditions.checkArgument(mDefaultCrossProfileIntentFilters == null
590                                 || mDefaultCrossProfileIntentFilters.isEmpty(),
591                         "UserTypeDetails %s has a non empty "
592                                 + "defaultCrossProfileIntentFilters", mName);
593             }
594             return new UserTypeDetails(
595                     mName,
596                     mEnabled != 0,
597                     mMaxAllowed,
598                     mBaseType,
599                     mDefaultUserInfoPropertyFlags,
600                     mLabels,
601                     mMaxAllowedPerParent,
602                     mIconBadge,
603                     mBadgePlain,
604                     mBadgeNoBackground,
605                     mStatusBarIcon,
606                     mBadgeLabels,
607                     mBadgeColors,
608                     mDarkThemeBadgeColors == null ? mBadgeColors : mDarkThemeBadgeColors,
609                     mDefaultRestrictions,
610                     mDefaultSystemSettings,
611                     mDefaultSecureSettings,
612                     mDefaultCrossProfileIntentFilters,
613                     mAccessibilityString,
614                     getDefaultUserProperties());
615         }
616 
hasBadge()617         private boolean hasBadge() {
618             return mIconBadge != Resources.ID_NULL;
619         }
620 
isProfile()621         private boolean isProfile() {
622             return (mBaseType & UserInfo.FLAG_PROFILE) != 0;
623         }
624 
625         // TODO(b/143784345): Refactor this when we clean up UserInfo.
hasValidBaseType()626         private boolean hasValidBaseType() {
627             return mBaseType == UserInfo.FLAG_FULL
628                     || mBaseType == UserInfo.FLAG_PROFILE
629                     || mBaseType == UserInfo.FLAG_SYSTEM
630                     || mBaseType == (UserInfo.FLAG_FULL | UserInfo.FLAG_SYSTEM);
631         }
632 
633         // TODO(b/143784345): Refactor this when we clean up UserInfo.
hasValidPropertyFlags()634         private boolean hasValidPropertyFlags() {
635             final int forbiddenMask =
636                     UserInfo.FLAG_INITIALIZED |
637                     UserInfo.FLAG_QUIET_MODE |
638                     UserInfo.FLAG_FULL |
639                     UserInfo.FLAG_SYSTEM |
640                     UserInfo.FLAG_PROFILE;
641             return (mDefaultUserInfoPropertyFlags & forbiddenMask) == 0;
642         }
643 
checkSystemAndMainUserPreconditions()644         private void checkSystemAndMainUserPreconditions() {
645             // Primary must be synonymous with System.
646             Preconditions.checkArgument(
647                     ((mBaseType & UserInfo.FLAG_SYSTEM) != 0) ==
648                             ((mDefaultUserInfoPropertyFlags & UserInfo.FLAG_PRIMARY) != 0),
649                     "UserTypeDetails " + mName + " cannot be SYSTEM xor PRIMARY.");
650             // At most one MainUser is ever allowed at a time.
651             Preconditions.checkArgument(
652                     ((mDefaultUserInfoPropertyFlags & UserInfo.FLAG_MAIN) == 0) || mMaxAllowed == 1,
653                     "UserTypeDetails " + mName + " must not sanction more than one MainUser.");
654         }
655     }
656 
657     /**
658      * Returns whether the user type is a managed profile
659      * (i.e. {@link UserManager#USER_TYPE_PROFILE_MANAGED}).
660      */
isManagedProfile()661     public boolean isManagedProfile() {
662         return UserManager.isUserTypeManagedProfile(mName);
663     }
664 
665     /**
666      * Returns whether the user type is a communal profile
667      * (i.e. {@link UserManager#USER_TYPE_PROFILE_COMMUNAL}).
668      */
isCommunalProfile()669     public boolean isCommunalProfile() {
670         return UserManager.isUserTypeCommunalProfile(mName);
671     }
672 
673     /**
674      * Returns whether the user type is a private profile
675      * (i.e. {@link UserManager#USER_TYPE_PROFILE_PRIVATE}).
676      */
isPrivateProfile()677     public boolean isPrivateProfile() {
678         return UserManager.isUserTypePrivateProfile(mName);
679     }
680 }
681