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