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