1 /* 2 * Copyright (C) 2023 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.documentsui; 18 19 import static androidx.core.util.Preconditions.checkNotNull; 20 21 import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLID_COLORED; 22 import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; 23 import static com.android.documentsui.DevicePolicyResources.Strings.PERSONAL_TAB; 24 import static com.android.documentsui.DevicePolicyResources.Strings.WORK_TAB; 25 import static com.android.documentsui.base.SharedMinimal.DEBUG; 26 27 import android.Manifest; 28 import android.annotation.SuppressLint; 29 import android.app.ActivityManager; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.content.pm.UserProperties; 37 import android.graphics.drawable.Drawable; 38 import android.os.Build; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.util.Log; 42 43 import androidx.annotation.GuardedBy; 44 import androidx.annotation.RequiresApi; 45 import androidx.annotation.VisibleForTesting; 46 47 import com.android.documentsui.base.Features; 48 import com.android.documentsui.base.UserId; 49 import com.android.documentsui.util.CrossProfileUtils; 50 import com.android.documentsui.util.VersionUtils; 51 import com.android.modules.utils.build.SdkLevel; 52 53 import com.google.common.base.Objects; 54 55 import java.util.ArrayList; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Map; 59 60 @RequiresApi(Build.VERSION_CODES.S) 61 public interface UserManagerState { 62 63 /** 64 * Returns the {@link UserId} of each profile which should be queried for documents. This will 65 * always 66 * include {@link UserId#CURRENT_USER}. 67 */ getUserIds()68 List<UserId> getUserIds(); 69 70 /** 71 * Returns mapping between the {@link UserId} and the label for the profile 72 */ getUserIdToLabelMap()73 Map<UserId, String> getUserIdToLabelMap(); 74 75 /** 76 * Returns mapping between the {@link UserId} and the drawable badge for the profile 77 * 78 * returns {@code null} for non-profile userId 79 */ getUserIdToBadgeMap()80 Map<UserId, Drawable> getUserIdToBadgeMap(); 81 82 /** 83 * Returns a map of {@link UserId} to boolean value indicating whether 84 * the {@link UserId}.CURRENT_USER can forward {@link Intent} to that {@link UserId} 85 */ getCanForwardToProfileIdMap(Intent intent)86 Map<UserId, Boolean> getCanForwardToProfileIdMap(Intent intent); 87 88 /** 89 * Updates the state of the list of userIds and all the associated maps according the intent 90 * received in broadcast 91 * 92 * @param userId {@link UserId} for the profile for which the availability status changed 93 * @param action {@link Intent}.ACTION_PROFILE_UNAVAILABLE and {@link 94 * Intent}.ACTION_PROFILE_AVAILABLE, {@link Intent}.ACTION_PROFILE_ADDED} and {@link 95 * Intent}.ACTION_PROFILE_REMOVED} 96 */ onProfileActionStatusChange(String action, UserId userId)97 void onProfileActionStatusChange(String action, UserId userId); 98 99 /** 100 * Sets the intent that triggered the launch of the DocsUI 101 */ setCurrentStateIntent(Intent intent)102 void setCurrentStateIntent(Intent intent); 103 104 /** Returns true if there are hidden profiles */ areHiddenInQuietModeProfilesPresent()105 boolean areHiddenInQuietModeProfilesPresent(); 106 107 /** 108 * Creates an implementation of {@link UserManagerState}. 109 */ 110 // TODO: b/314746383 Make this class a singleton create(Context context)111 static UserManagerState create(Context context) { 112 return new RuntimeUserManagerState(context); 113 } 114 115 /** 116 * Implementation of {@link UserManagerState} 117 */ 118 final class RuntimeUserManagerState implements UserManagerState { 119 120 private static final String TAG = "UserManagerState"; 121 private final Context mContext; 122 private final UserId mCurrentUser; 123 private final boolean mIsDeviceSupported; 124 private final UserManager mUserManager; 125 private final ConfigStore mConfigStore; 126 /** 127 * List of all the {@link UserId} that have the {@link UserProperties.ShowInSharingSurfaces} 128 * set as `SHOW_IN_SHARING_SURFACES_SEPARATE` OR it is a system/personal user 129 */ 130 @GuardedBy("mUserIds") 131 private final List<UserId> mUserIds = new ArrayList<>(); 132 /** 133 * Mapping between the {@link UserId} to the corresponding profile label 134 */ 135 @GuardedBy("mUserIdToLabelMap") 136 private final Map<UserId, String> mUserIdToLabelMap = new HashMap<>(); 137 /** 138 * Mapping between the {@link UserId} to the corresponding profile badge 139 */ 140 @GuardedBy("mUserIdToBadgeMap") 141 private final Map<UserId, Drawable> mUserIdToBadgeMap = new HashMap<>(); 142 /** 143 * Map containing {@link UserId}, other than that of the current user, as key and boolean 144 * denoting whether it is accessible by the current user or not as value 145 */ 146 @GuardedBy("mCanFrowardToProfileIdMap") 147 private final Map<UserId, Boolean> mCanFrowardToProfileIdMap = new HashMap<>(); 148 149 private Intent mCurrentStateIntent; 150 151 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 152 @Override 153 public void onReceive(Context context, Intent intent) { 154 synchronized (mUserIds) { 155 mUserIds.clear(); 156 } 157 synchronized (mUserIdToLabelMap) { 158 mUserIdToLabelMap.clear(); 159 } 160 synchronized (mUserIdToBadgeMap) { 161 mUserIdToBadgeMap.clear(); 162 } 163 synchronized (mCanFrowardToProfileIdMap) { 164 mCanFrowardToProfileIdMap.clear(); 165 } 166 } 167 }; 168 169 RuntimeUserManagerState(Context context)170 private RuntimeUserManagerState(Context context) { 171 this(context, UserId.CURRENT_USER, 172 Features.CROSS_PROFILE_TABS && isDeviceSupported(context), 173 DocumentsApplication.getConfigStore()); 174 } 175 176 @VisibleForTesting RuntimeUserManagerState(Context context, UserId currentUser, boolean isDeviceSupported, ConfigStore configStore)177 RuntimeUserManagerState(Context context, UserId currentUser, boolean isDeviceSupported, 178 ConfigStore configStore) { 179 mContext = context.getApplicationContext(); 180 mCurrentUser = checkNotNull(currentUser); 181 mIsDeviceSupported = isDeviceSupported; 182 mUserManager = mContext.getSystemService(UserManager.class); 183 mConfigStore = configStore; 184 185 IntentFilter filter = new IntentFilter(); 186 filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 187 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 188 if (SdkLevel.isAtLeastV() && mConfigStore.isPrivateSpaceInDocsUIEnabled()) { 189 filter.addAction(Intent.ACTION_PROFILE_ADDED); 190 filter.addAction(Intent.ACTION_PROFILE_REMOVED); 191 } 192 mContext.registerReceiver(mIntentReceiver, filter); 193 } 194 195 @Override getUserIds()196 public List<UserId> getUserIds() { 197 synchronized (mUserIds) { 198 if (mUserIds.isEmpty()) { 199 mUserIds.addAll(getUserIdsInternal()); 200 } 201 return mUserIds; 202 } 203 } 204 205 @Override getUserIdToLabelMap()206 public Map<UserId, String> getUserIdToLabelMap() { 207 synchronized (mUserIdToLabelMap) { 208 if (mUserIdToLabelMap.isEmpty()) { 209 getUserIdToLabelMapInternal(); 210 } 211 return mUserIdToLabelMap; 212 } 213 } 214 215 @Override getUserIdToBadgeMap()216 public Map<UserId, Drawable> getUserIdToBadgeMap() { 217 synchronized (mUserIdToBadgeMap) { 218 if (mUserIdToBadgeMap.isEmpty()) { 219 getUserIdToBadgeMapInternal(); 220 } 221 return mUserIdToBadgeMap; 222 } 223 } 224 225 @Override getCanForwardToProfileIdMap(Intent intent)226 public Map<UserId, Boolean> getCanForwardToProfileIdMap(Intent intent) { 227 synchronized (mCanFrowardToProfileIdMap) { 228 if (mCanFrowardToProfileIdMap.isEmpty()) { 229 getCanForwardToProfileIdMapInternal(intent); 230 } 231 return mCanFrowardToProfileIdMap; 232 } 233 } 234 235 @Override 236 @SuppressLint("NewApi") onProfileActionStatusChange(String action, UserId userId)237 public void onProfileActionStatusChange(String action, UserId userId) { 238 if (!SdkLevel.isAtLeastV()) return; 239 UserProperties userProperties = mUserManager.getUserProperties( 240 UserHandle.of(userId.getIdentifier())); 241 if (userProperties.getShowInQuietMode() != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { 242 return; 243 } 244 if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action) 245 || Intent.ACTION_PROFILE_REMOVED.equals(action)) { 246 synchronized (mUserIds) { 247 mUserIds.remove(userId); 248 } 249 } else if (Intent.ACTION_PROFILE_AVAILABLE.equals(action) 250 || Intent.ACTION_PROFILE_ADDED.equals(action)) { 251 synchronized (mUserIds) { 252 if (!mUserIds.contains(userId)) { 253 mUserIds.add(userId); 254 } 255 } 256 synchronized (mUserIdToLabelMap) { 257 if (!mUserIdToLabelMap.containsKey(userId)) { 258 mUserIdToLabelMap.put(userId, getProfileLabel(userId)); 259 } 260 } 261 synchronized (mUserIdToBadgeMap) { 262 if (!mUserIdToBadgeMap.containsKey(userId)) { 263 mUserIdToBadgeMap.put(userId, getProfileBadge(userId)); 264 } 265 } 266 synchronized (mCanFrowardToProfileIdMap) { 267 if (!mCanFrowardToProfileIdMap.containsKey(userId)) { 268 if (userId.getIdentifier() == ActivityManager.getCurrentUser() 269 || isCrossProfileContentSharingStrategyDelegatedFromParent( 270 UserHandle.of(userId.getIdentifier())) 271 || CrossProfileUtils.getCrossProfileResolveInfo(mCurrentUser, 272 mContext.getPackageManager(), mCurrentStateIntent, mContext, 273 mConfigStore.isPrivateSpaceInDocsUIEnabled()) != null) { 274 mCanFrowardToProfileIdMap.put(userId, true); 275 } else { 276 mCanFrowardToProfileIdMap.put(userId, false); 277 } 278 279 } 280 } 281 } else { 282 Log.e(TAG, "Unexpected action received: " + action); 283 } 284 } 285 286 @Override setCurrentStateIntent(Intent intent)287 public void setCurrentStateIntent(Intent intent) { 288 mCurrentStateIntent = intent; 289 } 290 291 @Override areHiddenInQuietModeProfilesPresent()292 public boolean areHiddenInQuietModeProfilesPresent() { 293 if (!SdkLevel.isAtLeastV()) { 294 return false; 295 } 296 297 for (UserId userId : getUserIds()) { 298 if (mUserManager 299 .getUserProperties(UserHandle.of(userId.getIdentifier())) 300 .getShowInQuietMode() 301 == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { 302 return true; 303 } 304 } 305 return false; 306 } 307 getUserIdsInternal()308 private List<UserId> getUserIdsInternal() { 309 final List<UserId> result = new ArrayList<>(); 310 311 if (!mIsDeviceSupported) { 312 result.add(mCurrentUser); 313 return result; 314 } 315 316 if (mUserManager == null) { 317 Log.e(TAG, "cannot obtain user manager"); 318 result.add(mCurrentUser); 319 return result; 320 } 321 322 final List<UserHandle> userProfiles = mUserManager.getUserProfiles(); 323 if (userProfiles.size() < 2) { 324 result.add(mCurrentUser); 325 return result; 326 } 327 328 if (SdkLevel.isAtLeastV()) { 329 getUserIdsInternalPostV(userProfiles, result); 330 } else { 331 getUserIdsInternalPreV(userProfiles, result); 332 } 333 return result; 334 } 335 336 @SuppressLint("NewApi") getUserIdsInternalPostV(List<UserHandle> userProfiles, List<UserId> result)337 private void getUserIdsInternalPostV(List<UserHandle> userProfiles, List<UserId> result) { 338 for (UserHandle userHandle : userProfiles) { 339 if (userHandle.getIdentifier() == ActivityManager.getCurrentUser()) { 340 result.add(UserId.of(userHandle)); 341 } else { 342 // Out of all the profiles returned by user manager the profiles that are 343 // returned should satisfy both the following conditions: 344 // 1. It has user property SHOW_IN_SHARING_SURFACES_SEPARATE 345 // 2. Quite mode is not enabled, if it is enabled then the profile's user 346 // property is not SHOW_IN_QUIET_MODE_HIDDEN 347 if (isProfileAllowed(userHandle)) { 348 result.add(UserId.of(userHandle)); 349 } 350 } 351 } 352 if (result.isEmpty()) { 353 result.add(mCurrentUser); 354 } 355 } 356 357 @SuppressLint("NewApi") isProfileAllowed(UserHandle userHandle)358 private boolean isProfileAllowed(UserHandle userHandle) { 359 final UserProperties userProperties = 360 mUserManager.getUserProperties(userHandle); 361 if (userProperties.getShowInSharingSurfaces() 362 == UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) { 363 return !UserId.of(userHandle).isQuietModeEnabled(mContext) 364 || userProperties.getShowInQuietMode() 365 != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN; 366 } 367 return false; 368 } 369 getUserIdsInternalPreV(List<UserHandle> userProfiles, List<UserId> result)370 private void getUserIdsInternalPreV(List<UserHandle> userProfiles, List<UserId> result) { 371 result.add(mCurrentUser); 372 UserId systemUser = null; 373 UserId managedUser = null; 374 for (UserHandle userHandle : userProfiles) { 375 if (userHandle.isSystem()) { 376 systemUser = UserId.of(userHandle); 377 } else if (mUserManager.isManagedProfile(userHandle.getIdentifier())) { 378 managedUser = UserId.of(userHandle); 379 } 380 } 381 if (mCurrentUser.isSystem() && managedUser != null) { 382 result.add(managedUser); 383 } else if (mCurrentUser.isManagedProfile(mUserManager) && systemUser != null) { 384 result.add(0, systemUser); 385 } else { 386 if (DEBUG) { 387 Log.w(TAG, "The current user " + UserId.CURRENT_USER 388 + " is neither system nor managed user. has system user: " 389 + (systemUser != null)); 390 } 391 } 392 } 393 getUserIdToLabelMapInternal()394 private void getUserIdToLabelMapInternal() { 395 if (SdkLevel.isAtLeastV()) { 396 getUserIdToLabelMapInternalPostV(); 397 } else { 398 getUserIdToLabelMapInternalPreV(); 399 } 400 } 401 402 @SuppressLint("NewApi") getUserIdToLabelMapInternalPostV()403 private void getUserIdToLabelMapInternalPostV() { 404 if (mUserManager == null) { 405 Log.e(TAG, "cannot obtain user manager"); 406 return; 407 } 408 List<UserId> userIds = getUserIds(); 409 for (UserId userId : userIds) { 410 synchronized (mUserIdToLabelMap) { 411 mUserIdToLabelMap.put(userId, getProfileLabel(userId)); 412 } 413 } 414 } 415 getUserIdToLabelMapInternalPreV()416 private void getUserIdToLabelMapInternalPreV() { 417 if (mUserManager == null) { 418 Log.e(TAG, "cannot obtain user manager"); 419 return; 420 } 421 List<UserId> userIds = getUserIds(); 422 for (UserId userId : userIds) { 423 if (mUserManager.isManagedProfile(userId.getIdentifier())) { 424 synchronized (mUserIdToLabelMap) { 425 mUserIdToLabelMap.put(userId, 426 getEnterpriseString(WORK_TAB, R.string.work_tab)); 427 } 428 } else { 429 synchronized (mUserIdToLabelMap) { 430 mUserIdToLabelMap.put(userId, 431 getEnterpriseString(PERSONAL_TAB, R.string.personal_tab)); 432 } 433 } 434 } 435 } 436 437 @SuppressLint("NewApi") getProfileLabel(UserId userId)438 private String getProfileLabel(UserId userId) { 439 if (userId.getIdentifier() == ActivityManager.getCurrentUser()) { 440 return getEnterpriseString(PERSONAL_TAB, R.string.personal_tab); 441 } 442 try { 443 Context userContext = mContext.createContextAsUser( 444 UserHandle.of(userId.getIdentifier()), 0 /* flags */); 445 UserManager userManagerAsUser = userContext.getSystemService(UserManager.class); 446 if (userManagerAsUser == null) { 447 Log.e(TAG, "cannot obtain user manager"); 448 return null; 449 } 450 return userManagerAsUser.getProfileLabel(); 451 } catch (Exception e) { 452 Log.e(TAG, "Exception occurred while trying to get profile label:\n" + e); 453 return null; 454 } 455 } 456 getEnterpriseString(String updatableStringId, int defaultStringId)457 private String getEnterpriseString(String updatableStringId, int defaultStringId) { 458 if (SdkLevel.isAtLeastT()) { 459 return getUpdatableEnterpriseString(updatableStringId, defaultStringId); 460 } else { 461 return mContext.getString(defaultStringId); 462 } 463 } 464 465 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getUpdatableEnterpriseString(String updatableStringId, int defaultStringId)466 private String getUpdatableEnterpriseString(String updatableStringId, int defaultStringId) { 467 DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 468 if (Objects.equal(dpm, null)) { 469 Log.e(TAG, "can not get device policy manager"); 470 return mContext.getString(defaultStringId); 471 } 472 return dpm.getResources().getString( 473 updatableStringId, 474 () -> mContext.getString(defaultStringId)); 475 } 476 getUserIdToBadgeMapInternal()477 private void getUserIdToBadgeMapInternal() { 478 if (SdkLevel.isAtLeastV()) { 479 getUserIdToBadgeMapInternalPostV(); 480 } else { 481 getUserIdToBadgeMapInternalPreV(); 482 } 483 } 484 485 @SuppressLint("NewApi") getUserIdToBadgeMapInternalPostV()486 private void getUserIdToBadgeMapInternalPostV() { 487 if (mUserManager == null) { 488 Log.e(TAG, "cannot obtain user manager"); 489 return; 490 } 491 List<UserId> userIds = getUserIds(); 492 for (UserId userId : userIds) { 493 synchronized (mUserIdToBadgeMap) { 494 mUserIdToBadgeMap.put(userId, getProfileBadge(userId)); 495 } 496 } 497 } 498 getUserIdToBadgeMapInternalPreV()499 private void getUserIdToBadgeMapInternalPreV() { 500 if (!SdkLevel.isAtLeastR()) return; 501 if (mUserManager == null) { 502 Log.e(TAG, "cannot obtain user manager"); 503 return; 504 } 505 List<UserId> userIds = getUserIds(); 506 for (UserId userId : userIds) { 507 if (mUserManager.isManagedProfile(userId.getIdentifier())) { 508 synchronized (mUserIdToBadgeMap) { 509 mUserIdToBadgeMap.put(userId, 510 SdkLevel.isAtLeastT() ? getWorkProfileBadge() 511 : mContext.getDrawable(R.drawable.ic_briefcase)); 512 } 513 } 514 } 515 } 516 517 @SuppressLint("NewApi") getProfileBadge(UserId userId)518 private Drawable getProfileBadge(UserId userId) { 519 if (userId.getIdentifier() == ActivityManager.getCurrentUser()) { 520 return null; 521 } 522 try { 523 Context userContext = mContext.createContextAsUser( 524 UserHandle.of(userId.getIdentifier()), 0 /* flags */); 525 UserManager userManagerAsUser = userContext.getSystemService(UserManager.class); 526 if (userManagerAsUser == null) { 527 Log.e(TAG, "cannot obtain user manager"); 528 return null; 529 } 530 return userManagerAsUser.getUserBadge(); 531 } catch (Exception e) { 532 Log.e(TAG, "Exception occurred while trying to get profile badge:\n" + e); 533 return null; 534 } 535 } 536 537 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getWorkProfileBadge()538 private Drawable getWorkProfileBadge() { 539 DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 540 Drawable drawable = dpm.getResources().getDrawable(WORK_PROFILE_ICON, SOLID_COLORED, 541 () -> 542 mContext.getDrawable(R.drawable.ic_briefcase)); 543 return drawable; 544 } 545 getCanForwardToProfileIdMapInternal(Intent intent)546 private void getCanForwardToProfileIdMapInternal(Intent intent) { 547 // Versions less than V will not have the user properties required to determine whether 548 // cross profile check is delegated from parent or not 549 if (!SdkLevel.isAtLeastV()) { 550 getCanForwardToProfileIdMapPreV(intent); 551 return; 552 } 553 if (mUserManager == null) { 554 Log.e(TAG, "can not get user manager"); 555 return; 556 } 557 558 List<UserId> parentOrDelegatedFromParent = new ArrayList<>(); 559 List<UserId> canForwardToProfileIds = new ArrayList<>(); 560 List<UserId> noDelegation = new ArrayList<>(); 561 562 List<UserId> userIds = getUserIds(); 563 for (UserId userId : userIds) { 564 final UserHandle userHandle = UserHandle.of(userId.getIdentifier()); 565 // Parent (personal) profile and all the child profiles that delegate cross profile 566 // content sharing check to parent can share among each other 567 if (userId.getIdentifier() == ActivityManager.getCurrentUser() 568 || isCrossProfileContentSharingStrategyDelegatedFromParent(userHandle)) { 569 parentOrDelegatedFromParent.add(userId); 570 } else { 571 noDelegation.add(userId); 572 } 573 } 574 575 if (noDelegation.size() > 1) { 576 Log.e(TAG, "There cannot be more than one profile delegating cross profile " 577 + "content sharing check from self."); 578 } 579 580 /* 581 * Cross profile resolve info need to be checked in the following 2 cases: 582 * 1. current user is either parent or delegates check to parent and the target user 583 * does not delegate to parent 584 * 2. current user does not delegate check to the parent and the target user is the 585 * parent profile 586 */ 587 UserId needToCheck = null; 588 if (parentOrDelegatedFromParent.contains(mCurrentUser) 589 && !noDelegation.isEmpty()) { 590 needToCheck = noDelegation.get(0); 591 } else if (mCurrentUser.getIdentifier() != ActivityManager.getCurrentUser()) { 592 final UserHandle parentProfile = mUserManager.getProfileParent( 593 UserHandle.of(mCurrentUser.getIdentifier())); 594 needToCheck = UserId.of(parentProfile); 595 } 596 597 if (needToCheck != null && CrossProfileUtils.getCrossProfileResolveInfo(mCurrentUser, 598 mContext.getPackageManager(), intent, mContext, 599 mConfigStore.isPrivateSpaceInDocsUIEnabled()) != null) { 600 if (parentOrDelegatedFromParent.contains(needToCheck)) { 601 canForwardToProfileIds.addAll(parentOrDelegatedFromParent); 602 } else { 603 canForwardToProfileIds.add(needToCheck); 604 } 605 } 606 607 if (parentOrDelegatedFromParent.contains(mCurrentUser)) { 608 canForwardToProfileIds.addAll(parentOrDelegatedFromParent); 609 } 610 611 for (UserId userId : userIds) { 612 synchronized (mCanFrowardToProfileIdMap) { 613 if (userId.equals(mCurrentUser)) { 614 mCanFrowardToProfileIdMap.put(userId, true); 615 continue; 616 } 617 mCanFrowardToProfileIdMap.put(userId, canForwardToProfileIds.contains(userId)); 618 } 619 } 620 } 621 622 @SuppressLint("NewApi") isCrossProfileContentSharingStrategyDelegatedFromParent( UserHandle userHandle)623 private boolean isCrossProfileContentSharingStrategyDelegatedFromParent( 624 UserHandle userHandle) { 625 if (mUserManager == null) { 626 Log.e(TAG, "can not obtain user manager"); 627 return false; 628 } 629 UserProperties userProperties = mUserManager.getUserProperties(userHandle); 630 if (java.util.Objects.equals(userProperties, null)) { 631 Log.e(TAG, "can not obtain user properties"); 632 return false; 633 } 634 635 return userProperties.getCrossProfileContentSharingStrategy() 636 == UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT; 637 } 638 getCanForwardToProfileIdMapPreV(Intent intent)639 private void getCanForwardToProfileIdMapPreV(Intent intent) { 640 // There only two profiles pre V 641 List<UserId> userIds = getUserIds(); 642 for (UserId userId : userIds) { 643 synchronized (mCanFrowardToProfileIdMap) { 644 if (mCurrentUser.equals(userId)) { 645 mCanFrowardToProfileIdMap.put(userId, true); 646 } else { 647 mCanFrowardToProfileIdMap.put(userId, 648 CrossProfileUtils.getCrossProfileResolveInfo( 649 mCurrentUser, mContext.getPackageManager(), intent, 650 mContext, mConfigStore.isPrivateSpaceInDocsUIEnabled()) 651 != null); 652 } 653 } 654 } 655 } 656 isDeviceSupported(Context context)657 private static boolean isDeviceSupported(Context context) { 658 // The feature requires Android R DocumentsContract APIs and INTERACT_ACROSS_USERS_FULL 659 // permission. 660 return VersionUtils.isAtLeastR() 661 && context.checkSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS) 662 == PackageManager.PERMISSION_GRANTED; 663 } 664 } 665 } 666