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 
22 import com.android.launcher3.compat.LauncherActivityInfoCompat;
23 import com.android.launcher3.compat.LauncherAppsCompat;
24 import com.android.launcher3.compat.UserHandleCompat;
25 
26 import java.util.ArrayList;
27 import java.util.List;
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<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     private AppFilter mAppFilter;
50 
51     /**
52      * Boring constructor.
53      */
AllAppsList(IconCache iconCache, AppFilter appFilter)54     public AllAppsList(IconCache iconCache, AppFilter appFilter) {
55         mIconCache = iconCache;
56         mAppFilter = appFilter;
57     }
58 
59     /**
60      * Add the supplied ApplicationInfo objects to the list, and enqueue it into the
61      * list to broadcast when notify() is called.
62      *
63      * If the app is already in the list, doesn't add it.
64      */
add(AppInfo info)65     public void add(AppInfo info) {
66         if (mAppFilter != null && !mAppFilter.shouldShowApp(info.componentName)) {
67             return;
68         }
69         if (findActivity(data, info.componentName, info.user)) {
70             return;
71         }
72         data.add(info);
73         added.add(info);
74     }
75 
clear()76     public void clear() {
77         data.clear();
78         // TODO: do we clear these too?
79         added.clear();
80         removed.clear();
81         modified.clear();
82     }
83 
size()84     public int size() {
85         return data.size();
86     }
87 
get(int index)88     public AppInfo get(int index) {
89         return data.get(index);
90     }
91 
92     /**
93      * Add the icons for the supplied apk called packageName.
94      */
addPackage(Context context, String packageName, UserHandleCompat user)95     public void addPackage(Context context, String packageName, UserHandleCompat user) {
96         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
97         final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
98                 user);
99 
100         for (LauncherActivityInfoCompat info : matches) {
101             add(new AppInfo(context, info, user, mIconCache, null));
102         }
103     }
104 
105     /**
106      * Remove the apps for the given apk identified by packageName.
107      */
removePackage(String packageName, UserHandleCompat user, boolean clearCache)108     public void removePackage(String packageName, UserHandleCompat user, boolean clearCache) {
109         final List<AppInfo> data = this.data;
110         for (int i = data.size() - 1; i >= 0; i--) {
111             AppInfo info = data.get(i);
112             final ComponentName component = info.intent.getComponent();
113             if (info.user.equals(user) && packageName.equals(component.getPackageName())) {
114                 removed.add(info);
115                 data.remove(i);
116             }
117         }
118         if (clearCache) {
119             mIconCache.remove(packageName, user);
120         }
121     }
122 
123     /**
124      * Add and remove icons for this package which has been updated.
125      */
updatePackage(Context context, String packageName, UserHandleCompat user)126     public void updatePackage(Context context, String packageName, UserHandleCompat user) {
127         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
128         final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
129                 user);
130         if (matches.size() > 0) {
131             // Find disabled/removed activities and remove them from data and add them
132             // to the removed list.
133             for (int i = data.size() - 1; i >= 0; i--) {
134                 final AppInfo applicationInfo = data.get(i);
135                 final ComponentName component = applicationInfo.intent.getComponent();
136                 if (user.equals(applicationInfo.user)
137                         && packageName.equals(component.getPackageName())) {
138                     if (!findActivity(matches, component)) {
139                         removed.add(applicationInfo);
140                         mIconCache.remove(component, user);
141                         data.remove(i);
142                     }
143                 }
144             }
145 
146             // Find enabled activities and add them to the adapter
147             // Also updates existing activities with new labels/icons
148             for (final LauncherActivityInfoCompat info : matches) {
149                 AppInfo applicationInfo = findApplicationInfoLocked(
150                         info.getComponentName().getPackageName(), user,
151                         info.getComponentName().getClassName());
152                 if (applicationInfo == null) {
153                     add(new AppInfo(context, info, user, mIconCache, null));
154                 } else {
155                     mIconCache.remove(applicationInfo.componentName, user);
156                     mIconCache.getTitleAndIcon(applicationInfo, info, null);
157                     modified.add(applicationInfo);
158                 }
159             }
160         } else {
161             // Remove all data for this package.
162             for (int i = data.size() - 1; i >= 0; i--) {
163                 final AppInfo applicationInfo = data.get(i);
164                 final ComponentName component = applicationInfo.intent.getComponent();
165                 if (user.equals(applicationInfo.user)
166                         && packageName.equals(component.getPackageName())) {
167                     removed.add(applicationInfo);
168                     mIconCache.remove(component, user);
169                     data.remove(i);
170                 }
171             }
172         }
173     }
174 
175 
176     /**
177      * Returns whether <em>apps</em> contains <em>component</em>.
178      */
findActivity(List<LauncherActivityInfoCompat> apps, ComponentName component)179     private static boolean findActivity(List<LauncherActivityInfoCompat> apps,
180             ComponentName component) {
181         for (LauncherActivityInfoCompat info : apps) {
182             if (info.getComponentName().equals(component)) {
183                 return true;
184             }
185         }
186         return false;
187     }
188 
189     /**
190      * Query the launcher apps service for whether the supplied package has
191      * MAIN/LAUNCHER activities in the supplied package.
192      */
packageHasActivities(Context context, String packageName, UserHandleCompat user)193     static boolean packageHasActivities(Context context, String packageName,
194             UserHandleCompat user) {
195         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
196         return launcherApps.getActivityList(packageName, user).size() > 0;
197     }
198 
199     /**
200      * Returns whether <em>apps</em> contains <em>component</em>.
201      */
findActivity(ArrayList<AppInfo> apps, ComponentName component, UserHandleCompat user)202     private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component,
203             UserHandleCompat user) {
204         final int N = apps.size();
205         for (int i = 0; i < N; i++) {
206             final AppInfo info = apps.get(i);
207             if (info.user.equals(user) && info.componentName.equals(component)) {
208                 return true;
209             }
210         }
211         return false;
212     }
213 
214     /**
215      * Find an ApplicationInfo object for the given packageName and className.
216      */
findApplicationInfoLocked(String packageName, UserHandleCompat user, String className)217     private AppInfo findApplicationInfoLocked(String packageName, UserHandleCompat user,
218             String className) {
219         for (AppInfo info: data) {
220             final ComponentName component = info.intent.getComponent();
221             if (user.equals(info.user) && packageName.equals(component.getPackageName())
222                     && className.equals(component.getClassName())) {
223                 return info;
224             }
225         }
226         return null;
227     }
228 }
229