1 /*
2  * Copyright (C) 2015 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 android.content.pm;
18 
19 import android.Manifest;
20 import android.app.AppGlobals;
21 import android.content.Intent;
22 import android.os.RemoteException;
23 import android.os.UserHandle;
24 import android.util.ArraySet;
25 import android.view.inputmethod.InputMethod;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 
32 /**
33  * Helper class for querying installed applications using multiple criteria.
34  *
35  * @hide
36  */
37 public class AppsQueryHelper {
38 
39     /**
40      * Return apps without launcher icon
41      */
42     public static int GET_NON_LAUNCHABLE_APPS = 1;
43 
44     /**
45      * Return apps with {@link Manifest.permission#INTERACT_ACROSS_USERS} permission
46      */
47     public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;
48 
49     /**
50      * Return all input methods available for the current user.
51      */
52     public static int GET_IMES = 1 << 2;
53 
54     /**
55      * Return all apps that are flagged as required for the system user.
56      */
57     public static int GET_REQUIRED_FOR_SYSTEM_USER = 1 << 3;
58 
59     private final IPackageManager mPackageManager;
60     private List<ApplicationInfo> mAllApps;
61 
AppsQueryHelper(IPackageManager packageManager)62     public AppsQueryHelper(IPackageManager packageManager) {
63         mPackageManager = packageManager;
64     }
65 
AppsQueryHelper()66     public AppsQueryHelper() {
67         this(AppGlobals.getPackageManager());
68     }
69 
70     /**
71      * Return a List of all packages that satisfy a specified criteria.
72      * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
73      * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_IMES}.
74      * @param systemAppsOnly if true, only system apps will be returned
75      * @param user user, whose apps are queried
76      */
queryApps(int flags, boolean systemAppsOnly, UserHandle user)77     public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
78         boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
79         boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
80         boolean imes = (flags & GET_IMES) > 0;
81         boolean requiredForSystemUser = (flags & GET_REQUIRED_FOR_SYSTEM_USER) > 0;
82         if (mAllApps == null) {
83             mAllApps = getAllApps(user.getIdentifier());
84         }
85 
86         List<String> result = new ArrayList<>();
87         if (flags == 0) {
88             final int allAppsSize = mAllApps.size();
89             for (int i = 0; i < allAppsSize; i++) {
90                 final ApplicationInfo appInfo = mAllApps.get(i);
91                 if (systemAppsOnly && !appInfo.isSystemApp()) {
92                     continue;
93                 }
94                 result.add(appInfo.packageName);
95             }
96             return result;
97         }
98 
99         if (nonLaunchableApps) {
100             Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
101             final List<ResolveInfo> resolveInfos = queryIntentActivitiesAsUser(intent,
102                     user.getIdentifier());
103 
104             ArraySet<String> appsWithLaunchers = new ArraySet<>();
105             final int resolveInfosSize = resolveInfos.size();
106             for (int i = 0; i < resolveInfosSize; i++) {
107                 appsWithLaunchers.add(resolveInfos.get(i).activityInfo.packageName);
108             }
109             final int allAppsSize = mAllApps.size();
110             for (int i = 0; i < allAppsSize; i++) {
111                 final ApplicationInfo appInfo = mAllApps.get(i);
112                 if (systemAppsOnly && !appInfo.isSystemApp()) {
113                     continue;
114                 }
115                 final String packageName = appInfo.packageName;
116                 if (!appsWithLaunchers.contains(packageName)) {
117                     result.add(packageName);
118                 }
119             }
120         }
121         if (interactAcrossUsers) {
122             final List<PackageInfo> packagesHoldingPermissions = getPackagesHoldingPermission(
123                     Manifest.permission.INTERACT_ACROSS_USERS, user.getIdentifier());
124             final int packagesHoldingPermissionsSize = packagesHoldingPermissions.size();
125             for (int i = 0; i < packagesHoldingPermissionsSize; i++) {
126                 PackageInfo packageInfo = packagesHoldingPermissions.get(i);
127                 if (systemAppsOnly && !packageInfo.applicationInfo.isSystemApp()) {
128                     continue;
129                 }
130                 if (!result.contains(packageInfo.packageName)) {
131                     result.add(packageInfo.packageName);
132                 }
133             }
134         }
135 
136         if (imes) {
137             final List<ResolveInfo> resolveInfos = queryIntentServicesAsUser(
138                     new Intent(InputMethod.SERVICE_INTERFACE), user.getIdentifier());
139             final int resolveInfosSize = resolveInfos.size();
140 
141             for (int i = 0; i < resolveInfosSize; i++) {
142                 ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
143                 if (systemAppsOnly && !serviceInfo.applicationInfo.isSystemApp()) {
144                     continue;
145                 }
146                 if (!result.contains(serviceInfo.packageName)) {
147                     result.add(serviceInfo.packageName);
148                 }
149             }
150         }
151 
152         if (requiredForSystemUser) {
153             final int allAppsSize = mAllApps.size();
154             for (int i = 0; i < allAppsSize; i++) {
155                 final ApplicationInfo appInfo = mAllApps.get(i);
156                 if (systemAppsOnly && !appInfo.isSystemApp()) {
157                     continue;
158                 }
159                 if (appInfo.isRequiredForSystemUser()) {
160                     result.add(appInfo.packageName);
161                 }
162             }
163         }
164         return result;
165     }
166 
167     @VisibleForTesting
168     @SuppressWarnings("unchecked")
getAllApps(int userId)169     protected List<ApplicationInfo> getAllApps(int userId) {
170         try {
171             return mPackageManager.getInstalledApplications(
172                     PackageManager.MATCH_UNINSTALLED_PACKAGES
173                             | PackageManager.MATCH_DISABLED_COMPONENTS, userId).getList();
174         } catch (RemoteException e) {
175             throw e.rethrowFromSystemServer();
176         }
177     }
178 
179     @VisibleForTesting
queryIntentActivitiesAsUser(Intent intent, int userId)180     protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
181         try {
182             return mPackageManager.queryIntentActivities(intent, null,
183                     PackageManager.MATCH_DISABLED_COMPONENTS
184                             | PackageManager.MATCH_UNINSTALLED_PACKAGES
185                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
186                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
187                     userId).getList();
188         } catch (RemoteException e) {
189             throw e.rethrowFromSystemServer();
190         }
191     }
192 
193     @VisibleForTesting
queryIntentServicesAsUser(Intent intent, int userId)194     protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
195         try {
196             return mPackageManager.queryIntentServices(intent, null,
197                     PackageManager.GET_META_DATA
198                             | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
199                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
200                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId)
201                     .getList();
202         } catch (RemoteException e) {
203             throw e.rethrowFromSystemServer();
204         }
205     }
206 
207     @VisibleForTesting
208     @SuppressWarnings("unchecked")
getPackagesHoldingPermission(String perm, int userId)209     protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
210         try {
211             return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
212                     userId).getList();
213         } catch (RemoteException e) {
214             throw e.rethrowFromSystemServer();
215         }
216     }
217 }
218