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.launcher2; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.ActivityInfo; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 29 30 /** 31 * Stores the list of all applications for the all apps view. 32 */ 33 class AllAppsList { 34 public static final int DEFAULT_APPLICATIONS_NUMBER = 42; 35 36 /** The list off all apps. */ 37 public ArrayList<ApplicationInfo> data = 38 new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); 39 /** The list of apps that have been added since the last notify() call. */ 40 public ArrayList<ApplicationInfo> added = 41 new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); 42 /** The list of apps that have been removed since the last notify() call. */ 43 public ArrayList<ApplicationInfo> removed = new ArrayList<ApplicationInfo>(); 44 /** The list of apps that have been modified since the last notify() call. */ 45 public ArrayList<ApplicationInfo> modified = new ArrayList<ApplicationInfo>(); 46 47 private IconCache mIconCache; 48 49 /** 50 * Boring constructor. 51 */ 52 public AllAppsList(IconCache iconCache) { 53 mIconCache = iconCache; 54 } 55 56 /** 57 * Add the supplied ApplicationInfo objects to the list, and enqueue it into the 58 * list to broadcast when notify() is called. 59 * 60 * If the app is already in the list, doesn't add it. 61 */ 62 public void add(ApplicationInfo info) { 63 if (findActivity(data, info.componentName)) { 64 return; 65 } 66 data.add(info); 67 added.add(info); 68 } 69 70 public void clear() { 71 data.clear(); 72 // TODO: do we clear these too? 73 added.clear(); 74 removed.clear(); 75 modified.clear(); 76 } 77 78 public int size() { 79 return data.size(); 80 } 81 82 public ApplicationInfo get(int index) { 83 return data.get(index); 84 } 85 86 /** 87 * Add the icons for the supplied apk called packageName. 88 */ 89 public void addPackage(Context context, String packageName) { 90 final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); 91 92 if (matches.size() > 0) { 93 for (ResolveInfo info : matches) { 94 add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null)); 95 } 96 } 97 } 98 99 /** 100 * Remove the apps for the given apk identified by packageName. 101 */ 102 public void removePackage(String packageName) { 103 final List<ApplicationInfo> data = this.data; 104 for (int i = data.size() - 1; i >= 0; i--) { 105 ApplicationInfo info = data.get(i); 106 final ComponentName component = info.intent.getComponent(); 107 if (packageName.equals(component.getPackageName())) { 108 removed.add(info); 109 data.remove(i); 110 } 111 } 112 // This is more aggressive than it needs to be. 113 mIconCache.flush(); 114 } 115 116 /** 117 * Add and remove icons for this package which has been updated. 118 */ 119 public void updatePackage(Context context, String packageName) { 120 final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); 121 if (matches.size() > 0) { 122 // Find disabled/removed activities and remove them from data and add them 123 // to the removed list. 124 for (int i = data.size() - 1; i >= 0; i--) { 125 final ApplicationInfo applicationInfo = data.get(i); 126 final ComponentName component = applicationInfo.intent.getComponent(); 127 if (packageName.equals(component.getPackageName())) { 128 if (!findActivity(matches, component)) { 129 removed.add(applicationInfo); 130 mIconCache.remove(component); 131 data.remove(i); 132 } 133 } 134 } 135 136 // Find enabled activities and add them to the adapter 137 // Also updates existing activities with new labels/icons 138 int count = matches.size(); 139 for (int i = 0; i < count; i++) { 140 final ResolveInfo info = matches.get(i); 141 ApplicationInfo applicationInfo = findApplicationInfoLocked( 142 info.activityInfo.applicationInfo.packageName, 143 info.activityInfo.name); 144 if (applicationInfo == null) { 145 add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null)); 146 } else { 147 mIconCache.remove(applicationInfo.componentName); 148 mIconCache.getTitleAndIcon(applicationInfo, info, null); 149 modified.add(applicationInfo); 150 } 151 } 152 } else { 153 // Remove all data for this package. 154 for (int i = data.size() - 1; i >= 0; i--) { 155 final ApplicationInfo applicationInfo = data.get(i); 156 final ComponentName component = applicationInfo.intent.getComponent(); 157 if (packageName.equals(component.getPackageName())) { 158 removed.add(applicationInfo); 159 mIconCache.remove(component); 160 data.remove(i); 161 } 162 } 163 } 164 } 165 166 /** 167 * Query the package manager for MAIN/LAUNCHER activities in the supplied package. 168 */ 169 private static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) { 170 final PackageManager packageManager = context.getPackageManager(); 171 172 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 173 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 174 mainIntent.setPackage(packageName); 175 176 final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); 177 return apps != null ? apps : new ArrayList<ResolveInfo>(); 178 } 179 180 /** 181 * Returns whether <em>apps</em> contains <em>component</em>. 182 */ 183 private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) { 184 final String className = component.getClassName(); 185 for (ResolveInfo info : apps) { 186 final ActivityInfo activityInfo = info.activityInfo; 187 if (activityInfo.name.equals(className)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 /** 195 * Returns whether <em>apps</em> contains <em>component</em>. 196 */ 197 private static boolean findActivity(ArrayList<ApplicationInfo> apps, ComponentName component) { 198 final int N = apps.size(); 199 for (int i=0; i<N; i++) { 200 final ApplicationInfo info = apps.get(i); 201 if (info.componentName.equals(component)) { 202 return true; 203 } 204 } 205 return false; 206 } 207 208 /** 209 * Find an ApplicationInfo object for the given packageName and className. 210 */ 211 private ApplicationInfo findApplicationInfoLocked(String packageName, String className) { 212 for (ApplicationInfo info: data) { 213 final ComponentName component = info.intent.getComponent(); 214 if (packageName.equals(component.getPackageName()) 215 && className.equals(component.getClassName())) { 216 return info; 217 } 218 } 219 return null; 220 } 221 } 222