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 static android.content.pm.UserInfo.FLAG_ADMIN; 20 import static android.content.pm.UserInfo.FLAG_DEMO; 21 import static android.content.pm.UserInfo.FLAG_EPHEMERAL; 22 import static android.content.pm.UserInfo.FLAG_FULL; 23 import static android.content.pm.UserInfo.FLAG_GUEST; 24 import static android.content.pm.UserInfo.FLAG_MAIN; 25 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; 26 import static android.content.pm.UserInfo.FLAG_PRIMARY; 27 import static android.content.pm.UserInfo.FLAG_PROFILE; 28 import static android.content.pm.UserInfo.FLAG_RESTRICTED; 29 import static android.content.pm.UserInfo.FLAG_SYSTEM; 30 import static android.os.UserManager.USER_TYPE_FULL_DEMO; 31 import static android.os.UserManager.USER_TYPE_FULL_GUEST; 32 import static android.os.UserManager.USER_TYPE_FULL_RESTRICTED; 33 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 34 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM; 35 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; 36 import static android.os.UserManager.USER_TYPE_PROFILE_COMMUNAL; 37 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 38 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; 39 import static android.os.UserManager.USER_TYPE_PROFILE_TEST; 40 import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS; 41 42 import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS; 43 44 import android.content.pm.UserInfo; 45 import android.content.pm.UserProperties; 46 import android.content.res.Resources; 47 import android.content.res.XmlResourceParser; 48 import android.os.Build; 49 import android.os.Bundle; 50 import android.os.UserManager; 51 import android.util.ArrayMap; 52 import android.util.Slog; 53 54 import com.android.internal.R; 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.internal.util.XmlUtils; 57 58 import org.xmlpull.v1.XmlPullParserException; 59 60 import java.io.IOException; 61 import java.util.ArrayList; 62 import java.util.List; 63 import java.util.function.Consumer; 64 65 /** 66 * Class for creating all {@link UserTypeDetails} on the device. 67 * 68 * This class is responsible both for defining the AOSP use types, as well as reading in customized 69 * user types from {@link com.android.internal.R.xml#config_user_types}. 70 * 71 * Tests are located in {@link UserManagerServiceUserTypeTest}. 72 * @hide 73 */ 74 public final class UserTypeFactory { 75 76 private static final String LOG_TAG = "UserTypeFactory"; 77 78 /** This is a utility class, so no instantiable constructor. */ UserTypeFactory()79 private UserTypeFactory() {} 80 81 /** 82 * Obtains the user types (built-in and customized) for this device. 83 * 84 * @return mapping from the name of each user type to its {@link UserTypeDetails} object 85 */ getUserTypes()86 public static ArrayMap<String, UserTypeDetails> getUserTypes() { 87 final ArrayMap<String, UserTypeDetails.Builder> builders = getDefaultBuilders(); 88 89 try (XmlResourceParser parser = 90 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 91 customizeBuilders(builders, parser); 92 } 93 94 final ArrayMap<String, UserTypeDetails> types = new ArrayMap<>(builders.size()); 95 for (int i = 0; i < builders.size(); i++) { 96 types.put(builders.keyAt(i), builders.valueAt(i).createUserTypeDetails()); 97 } 98 return types; 99 } 100 getDefaultBuilders()101 private static ArrayMap<String, UserTypeDetails.Builder> getDefaultBuilders() { 102 final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>(); 103 104 builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged()); 105 builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem()); 106 builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary()); 107 builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest()); 108 builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo()); 109 builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted()); 110 builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless()); 111 builders.put(USER_TYPE_PROFILE_CLONE, getDefaultTypeProfileClone()); 112 builders.put(USER_TYPE_PROFILE_COMMUNAL, getDefaultTypeProfileCommunal()); 113 builders.put(USER_TYPE_PROFILE_PRIVATE, getDefaultTypeProfilePrivate()); 114 if (Build.IS_DEBUGGABLE) { 115 builders.put(USER_TYPE_PROFILE_TEST, getDefaultTypeProfileTest()); 116 } 117 118 return builders; 119 } 120 121 /** 122 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_CLONE} 123 * configuration. 124 */ 125 // TODO(b/182396009): Add default restrictions, if needed for clone user type. getDefaultTypeProfileClone()126 private static UserTypeDetails.Builder getDefaultTypeProfileClone() { 127 return new UserTypeDetails.Builder() 128 .setName(USER_TYPE_PROFILE_CLONE) 129 .setBaseType(FLAG_PROFILE) 130 .setMaxAllowedPerParent(1) 131 .setLabels(R.string.profile_label_clone) 132 .setIconBadge(com.android.internal.R.drawable.ic_clone_icon_badge) 133 .setBadgePlain(com.android.internal.R.drawable.ic_clone_badge) 134 // Clone doesn't use BadgeNoBackground, so just set to BadgePlain as a placeholder. 135 .setBadgeNoBackground(com.android.internal.R.drawable.ic_clone_badge) 136 .setStatusBarIcon(Resources.ID_NULL) 137 .setBadgeLabels( 138 com.android.internal.R.string.clone_profile_label_badge) 139 .setBadgeColors( 140 com.android.internal.R.color.system_neutral2_800) 141 .setDarkThemeBadgeColors( 142 com.android.internal.R.color.system_neutral2_900) 143 .setAccessibilityString(com.android.internal 144 .R.string.accessibility_label_clone_profile) 145 .setDefaultRestrictions(null) 146 .setDefaultCrossProfileIntentFilters(getDefaultCloneCrossProfileIntentFilter()) 147 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) 148 .setDefaultUserProperties(new UserProperties.Builder() 149 .setStartWithParent(true) 150 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT) 151 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_WITH_PARENT) 152 .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT) 153 .setUseParentsContacts(true) 154 .setUpdateCrossProfileIntentFiltersOnOTA(true) 155 .setCrossProfileIntentFilterAccessControl( 156 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM) 157 .setCrossProfileIntentResolutionStrategy(UserProperties 158 .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING) 159 .setShowInQuietMode( 160 UserProperties.SHOW_IN_QUIET_MODE_DEFAULT) 161 .setShowInSharingSurfaces( 162 UserProperties.SHOW_IN_SHARING_SURFACES_WITH_PARENT) 163 .setMediaSharedWithParent(true) 164 .setCredentialShareableWithParent(true) 165 .setDeleteAppWithParent(true) 166 .setCrossProfileContentSharingStrategy(UserProperties 167 .CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT)); 168 } 169 170 /** 171 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_MANAGED} 172 * configuration. 173 */ getDefaultTypeProfileManaged()174 private static UserTypeDetails.Builder getDefaultTypeProfileManaged() { 175 return new UserTypeDetails.Builder() 176 .setName(USER_TYPE_PROFILE_MANAGED) 177 .setBaseType(FLAG_PROFILE) 178 .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE) 179 .setMaxAllowedPerParent(1) 180 .setLabels( 181 R.string.profile_label_work, 182 R.string.profile_label_work_2, 183 R.string.profile_label_work_3) 184 .setIconBadge(com.android.internal.R.drawable.ic_corp_icon_badge_case) 185 .setBadgePlain(com.android.internal.R.drawable.ic_corp_badge_case) 186 .setBadgeNoBackground(com.android.internal.R.drawable.ic_corp_badge_no_background) 187 .setStatusBarIcon(com.android.internal.R.drawable.stat_sys_managed_profile_status) 188 .setBadgeLabels( 189 com.android.internal.R.string.managed_profile_label_badge, 190 com.android.internal.R.string.managed_profile_label_badge_2, 191 com.android.internal.R.string.managed_profile_label_badge_3) 192 .setBadgeColors( 193 com.android.internal.R.color.profile_badge_1, 194 com.android.internal.R.color.profile_badge_2, 195 com.android.internal.R.color.profile_badge_3) 196 .setDarkThemeBadgeColors( 197 com.android.internal.R.color.profile_badge_1_dark, 198 com.android.internal.R.color.profile_badge_2_dark, 199 com.android.internal.R.color.profile_badge_3_dark) 200 .setAccessibilityString(com.android.internal 201 .R.string.accessibility_label_managed_profile) 202 .setDefaultRestrictions(getDefaultProfileRestrictions()) 203 .setDefaultSecureSettings(getDefaultManagedProfileSecureSettings()) 204 .setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter()) 205 .setDefaultUserProperties(new UserProperties.Builder() 206 .setStartWithParent(true) 207 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 208 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 209 .setShowInQuietMode( 210 UserProperties.SHOW_IN_QUIET_MODE_PAUSED) 211 .setShowInSharingSurfaces( 212 UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) 213 .setAuthAlwaysRequiredToDisableQuietMode(false) 214 .setCredentialShareableWithParent(true)); 215 } 216 217 /** 218 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_TEST} 219 * configuration (for userdebug builds). For now it just uses managed profile badges. 220 */ getDefaultTypeProfileTest()221 private static UserTypeDetails.Builder getDefaultTypeProfileTest() { 222 final Bundle restrictions = getDefaultProfileRestrictions(); 223 restrictions.putBoolean(UserManager.DISALLOW_FUN, true); 224 225 return new UserTypeDetails.Builder() 226 .setName(USER_TYPE_PROFILE_TEST) 227 .setBaseType(FLAG_PROFILE) 228 .setMaxAllowedPerParent(2) 229 .setLabels( 230 R.string.profile_label_test, 231 R.string.profile_label_test, 232 R.string.profile_label_test) 233 .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment) 234 .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment) 235 .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background) 236 .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment) 237 .setBadgeLabels( 238 com.android.internal.R.string.managed_profile_label_badge, 239 com.android.internal.R.string.managed_profile_label_badge_2, 240 com.android.internal.R.string.managed_profile_label_badge_3) 241 .setBadgeColors( 242 com.android.internal.R.color.profile_badge_1, 243 com.android.internal.R.color.profile_badge_2, 244 com.android.internal.R.color.profile_badge_3) 245 .setDarkThemeBadgeColors( 246 com.android.internal.R.color.profile_badge_1_dark, 247 com.android.internal.R.color.profile_badge_2_dark, 248 com.android.internal.R.color.profile_badge_3_dark) 249 .setDefaultRestrictions(restrictions) 250 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()); 251 } 252 253 /** 254 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_COMMUNAL} 255 * configuration. For now it just uses managed profile badges. 256 */ getDefaultTypeProfileCommunal()257 private static UserTypeDetails.Builder getDefaultTypeProfileCommunal() { 258 return new UserTypeDetails.Builder() 259 .setName(USER_TYPE_PROFILE_COMMUNAL) 260 .setBaseType(FLAG_PROFILE) 261 .setMaxAllowed(1) 262 .setEnabled(UserManager.isCommunalProfileEnabled() ? 1 : 0) 263 .setLabels(R.string.profile_label_communal) 264 .setIconBadge(com.android.internal.R.drawable.ic_test_icon_badge_experiment) 265 .setBadgePlain(com.android.internal.R.drawable.ic_test_badge_experiment) 266 .setBadgeNoBackground(com.android.internal.R.drawable.ic_test_badge_no_background) 267 .setStatusBarIcon(com.android.internal.R.drawable.ic_test_badge_experiment) 268 .setBadgeLabels( 269 com.android.internal.R.string.managed_profile_label_badge, 270 com.android.internal.R.string.managed_profile_label_badge_2, 271 com.android.internal.R.string.managed_profile_label_badge_3) 272 .setBadgeColors( 273 com.android.internal.R.color.profile_badge_1, 274 com.android.internal.R.color.profile_badge_2, 275 com.android.internal.R.color.profile_badge_3) 276 .setDarkThemeBadgeColors( 277 com.android.internal.R.color.profile_badge_1_dark, 278 com.android.internal.R.color.profile_badge_2_dark, 279 com.android.internal.R.color.profile_badge_3_dark) 280 .setDefaultRestrictions(getDefaultProfileRestrictions()) 281 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) 282 .setDefaultUserProperties(new UserProperties.Builder() 283 .setStartWithParent(false) 284 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 285 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 286 .setCredentialShareableWithParent(false) 287 .setAlwaysVisible(true)); 288 } 289 290 /** 291 * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_PRIVATE} 292 * configuration. 293 */ getDefaultTypeProfilePrivate()294 private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() { 295 return new UserTypeDetails.Builder() 296 .setName(USER_TYPE_PROFILE_PRIVATE) 297 .setBaseType(FLAG_PROFILE) 298 .setMaxAllowedPerParent(1) 299 .setEnabled(UserManager.isPrivateProfileEnabled() ? 1 : 0) 300 .setLabels(R.string.profile_label_private) 301 .setIconBadge(com.android.internal.R.drawable.ic_private_profile_icon_badge) 302 .setBadgePlain(com.android.internal.R.drawable.ic_private_profile_badge) 303 // Private Profile doesn't use BadgeNoBackground, so just set to BadgePlain 304 // as a placeholder. 305 .setBadgeNoBackground(com.android.internal.R.drawable.ic_private_profile_badge) 306 .setStatusBarIcon(com.android.internal.R.drawable.stat_sys_private_profile_status) 307 .setBadgeLabels( 308 com.android.internal.R.string.private_profile_label_badge) 309 .setBadgeColors( 310 R.color.black) 311 .setDarkThemeBadgeColors( 312 R.color.white) 313 .setAccessibilityString(com.android.internal 314 .R.string.accessibility_label_private_profile) 315 .setDefaultRestrictions(getDefaultPrivateProfileRestrictions()) 316 .setDefaultCrossProfileIntentFilters(getDefaultPrivateCrossProfileIntentFilter()) 317 .setDefaultUserProperties(new UserProperties.Builder() 318 .setStartWithParent(true) 319 .setCredentialShareableWithParent(true) 320 .setAuthAlwaysRequiredToDisableQuietMode(true) 321 .setAllowStoppingUserWithDelayedLocking(true) 322 .setMediaSharedWithParent(false) 323 .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE) 324 .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE) 325 .setShowInQuietMode( 326 UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) 327 .setShowInSharingSurfaces( 328 UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) 329 .setCrossProfileIntentFilterAccessControl( 330 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM) 331 .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT) 332 .setCrossProfileContentSharingStrategy( 333 UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) 334 .setProfileApiVisibility( 335 UserProperties.PROFILE_API_VISIBILITY_HIDDEN) 336 .setItemsRestrictedOnHomeScreen(true) 337 .setUpdateCrossProfileIntentFiltersOnOTA(true)); 338 } 339 340 /** 341 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SECONDARY} 342 * configuration. 343 */ getDefaultTypeFullSecondary()344 private static UserTypeDetails.Builder getDefaultTypeFullSecondary() { 345 return new UserTypeDetails.Builder() 346 .setName(USER_TYPE_FULL_SECONDARY) 347 .setBaseType(FLAG_FULL) 348 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 349 .setDefaultRestrictions(getDefaultSecondaryUserRestrictions()); 350 } 351 352 /** 353 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_GUEST} configuration. 354 */ getDefaultTypeFullGuest()355 private static UserTypeDetails.Builder getDefaultTypeFullGuest() { 356 final boolean ephemeralGuests = Resources.getSystem() 357 .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral); 358 final int flags = FLAG_GUEST | (ephemeralGuests ? FLAG_EPHEMERAL : 0); 359 360 return new UserTypeDetails.Builder() 361 .setName(USER_TYPE_FULL_GUEST) 362 .setBaseType(FLAG_FULL) 363 .setDefaultUserInfoPropertyFlags(flags) 364 .setMaxAllowed(1) 365 .setDefaultRestrictions(getDefaultGuestUserRestrictions()); 366 } 367 368 /** 369 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_DEMO} configuration. 370 */ getDefaultTypeFullDemo()371 private static UserTypeDetails.Builder getDefaultTypeFullDemo() { 372 return new UserTypeDetails.Builder() 373 .setName(USER_TYPE_FULL_DEMO) 374 .setBaseType(FLAG_FULL) 375 .setDefaultUserInfoPropertyFlags(FLAG_DEMO) 376 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 377 .setDefaultRestrictions(null); 378 } 379 380 /** 381 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_RESTRICTED} 382 * configuration. 383 */ getDefaultTypeFullRestricted()384 private static UserTypeDetails.Builder getDefaultTypeFullRestricted() { 385 return new UserTypeDetails.Builder() 386 .setName(USER_TYPE_FULL_RESTRICTED) 387 .setBaseType(FLAG_FULL) 388 .setDefaultUserInfoPropertyFlags(FLAG_RESTRICTED) 389 .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS) 390 // NB: UserManagerService.createRestrictedProfile() applies hardcoded restrictions. 391 .setDefaultRestrictions(null); 392 } 393 394 /** 395 * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SYSTEM} configuration. 396 */ getDefaultTypeFullSystem()397 private static UserTypeDetails.Builder getDefaultTypeFullSystem() { 398 return new UserTypeDetails.Builder() 399 .setName(USER_TYPE_FULL_SYSTEM) 400 .setBaseType(FLAG_SYSTEM | FLAG_FULL) 401 .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN | FLAG_MAIN) 402 .setMaxAllowed(1); 403 } 404 405 /** 406 * Returns the Builder for the default {@link UserManager#USER_TYPE_SYSTEM_HEADLESS} 407 * configuration. 408 */ getDefaultTypeSystemHeadless()409 private static UserTypeDetails.Builder getDefaultTypeSystemHeadless() { 410 return new UserTypeDetails.Builder() 411 .setName(USER_TYPE_SYSTEM_HEADLESS) 412 .setBaseType(FLAG_SYSTEM) 413 .setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN) 414 .setMaxAllowed(1); 415 } 416 getDefaultSecondaryUserRestrictions()417 private static Bundle getDefaultSecondaryUserRestrictions() { 418 final Bundle restrictions = new Bundle(); 419 restrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true); 420 restrictions.putBoolean(UserManager.DISALLOW_SMS, true); 421 return restrictions; 422 } 423 getDefaultGuestUserRestrictions()424 private static Bundle getDefaultGuestUserRestrictions() { 425 // Guest inherits the secondary user's restrictions, plus has some extra ones. 426 final Bundle restrictions = getDefaultSecondaryUserRestrictions(); 427 restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true); 428 restrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); 429 restrictions.putBoolean(UserManager.DISALLOW_CONFIG_CREDENTIALS, true); 430 return restrictions; 431 } 432 getDefaultProfileRestrictions()433 private static Bundle getDefaultProfileRestrictions() { 434 final Bundle restrictions = new Bundle(); 435 restrictions.putBoolean(UserManager.DISALLOW_WALLPAPER, true); 436 return restrictions; 437 } 438 439 @VisibleForTesting getDefaultPrivateProfileRestrictions()440 static Bundle getDefaultPrivateProfileRestrictions() { 441 final Bundle restrictions = getDefaultProfileRestrictions(); 442 restrictions.putBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING, true); 443 return restrictions; 444 } 445 getDefaultManagedProfileSecureSettings()446 private static Bundle getDefaultManagedProfileSecureSettings() { 447 // Only add String values to the bundle, settings are written as Strings eventually 448 final Bundle settings = new Bundle(); 449 settings.putString( 450 android.provider.Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, "1"); 451 settings.putString( 452 android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, "1"); 453 return settings; 454 } 455 456 private static List<DefaultCrossProfileIntentFilter> getDefaultManagedCrossProfileIntentFilter()457 getDefaultManagedCrossProfileIntentFilter() { 458 return DefaultCrossProfileIntentFiltersUtils.getDefaultManagedProfileFilters(); 459 } 460 getDefaultCloneCrossProfileIntentFilter()461 private static List<DefaultCrossProfileIntentFilter> getDefaultCloneCrossProfileIntentFilter() { 462 return DefaultCrossProfileIntentFiltersUtils.getDefaultCloneProfileFilters(); 463 } 464 getDefaultPrivateCrossProfileIntentFilter()465 private static List<DefaultCrossProfileIntentFilter> getDefaultPrivateCrossProfileIntentFilter() 466 { 467 return DefaultCrossProfileIntentFiltersUtils.getDefaultPrivateProfileFilters(); 468 } 469 470 /** Gets a default bundle, keyed by Settings.Secure String names, for non-managed profiles. */ getDefaultNonManagedProfileSecureSettings()471 private static Bundle getDefaultNonManagedProfileSecureSettings() { 472 final Bundle settings = new Bundle(); 473 // Non-managed profiles go through neither SetupWizard nor DPC flows, so we automatically 474 // mark them as setup. 475 settings.putString(android.provider.Settings.Secure.USER_SETUP_COMPLETE, "1"); 476 return settings; 477 } 478 479 /** 480 * Reads the given xml parser to obtain device user-type customization, and updates the given 481 * map of {@link UserTypeDetails.Builder}s accordingly. 482 * <p> 483 * The xml file can specify the attributes according to the set... methods below. 484 */ 485 // TODO(b/176973369): Add parsing logic to support custom settings/filters 486 // in config_user_types.xml 487 @VisibleForTesting customizeBuilders(ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser)488 static void customizeBuilders(ArrayMap<String, UserTypeDetails.Builder> builders, 489 XmlResourceParser parser) { 490 try { 491 XmlUtils.beginDocument(parser, "user-types"); 492 for (XmlUtils.nextElement(parser); 493 parser.getEventType() != XmlResourceParser.END_DOCUMENT; 494 XmlUtils.nextElement(parser)) { 495 final boolean isProfile; 496 final String elementName = parser.getName(); 497 if ("profile-type".equals(elementName)) { 498 isProfile = true; 499 } else if ("full-type".equals(elementName)) { 500 isProfile = false; 501 } else if ("change-user-type".equals(elementName)) { 502 // parsed in parseUserUpgrades 503 XmlUtils.skipCurrentTag(parser); 504 continue; 505 } else { 506 Slog.w(LOG_TAG, "Skipping unknown element " + elementName + " in " 507 + parser.getPositionDescription()); 508 XmlUtils.skipCurrentTag(parser); 509 continue; 510 } 511 512 String typeName = parser.getAttributeValue(null, "name"); 513 if (typeName == null || typeName.equals("")) { 514 Slog.w(LOG_TAG, "Skipping user type with no name in " 515 + parser.getPositionDescription()); 516 XmlUtils.skipCurrentTag(parser); 517 continue; 518 } 519 typeName = typeName.intern(); 520 521 UserTypeDetails.Builder builder; 522 if (typeName.startsWith("android.")) { 523 // typeName refers to a AOSP-defined type which we are modifying. 524 Slog.i(LOG_TAG, "Customizing user type " + typeName); 525 builder = builders.get(typeName); 526 if (builder == null) { 527 throw new IllegalArgumentException("Illegal custom user type name " 528 + typeName + ": Non-AOSP user types cannot start with 'android.'"); 529 } 530 final boolean isValid = 531 (isProfile && builder.getBaseType() == UserInfo.FLAG_PROFILE) 532 || (!isProfile && builder.getBaseType() == UserInfo.FLAG_FULL); 533 if (!isValid) { 534 throw new IllegalArgumentException("Wrong base type to customize user type " 535 + "(" + typeName + "), which is type " 536 + UserInfo.flagsToString(builder.getBaseType())); 537 } 538 } else if (isProfile) { 539 // typeName refers to a new OEM-defined profile type which we are defining. 540 Slog.i(LOG_TAG, "Creating custom user type " + typeName); 541 builder = new UserTypeDetails.Builder(); 542 builder.setName(typeName); 543 builder.setBaseType(FLAG_PROFILE); 544 builders.put(typeName, builder); 545 } else { 546 throw new IllegalArgumentException("Creation of non-profile user type " 547 + "(" + typeName + ") is not currently supported."); 548 } 549 550 // Process the attributes (other than name). 551 if (isProfile) { 552 setIntAttribute(parser, "max-allowed-per-parent", 553 builder::setMaxAllowedPerParent); 554 setResAttribute(parser, "icon-badge", builder::setIconBadge); 555 setResAttribute(parser, "badge-plain", builder::setBadgePlain); 556 setResAttribute(parser, "badge-no-background", builder::setBadgeNoBackground); 557 setResAttribute(parser, "status-bar-icon", builder::setStatusBarIcon); 558 } 559 560 setIntAttribute(parser, "enabled", builder::setEnabled); 561 setIntAttribute(parser, "max-allowed", builder::setMaxAllowed); 562 563 // Process child elements. 564 final int depth = parser.getDepth(); 565 while (XmlUtils.nextElementWithin(parser, depth)) { 566 final String childName = parser.getName(); 567 if ("default-restrictions".equals(childName)) { 568 final Bundle restrictions = UserRestrictionsUtils 569 .readRestrictions(XmlUtils.makeTyped(parser)); 570 builder.setDefaultRestrictions(restrictions); 571 } else if (isProfile && "badge-labels".equals(childName)) { 572 setResAttributeArray(parser, builder::setBadgeLabels); 573 } else if (isProfile && "badge-colors".equals(childName)) { 574 setResAttributeArray(parser, builder::setBadgeColors); 575 } else if (isProfile && "badge-colors-dark".equals(childName)) { 576 setResAttributeArray(parser, builder::setDarkThemeBadgeColors); 577 } else if ("user-properties".equals(childName)) { 578 builder.getDefaultUserProperties() 579 .updateFromXml(XmlUtils.makeTyped(parser)); 580 } else { 581 Slog.w(LOG_TAG, "Unrecognized tag " + childName + " in " 582 + parser.getPositionDescription()); 583 } 584 } 585 } 586 } catch (XmlPullParserException | IOException e) { 587 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 588 } 589 } 590 591 /** 592 * If the given attribute exists, gets the int stored in it and performs the given fcn using it. 593 * The stored value must be an int or NumberFormatException will be thrown. 594 * 595 * @param parser xml parser from which to read the attribute 596 * @param attributeName name of the attribute 597 * @param fcn one-int-argument function, 598 * like {@link UserTypeDetails.Builder#setMaxAllowedPerParent(int)} 599 */ setIntAttribute(XmlResourceParser parser, String attributeName, Consumer<Integer> fcn)600 private static void setIntAttribute(XmlResourceParser parser, String attributeName, 601 Consumer<Integer> fcn) { 602 final String intValue = parser.getAttributeValue(null, attributeName); 603 if (intValue == null) { 604 return; 605 } 606 try { 607 fcn.accept(Integer.parseInt(intValue)); 608 } catch (NumberFormatException e) { 609 Slog.e(LOG_TAG, "Cannot parse value of '" + intValue + "' for " + attributeName 610 + " in " + parser.getPositionDescription(), e); 611 throw e; 612 } 613 } 614 615 /** 616 * If the given attribute exists, gets the resId stored in it (or 0 if it is not a valid resId) 617 * and performs the given fcn using it. 618 * 619 * @param parser xml parser from which to read the attribute 620 * @param attributeName name of the attribute 621 * @param fcn one-argument function, like {@link UserTypeDetails.Builder#setIconBadge(int)} 622 */ setResAttribute(XmlResourceParser parser, String attributeName, Consumer<Integer> fcn)623 private static void setResAttribute(XmlResourceParser parser, String attributeName, 624 Consumer<Integer> fcn) { 625 if (parser.getAttributeValue(null, attributeName) == null) { 626 // Attribute is not present, i.e. use the default value. 627 return; 628 } 629 final int resId = parser.getAttributeResourceValue(null, attributeName, Resources.ID_NULL); 630 fcn.accept(resId); 631 } 632 633 /** 634 * Gets the resIds stored in "item" elements (in their "res" attribute) at the current depth. 635 * Then performs the given fcn using the int[] array of these resIds. 636 * <p> 637 * Each xml element is expected to be of the form {@code <item res="someResValue" />}. 638 * 639 * @param parser xml parser from which to read the elements and their attributes 640 * @param fcn function, like {@link UserTypeDetails.Builder#setBadgeColors(int...)} 641 */ setResAttributeArray(XmlResourceParser parser, Consumer<int[]> fcn)642 private static void setResAttributeArray(XmlResourceParser parser, Consumer<int[]> fcn) 643 throws IOException, XmlPullParserException { 644 645 ArrayList<Integer> resList = new ArrayList<>(); 646 final int depth = parser.getDepth(); 647 while (XmlUtils.nextElementWithin(parser, depth)) { 648 final String elementName = parser.getName(); 649 if (!"item".equals(elementName)) { 650 Slog.w(LOG_TAG, "Skipping unknown child element " + elementName + " in " 651 + parser.getPositionDescription()); 652 XmlUtils.skipCurrentTag(parser); 653 continue; 654 } 655 final int resId = parser.getAttributeResourceValue(null, "res", -1); 656 if (resId == -1) { 657 continue; 658 } 659 resList.add(resId); 660 } 661 662 int[] result = new int[resList.size()]; 663 for (int i = 0; i < resList.size(); i++) { 664 result[i] = resList.get(i); 665 } 666 fcn.accept(result); 667 } 668 669 /** 670 * Returns the user type version of the config XML file. 671 * @return user type version defined in XML file, 0 if none. 672 */ getUserTypeVersion()673 public static int getUserTypeVersion() { 674 try (XmlResourceParser parser = 675 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 676 return getUserTypeVersion(parser); 677 } 678 } 679 680 @VisibleForTesting getUserTypeVersion(XmlResourceParser parser)681 static int getUserTypeVersion(XmlResourceParser parser) { 682 int version = 0; 683 684 try { 685 XmlUtils.beginDocument(parser, "user-types"); 686 String versionValue = parser.getAttributeValue(null, "version"); 687 if (versionValue != null) { 688 try { 689 version = Integer.parseInt(versionValue); 690 } catch (NumberFormatException e) { 691 Slog.e(LOG_TAG, "Cannot parse value of '" + versionValue + "' for version in " 692 + parser.getPositionDescription(), e); 693 throw e; 694 } 695 } 696 } catch (XmlPullParserException | IOException e) { 697 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 698 } 699 700 return version; 701 } 702 703 /** 704 * Obtains the user type upgrades for this device. 705 * @return The list of user type upgrades. 706 */ getUserTypeUpgrades()707 public static List<UserTypeUpgrade> getUserTypeUpgrades() { 708 final List<UserTypeUpgrade> userUpgrades; 709 try (XmlResourceParser parser = 710 Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) { 711 userUpgrades = parseUserUpgrades(getDefaultBuilders(), parser); 712 } 713 return userUpgrades; 714 } 715 716 @VisibleForTesting parseUserUpgrades( ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser)717 static List<UserTypeUpgrade> parseUserUpgrades( 718 ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser) { 719 final List<UserTypeUpgrade> userUpgrades = new ArrayList<>(); 720 721 try { 722 XmlUtils.beginDocument(parser, "user-types"); 723 for (XmlUtils.nextElement(parser); 724 parser.getEventType() != XmlResourceParser.END_DOCUMENT; 725 XmlUtils.nextElement(parser)) { 726 final String elementName = parser.getName(); 727 if ("change-user-type".equals(elementName)) { 728 final String fromType = parser.getAttributeValue(null, "from"); 729 final String toType = parser.getAttributeValue(null, "to"); 730 // Check that the base type doesn't change. 731 // Currently, only the base type of PROFILE is supported. 732 validateUserTypeIsProfile(fromType, builders); 733 validateUserTypeIsProfile(toType, builders); 734 735 final int maxVersionToConvert; 736 try { 737 maxVersionToConvert = Integer.parseInt( 738 parser.getAttributeValue(null, "whenVersionLeq")); 739 } catch (NumberFormatException e) { 740 Slog.e(LOG_TAG, "Cannot parse value of whenVersionLeq in " 741 + parser.getPositionDescription(), e); 742 throw e; 743 } 744 745 UserTypeUpgrade userTypeUpgrade = new UserTypeUpgrade(fromType, toType, 746 maxVersionToConvert); 747 userUpgrades.add(userTypeUpgrade); 748 continue; 749 } else { 750 XmlUtils.skipCurrentTag(parser); 751 continue; 752 } 753 } 754 } catch (XmlPullParserException | IOException e) { 755 Slog.w(LOG_TAG, "Cannot read user type configuration file.", e); 756 } 757 758 return userUpgrades; 759 } 760 validateUserTypeIsProfile(String userType, ArrayMap<String, UserTypeDetails.Builder> builders)761 private static void validateUserTypeIsProfile(String userType, 762 ArrayMap<String, UserTypeDetails.Builder> builders) { 763 UserTypeDetails.Builder builder = builders.get(userType); 764 if (builder != null && builder.getBaseType() != FLAG_PROFILE) { 765 throw new IllegalArgumentException("Illegal upgrade of user type " + userType 766 + " : Can only upgrade profiles user types"); 767 } 768 } 769 770 /** 771 * Contains details required for an upgrade operation for {@link UserTypeDetails}; 772 */ 773 public static class UserTypeUpgrade { 774 private final String mFromType; 775 private final String mToType; 776 private final int mUpToVersion; 777 UserTypeUpgrade(String fromType, String toType, int upToVersion)778 public UserTypeUpgrade(String fromType, String toType, int upToVersion) { 779 mFromType = fromType; 780 mToType = toType; 781 mUpToVersion = upToVersion; 782 } 783 getFromType()784 public String getFromType() { 785 return mFromType; 786 } 787 getToType()788 public String getToType() { 789 return mToType; 790 } 791 getUpToVersion()792 public int getUpToVersion() { 793 return mUpToVersion; 794 } 795 } 796 } 797