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 android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ResolveInfo; 24 import android.os.UserHandle; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.VisibleForTesting; 28 29 import com.android.settingslib.utils.ThreadUtils; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Class used to count the number of non-system apps. Largely derived from 36 * {@link com.android.settings.applications.InstalledAppCounter}. 37 */ 38 public class InstalledAppCountItemManager { 39 40 private Context mContext; 41 private final List<InstalledAppCountListener> mInstalledAppCountListeners; 42 InstalledAppCountItemManager(Context context)43 public InstalledAppCountItemManager(Context context) { 44 mContext = context; 45 mInstalledAppCountListeners = new ArrayList<>(); 46 } 47 48 /** 49 * Registers a listener that will be notified once the data is loaded. 50 */ addListener(@onNull InstalledAppCountListener listener)51 public void addListener(@NonNull InstalledAppCountListener listener) { 52 mInstalledAppCountListeners.add(listener); 53 } 54 55 /** 56 * Starts fetching installed apps and counting the non-system apps 57 */ startLoading()58 public void startLoading() { 59 ThreadUtils.postOnBackgroundThread(() -> { 60 List<ApplicationInfo> appList = mContext.getPackageManager() 61 .getInstalledApplications(PackageManager.MATCH_DISABLED_COMPONENTS 62 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS); 63 64 int appCount = 0; 65 for (ApplicationInfo applicationInfo : appList) { 66 if (shouldCountApp(applicationInfo)) { 67 appCount++; 68 } 69 } 70 int finalAppCount = appCount; 71 for (InstalledAppCountListener listener : mInstalledAppCountListeners) { 72 ThreadUtils.postOnMainThread(() -> listener 73 .onInstalledAppCountLoaded(finalAppCount)); 74 } 75 }); 76 } 77 78 @VisibleForTesting shouldCountApp(ApplicationInfo applicationInfo)79 boolean shouldCountApp(ApplicationInfo applicationInfo) { 80 if ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 81 return true; 82 } 83 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { 84 return true; 85 } 86 int userId = UserHandle.getUserId(applicationInfo.uid); 87 Intent launchIntent = new Intent(Intent.ACTION_MAIN, null) 88 .addCategory(Intent.CATEGORY_LAUNCHER) 89 .setPackage(applicationInfo.packageName); 90 List<ResolveInfo> intents = mContext.getPackageManager().queryIntentActivitiesAsUser( 91 launchIntent, 92 PackageManager.MATCH_DISABLED_COMPONENTS 93 | PackageManager.MATCH_DIRECT_BOOT_AWARE 94 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 95 userId); 96 return intents != null && !intents.isEmpty(); 97 } 98 99 /** 100 * Callback that is called once the number of installed applications is counted. 101 */ 102 public interface InstalledAppCountListener { 103 /** 104 * Called when the apps are successfully loaded from PackageManager and non-system apps are 105 * counted. 106 */ onInstalledAppCountLoaded(int appCount)107 void onInstalledAppCountLoaded(int appCount); 108 } 109 } 110