1 /*
2  * Copyright (C) 2020 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.util;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.PackageManager;
23 import android.content.pm.ResolveInfo;
24 import android.content.pm.UserProperties;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.util.Log;
28 
29 import androidx.annotation.Nullable;
30 
31 import com.android.documentsui.base.UserId;
32 import com.android.modules.utils.build.SdkLevel;
33 
34 /**
35  * A utility class for cross-profile usage.
36  */
37 public class CrossProfileUtils {
38 
39     private static final String TAG = "CrossProfileUtils";
40     private static final String PROFILE_TARGET_ACTIVITY =
41             "com.android.internal.app.IntentForwarderActivity";
42 
CrossProfileUtils()43     private CrossProfileUtils() {
44     }
45 
46     /**
47      * Returns whether this resolution represents the intent forwarder activity.
48      */
isCrossProfileIntentForwarderActivity(ResolveInfo info)49     public static boolean isCrossProfileIntentForwarderActivity(ResolveInfo info) {
50         if (VersionUtils.isAtLeastR()) {
51             return info.isCrossProfileIntentForwarderActivity();
52         }
53         if (info.activityInfo != null) {
54             return PROFILE_TARGET_ACTIVITY.equals(info.activityInfo.targetActivity);
55         }
56         return false;
57     }
58 
59     /**
60      * Returns the {@link ResolveInfo} if this intent is a cross-profile intent or {@code null}
61      * otherwise.
62      */
63     @Nullable
getCrossProfileResolveInfo(UserId currentUser, PackageManager packageManager, Intent intent, Context context, boolean isPrivateSpaceEnabled)64     public static ResolveInfo getCrossProfileResolveInfo(UserId currentUser,
65             PackageManager packageManager, Intent intent, Context context,
66             boolean isPrivateSpaceEnabled) {
67         if (isPrivateSpaceEnabled && SdkLevel.isAtLeastV()) {
68             return getCrossProfileResolveInfoPostV(currentUser, packageManager,
69                     intent, context);
70         }
71         return getCrossProfileResolveInfoPreV(packageManager, intent);
72     }
73 
74     @Nullable
75     @TargetApi(35)
getCrossProfileResolveInfoPostV( UserId currentUser, PackageManager packageManager, Intent intent, Context context)76     private static ResolveInfo getCrossProfileResolveInfoPostV(
77             UserId currentUser, PackageManager packageManager,
78             Intent intent, Context context) {
79         UserManager userManager = context.getSystemService(UserManager.class);
80         UserHandle queringUser = UserHandle.of(currentUser.getIdentifier());
81         if (userManager == null) {
82             Log.e(TAG, "cannot obtain user manager");
83             return null;
84         }
85 
86         UserProperties userProperties = userManager.getUserProperties(queringUser);
87         if (userProperties == null) {
88             Log.e(TAG, "cannot obtain user properties");
89             return null;
90         }
91 
92         if (userProperties.getCrossProfileContentSharingStrategy()
93                 == UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) {
94             queringUser = userManager.getProfileParent(queringUser);
95         }
96 
97         for (ResolveInfo info : packageManager.queryIntentActivitiesAsUser(intent,
98                 PackageManager.MATCH_DEFAULT_ONLY, queringUser)) {
99             if (isCrossProfileIntentForwarderActivity(info)) {
100                 return info;
101             }
102         }
103         return null;
104     }
105 
106     @Nullable
getCrossProfileResolveInfoPreV( PackageManager packageManager, Intent intent)107     private static ResolveInfo getCrossProfileResolveInfoPreV(
108             PackageManager packageManager,
109             Intent intent) {
110         for (ResolveInfo info : packageManager.queryIntentActivities(intent,
111                 PackageManager.MATCH_DEFAULT_ONLY)) {
112             if (isCrossProfileIntentForwarderActivity(info)) {
113                 return info;
114             }
115         }
116         return null;
117     }
118 }
119