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