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