• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.car.settings.applications;
18 
19 import static android.Manifest.permission.MANAGE_OWN_CALLS;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 
29 import androidx.annotation.NonNull;
30 import androidx.annotation.VisibleForTesting;
31 
32 import com.android.car.settings.common.PermissionUtil;
33 import com.android.settingslib.utils.ThreadUtils;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Class used to count the number of non-system apps. Largely derived from
40  * {@link com.android.settings.applications.InstalledAppCounter}.
41  */
42 public class InstalledAppCountItemManager {
43 
44     private final List<InstalledAppCountListener> mInstalledAppCountListeners;
45     private final PackageManager mPackageManager;
46     private final boolean mIsVisibleBackgroundUser;
47 
InstalledAppCountItemManager(Context context)48     public InstalledAppCountItemManager(Context context) {
49         mInstalledAppCountListeners = new ArrayList<>();
50         mPackageManager = context.getPackageManager();
51         UserManager userManager = context.getSystemService(UserManager.class);
52         mIsVisibleBackgroundUser = !userManager.isUserForeground() && userManager.isUserVisible()
53                 && !userManager.isProfile();
54     }
55 
56     /**
57      * Registers a listener that will be notified once the data is loaded.
58      */
addListener(@onNull InstalledAppCountListener listener)59     public void addListener(@NonNull InstalledAppCountListener listener) {
60         mInstalledAppCountListeners.add(listener);
61     }
62 
63     /**
64      * Starts fetching installed apps and counting the non-system apps
65      */
startLoading()66     public void startLoading() {
67         ThreadUtils.postOnBackgroundThread(() -> {
68             List<ApplicationInfo> appList = mPackageManager
69                     .getInstalledApplications(PackageManager.MATCH_DISABLED_COMPONENTS
70                             | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS);
71 
72             int appCount = 0;
73             for (ApplicationInfo applicationInfo : appList) {
74                 if (shouldCountApp(applicationInfo)) {
75                     appCount++;
76                 }
77             }
78             int finalAppCount = appCount;
79             for (InstalledAppCountListener listener : mInstalledAppCountListeners) {
80                 ThreadUtils.postOnMainThread(() -> listener
81                         .onInstalledAppCountLoaded(finalAppCount));
82             }
83         });
84     }
85 
86     @VisibleForTesting
shouldCountApp(ApplicationInfo applicationInfo)87     boolean shouldCountApp(ApplicationInfo applicationInfo) {
88         // MUMD passenger users can't use telephony applications so they don't interrupt the
89         // driver's calls
90         if (mIsVisibleBackgroundUser && PermissionUtil.doesPackageRequestPermission(
91                 applicationInfo.packageName, mPackageManager, MANAGE_OWN_CALLS)) {
92             return false;
93         }
94         if ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
95             return true;
96         }
97         if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
98             return true;
99         }
100         int userId = UserHandle.getUserId(applicationInfo.uid);
101         Intent launchIntent = new Intent(Intent.ACTION_MAIN, null)
102                 .addCategory(Intent.CATEGORY_LAUNCHER)
103                 .setPackage(applicationInfo.packageName);
104         List<ResolveInfo> intents = mPackageManager.queryIntentActivitiesAsUser(
105                 launchIntent,
106                 PackageManager.MATCH_DISABLED_COMPONENTS
107                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
108                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
109                 userId);
110         return intents != null && !intents.isEmpty();
111     }
112 
113     /**
114      * Callback that is called once the number of installed applications is counted.
115      */
116     public interface InstalledAppCountListener {
117         /**
118          * Called when the apps are successfully loaded from PackageManager and non-system apps are
119          * counted.
120          */
onInstalledAppCountLoaded(int appCount)121         void onInstalledAppCountLoaded(int appCount);
122     }
123 }
124