AllAppsList.java revision eadbfc564d84aaf1d800da3d0d6edf6312f89648
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
17package com.android.launcher3;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.ActivityInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.ResolveInfo;
28
29
30/**
31 * Stores the list of all applications for the all apps view.
32 */
33class AllAppsList {
34    public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
35
36    /** The list off all apps. */
37    public ArrayList<AppInfo> data =
38            new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
39    /** The list of apps that have been added since the last notify() call. */
40    public ArrayList<AppInfo> added =
41            new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
42    /** The list of apps that have been removed since the last notify() call. */
43    public ArrayList<AppInfo> removed = new ArrayList<AppInfo>();
44    /** The list of apps that have been modified since the last notify() call. */
45    public ArrayList<AppInfo> modified = new ArrayList<AppInfo>();
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(AppInfo 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 AppInfo 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 AppInfo(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<AppInfo> data = this.data;
104        for (int i = data.size() - 1; i >= 0; i--) {
105            AppInfo 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 AppInfo 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                AppInfo applicationInfo = findApplicationInfoLocked(
142                        info.activityInfo.applicationInfo.packageName,
143                        info.activityInfo.name);
144                if (applicationInfo == null) {
145                    add(new AppInfo(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 AppInfo 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    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<AppInfo> apps, ComponentName component) {
198        final int N = apps.size();
199        for (int i=0; i<N; i++) {
200            final AppInfo 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 AppInfo findApplicationInfoLocked(String packageName, String className) {
212        for (AppInfo 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