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