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.systemui;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.ResolveInfo;
24 
25 import com.android.systemui.dagger.SysUISingleton;
26 
27 import java.util.List;
28 
29 import javax.inject.Inject;
30 
31 /**
32  * Contains useful methods for querying properties of an Activity Intent.
33  */
34 @SysUISingleton
35 public class ActivityIntentHelper {
36 
37     private final Context mContext;
38 
39     @Inject
ActivityIntentHelper(Context context)40     public ActivityIntentHelper(Context context) {
41         // TODO: inject a package manager, not a context.
42         mContext = context;
43     }
44 
45     /**
46      * Determines if sending the given intent would result in starting an Intent resolver activity,
47      * instead of resolving to a specific component.
48      *
49      * @param intent the intent
50      * @param currentUserId the id for the user to resolve as
51      * @return true if the intent would launch a resolver activity
52      */
wouldLaunchResolverActivity(Intent intent, int currentUserId)53     public boolean wouldLaunchResolverActivity(Intent intent, int currentUserId) {
54         ActivityInfo targetActivityInfo = getTargetActivityInfo(intent, currentUserId,
55                 false /* onlyDirectBootAware */);
56         return targetActivityInfo == null;
57     }
58 
59     /**
60      * Returns info about the target Activity of a given intent, or null if the intent does not
61      * resolve to a specific component meeting the requirements.
62      *
63      * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must
64      *         be direct boot aware when in direct boot mode if false, all packages are considered
65      *         a match even if they are not aware.
66      * @return the target activity info of the intent it resolves to a specific package or
67      *         {@code null} if it resolved to the resolver activity
68      */
getTargetActivityInfo(Intent intent, int currentUserId, boolean onlyDirectBootAware)69     public ActivityInfo getTargetActivityInfo(Intent intent, int currentUserId,
70             boolean onlyDirectBootAware) {
71         PackageManager packageManager = mContext.getPackageManager();
72         int flags = PackageManager.MATCH_DEFAULT_ONLY;
73         if (!onlyDirectBootAware) {
74             flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
75                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
76         }
77         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
78                 intent, flags, currentUserId);
79         if (appList.size() == 0) {
80             return null;
81         }
82         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
83                 flags | PackageManager.GET_META_DATA, currentUserId);
84         if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) {
85             return null;
86         } else {
87             return resolved.activityInfo;
88         }
89     }
90 
91     /**
92      * Determines if the given intent resolves to an Activity which is allowed to appear above
93      * the lock screen.
94      *
95      * @param intent the intent to resolve
96      * @return true if the launched Activity would appear above the lock screen
97      */
wouldShowOverLockscreen(Intent intent, int currentUserId)98     public boolean wouldShowOverLockscreen(Intent intent, int currentUserId) {
99         ActivityInfo targetActivityInfo = getTargetActivityInfo(intent,
100                 currentUserId, false /* onlyDirectBootAware */);
101         return targetActivityInfo != null
102                 && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED
103                 | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0;
104     }
105 
106     /**
107      * Determines if sending the given intent would result in starting an Intent resolver activity,
108      * instead of resolving to a specific component.
109      *
110      * @param resolved the resolveInfo for the intent as returned by resolveActivityAsUser
111      * @param appList a list of resolveInfo as returned by queryIntentActivitiesAsUser
112      * @return true if the intent would launch a resolver activity
113      */
wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList)114     public boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
115         // If the list contains the above resolved activity, then it can't be
116         // ResolverActivity itself.
117         for (int i = 0; i < appList.size(); i++) {
118             ResolveInfo tmp = appList.get(i);
119             if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
120                     && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
121                 return false;
122             }
123         }
124         return true;
125     }
126 }
127