1 /* 2 * Copyright (C) 2008 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.launcher3; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.LauncherActivityInfo; 23 import android.os.Process; 24 import android.os.UserHandle; 25 import android.util.Log; 26 27 import com.android.launcher3.compat.LauncherAppsCompat; 28 import com.android.launcher3.compat.PackageInstallerCompat; 29 import com.android.launcher3.icons.IconCache; 30 import com.android.launcher3.util.FlagOp; 31 import com.android.launcher3.util.ItemInfoMatcher; 32 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.List; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 40 41 /** 42 * Stores the list of all applications for the all apps view. 43 */ 44 public class AllAppsList { 45 private static final String TAG = "AllAppsList"; 46 47 public static final int DEFAULT_APPLICATIONS_NUMBER = 42; 48 49 /** The list off all apps. */ 50 public final ArrayList<AppInfo> data = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER); 51 /** The list of apps that have been added since the last notify() call. */ 52 public ArrayList<AppInfo> added = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER); 53 /** The list of apps that have been removed since the last notify() call. */ 54 public ArrayList<AppInfo> removed = new ArrayList<>(); 55 /** The list of apps that have been modified since the last notify() call. */ 56 public ArrayList<AppInfo> modified = new ArrayList<>(); 57 58 private IconCache mIconCache; 59 60 private AppFilter mAppFilter; 61 62 /** 63 * Boring constructor. 64 */ AllAppsList(IconCache iconCache, AppFilter appFilter)65 public AllAppsList(IconCache iconCache, AppFilter appFilter) { 66 mIconCache = iconCache; 67 mAppFilter = appFilter; 68 } 69 70 /** 71 * Add the supplied ApplicationInfo objects to the list, and enqueue it into the 72 * list to broadcast when notify() is called. 73 * 74 * If the app is already in the list, doesn't add it. 75 */ add(AppInfo info, LauncherActivityInfo activityInfo)76 public void add(AppInfo info, LauncherActivityInfo activityInfo) { 77 if (!mAppFilter.shouldShowApp(info.componentName)) { 78 return; 79 } 80 if (findAppInfo(info.componentName, info.user) != null) { 81 return; 82 } 83 mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */); 84 85 data.add(info); 86 added.add(info); 87 } 88 addPromiseApp(Context context, PackageInstallerCompat.PackageInstallInfo installInfo)89 public void addPromiseApp(Context context, 90 PackageInstallerCompat.PackageInstallInfo installInfo) { 91 ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context) 92 .getApplicationInfo(installInfo.packageName, 0, Process.myUserHandle()); 93 // only if not yet installed 94 if (applicationInfo == null) { 95 PromiseAppInfo info = new PromiseAppInfo(installInfo); 96 mIconCache.getTitleAndIcon(info, info.usingLowResIcon()); 97 data.add(info); 98 added.add(info); 99 } 100 } 101 removePromiseApp(AppInfo appInfo)102 public void removePromiseApp(AppInfo appInfo) { 103 // the <em>removed</em> list is handled by the caller 104 // so not adding it here 105 data.remove(appInfo); 106 } 107 clear()108 public void clear() { 109 data.clear(); 110 // TODO: do we clear these too? 111 added.clear(); 112 removed.clear(); 113 modified.clear(); 114 } 115 size()116 public int size() { 117 return data.size(); 118 } 119 get(int index)120 public AppInfo get(int index) { 121 return data.get(index); 122 } 123 124 /** 125 * Add the icons for the supplied apk called packageName. 126 */ addPackage(Context context, String packageName, UserHandle user)127 public void addPackage(Context context, String packageName, UserHandle user) { 128 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); 129 final List<LauncherActivityInfo> matches = launcherApps.getActivityList(packageName, 130 user); 131 132 for (LauncherActivityInfo info : matches) { 133 add(new AppInfo(context, info, user), info); 134 } 135 } 136 137 /** 138 * Remove the apps for the given apk identified by packageName. 139 */ removePackage(String packageName, UserHandle user)140 public void removePackage(String packageName, UserHandle user) { 141 final List<AppInfo> data = this.data; 142 for (int i = data.size() - 1; i >= 0; i--) { 143 AppInfo info = data.get(i); 144 if (info.user.equals(user) && packageName.equals(info.componentName.getPackageName())) { 145 removed.add(info); 146 data.remove(i); 147 } 148 } 149 } 150 151 /** 152 * Updates the disabled flags of apps matching {@param matcher} based on {@param op}. 153 */ updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op)154 public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) { 155 final List<AppInfo> data = this.data; 156 for (int i = data.size() - 1; i >= 0; i--) { 157 AppInfo info = data.get(i); 158 if (matcher.matches(info, info.componentName)) { 159 info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags); 160 modified.add(info); 161 } 162 } 163 } 164 updateIconsAndLabels(HashSet<String> packages, UserHandle user, ArrayList<AppInfo> outUpdates)165 public void updateIconsAndLabels(HashSet<String> packages, UserHandle user, 166 ArrayList<AppInfo> outUpdates) { 167 for (AppInfo info : data) { 168 if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) { 169 mIconCache.updateTitleAndIcon(info); 170 outUpdates.add(info); 171 } 172 } 173 } 174 175 /** 176 * Add and remove icons for this package which has been updated. 177 */ updatePackage(Context context, String packageName, UserHandle user)178 public void updatePackage(Context context, String packageName, UserHandle user) { 179 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); 180 final List<LauncherActivityInfo> matches = launcherApps.getActivityList(packageName, 181 user); 182 if (matches.size() > 0) { 183 // Find disabled/removed activities and remove them from data and add them 184 // to the removed list. 185 for (int i = data.size() - 1; i >= 0; i--) { 186 final AppInfo applicationInfo = data.get(i); 187 if (user.equals(applicationInfo.user) 188 && packageName.equals(applicationInfo.componentName.getPackageName())) { 189 if (!findActivity(matches, applicationInfo.componentName)) { 190 Log.w(TAG, "Changing shortcut target due to app component name change."); 191 removed.add(applicationInfo); 192 data.remove(i); 193 } 194 } 195 } 196 197 // Find enabled activities and add them to the adapter 198 // Also updates existing activities with new labels/icons 199 for (final LauncherActivityInfo info : matches) { 200 AppInfo applicationInfo = findAppInfo(info.getComponentName(), user); 201 if (applicationInfo == null) { 202 add(new AppInfo(context, info, user), info); 203 } else { 204 mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */); 205 modified.add(applicationInfo); 206 } 207 } 208 } else { 209 // Remove all data for this package. 210 for (int i = data.size() - 1; i >= 0; i--) { 211 final AppInfo applicationInfo = data.get(i); 212 if (user.equals(applicationInfo.user) 213 && packageName.equals(applicationInfo.componentName.getPackageName())) { 214 removed.add(applicationInfo); 215 mIconCache.remove(applicationInfo.componentName, user); 216 data.remove(i); 217 } 218 } 219 } 220 } 221 222 223 /** 224 * Returns whether <em>apps</em> contains <em>component</em>. 225 */ findActivity(List<LauncherActivityInfo> apps, ComponentName component)226 private static boolean findActivity(List<LauncherActivityInfo> apps, 227 ComponentName component) { 228 for (LauncherActivityInfo info : apps) { 229 if (info.getComponentName().equals(component)) { 230 return true; 231 } 232 } 233 return false; 234 } 235 236 /** 237 * Find an AppInfo object for the given componentName 238 * 239 * @return the corresponding AppInfo or null 240 */ findAppInfo(@onNull ComponentName componentName, @NonNull UserHandle user)241 private @Nullable AppInfo findAppInfo(@NonNull ComponentName componentName, 242 @NonNull UserHandle user) { 243 for (AppInfo info: data) { 244 if (componentName.equals(info.componentName) && user.equals(info.user)) { 245 return info; 246 } 247 } 248 return null; 249 } 250 } 251