blob: 591463bd019f67e5e03deb1baaa355435e753ebf [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
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.launcher;
18
19import android.content.ComponentName;
20import android.content.ContentResolver;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.content.Context;
24import android.content.pm.ActivityInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.content.res.Resources;
28import android.database.Cursor;
29import android.graphics.Bitmap;
30import android.graphics.BitmapFactory;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070031import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080032import android.net.Uri;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070033import static android.util.Log.*;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080034import android.os.Process;
35
36import java.util.ArrayList;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080037import java.util.HashMap;
38import java.util.List;
39import java.util.Comparator;
40import java.lang.ref.WeakReference;
41import java.text.Collator;
42import java.net.URISyntaxException;
43
44/**
45 * Maintains in-memory state of the Launcher. It is expected that there should be only one
46 * LauncherModel object held in a static. Also provide APIs for updating the database state
The Android Open Source Projectbc219c32009-03-09 11:52:14 -070047 * for the Launcher.
The Android Open Source Project31dd5032009-03-03 19:32:27 -080048 */
49public class LauncherModel {
Romain Guy829f56a2009-03-27 16:58:13 -070050 static final boolean DEBUG_LOADERS = true;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070051 static final String LOG_TAG = "HomeLoaders";
52
The Android Open Source Project31dd5032009-03-03 19:32:27 -080053 private static final int UI_NOTIFICATION_RATE = 4;
54 private static final int DEFAULT_APPLICATIONS_NUMBER = 42;
55 private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000;
The Android Open Source Projectbc219c32009-03-09 11:52:14 -070056 private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080057
The Android Open Source Project7376fae2009-03-11 12:11:58 -070058 private static final Collator sCollator = Collator.getInstance();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080059
60 private boolean mApplicationsLoaded;
61 private boolean mDesktopItemsLoaded;
62
63 private ArrayList<ItemInfo> mDesktopItems;
The Android Open Source Project7376fae2009-03-11 12:11:58 -070064 private ArrayList<LauncherAppWidgetInfo> mDesktopAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080065 private HashMap<Long, FolderInfo> mFolders;
66
67 private ArrayList<ApplicationInfo> mApplications;
68 private ApplicationsAdapter mApplicationsAdapter;
69 private ApplicationsLoader mApplicationsLoader;
70 private DesktopItemsLoader mDesktopItemsLoader;
The Android Open Source Projectca9475f2009-03-13 13:04:24 -070071 private Thread mApplicationsLoaderThread;
72 private Thread mDesktopLoaderThread;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080073
The Android Open Source Projectbc219c32009-03-09 11:52:14 -070074 private final HashMap<ComponentName, ApplicationInfo> mAppInfoCache =
75 new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY);
76
The Android Open Source Projectca9475f2009-03-13 13:04:24 -070077 synchronized void abortLoaders() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080078 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
79 mApplicationsLoader.stop();
80 mApplicationsLoaded = false;
81 }
The Android Open Source Projectca9475f2009-03-13 13:04:24 -070082
The Android Open Source Project31dd5032009-03-03 19:32:27 -080083 if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
84 mDesktopItemsLoader.stop();
85 mDesktopItemsLoaded = false;
86 }
87 }
88
89 /**
The Android Open Source Projectbc219c32009-03-09 11:52:14 -070090 * Drop our cache of components to their lables & icons. We do
91 * this from Launcher when applications are added/removed. It's a
92 * bit overkill, but it's a rare operation anyway.
93 */
94 synchronized void dropApplicationCache() {
95 mAppInfoCache.clear();
96 }
97
98 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -080099 * Loads the list of installed applications in mApplications.
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700100 *
101 * @return true if the applications loader must be started
102 * (see startApplicationsLoader()), false otherwise.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800103 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700104 synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700105 boolean localeChanged) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700106
107 if (DEBUG_LOADERS) d(LOG_TAG, "load applications");
108
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800109 if (isLaunching && mApplicationsLoaded && !localeChanged) {
110 mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700111 if (DEBUG_LOADERS) d(LOG_TAG, " --> applications loaded, return");
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700112 return false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800113 }
114
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700115 stopAndWaitForApplicationsLoader();
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700116
117 if (localeChanged) {
118 dropApplicationCache();
Romain Guy2fcbd682009-06-11 13:58:26 -0700119 }
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700120
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800121 if (mApplicationsAdapter == null || isLaunching || localeChanged) {
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700122 mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
123 mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800124 }
125
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800126 mApplicationsLoaded = false;
127
128 if (!isLaunching) {
Romain Guy2fcbd682009-06-11 13:58:26 -0700129 startApplicationsLoader(launcher, false);
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700130 return false;
131 }
132
133 return true;
134 }
135
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700136 private synchronized void stopAndWaitForApplicationsLoader() {
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700137 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700138 if (DEBUG_LOADERS) d(LOG_TAG, " --> wait for applications loader");
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700139
140 mApplicationsLoader.stop();
141 // Wait for the currently running thread to finish, this can take a little
142 // time but it should be well below the timeout limit
143 try {
144 mApplicationsLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
145 } catch (InterruptedException e) {
146 // EMpty
147 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800148 }
149 }
150
Romain Guy2fcbd682009-06-11 13:58:26 -0700151 private synchronized void startApplicationsLoader(Launcher launcher, boolean isLaunching) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700152 if (DEBUG_LOADERS) d(LOG_TAG, " --> starting applications loader");
153
154 stopAndWaitForApplicationsLoader();
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700155
Romain Guy2fcbd682009-06-11 13:58:26 -0700156 mApplicationsLoader = new ApplicationsLoader(launcher, isLaunching);
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700157 mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");
158 mApplicationsLoaderThread.start();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800159 }
160
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700161 synchronized void addPackage(Launcher launcher, String packageName) {
162 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
Romain Guy2fcbd682009-06-11 13:58:26 -0700163 startApplicationsLoader(launcher, false);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700164 return;
165 }
166
167 if (packageName != null && packageName.length() > 0) {
168 final PackageManager packageManager = launcher.getPackageManager();
169 final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
170
171 if (matches.size() > 0) {
172 final ApplicationsAdapter adapter = mApplicationsAdapter;
173 final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
174
175 for (ResolveInfo info : matches) {
176 adapter.setNotifyOnChange(false);
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700177 adapter.add(makeAndCacheApplicationInfo(packageManager, cache, info, launcher));
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700178 }
179
180 adapter.sort(new ApplicationInfoComparator());
181 adapter.notifyDataSetChanged();
182 }
183 }
184 }
185
186 synchronized void removePackage(Launcher launcher, String packageName) {
187 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
188 dropApplicationCache(); // TODO: this could be optimized
Romain Guy2fcbd682009-06-11 13:58:26 -0700189 startApplicationsLoader(launcher, false);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700190 return;
191 }
192
193 if (packageName != null && packageName.length() > 0) {
194 final ApplicationsAdapter adapter = mApplicationsAdapter;
195
196 final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
197 final int count = adapter.getCount();
198
199 for (int i = 0; i < count; i++) {
200 final ApplicationInfo applicationInfo = adapter.getItem(i);
201 final Intent intent = applicationInfo.intent;
202 final ComponentName component = intent.getComponent();
203 if (packageName.equals(component.getPackageName())) {
204 toRemove.add(applicationInfo);
205 }
206 }
207
208 final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
209 for (ApplicationInfo info : toRemove) {
210 adapter.setNotifyOnChange(false);
211 adapter.remove(info);
212 cache.remove(info.intent.getComponent());
213 }
214
215 if (toRemove.size() > 0) {
216 adapter.sort(new ApplicationInfoComparator());
217 adapter.notifyDataSetChanged();
218 }
219 }
220 }
221
222 synchronized void updatePackage(Launcher launcher, String packageName) {
223 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
Romain Guy2fcbd682009-06-11 13:58:26 -0700224 startApplicationsLoader(launcher, false);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700225 return;
226 }
227
228 if (packageName != null && packageName.length() > 0) {
229 final PackageManager packageManager = launcher.getPackageManager();
230 final ApplicationsAdapter adapter = mApplicationsAdapter;
231
232 final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
233 final int count = matches.size();
234
235 boolean changed = false;
236
237 for (int i = 0; i < count; i++) {
238 final ResolveInfo info = matches.get(i);
239 final ApplicationInfo applicationInfo = findIntent(adapter,
240 info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
241 if (applicationInfo != null) {
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700242 updateAndCacheApplicationInfo(packageManager, info, applicationInfo, launcher);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700243 changed = true;
244 }
245 }
246
Romain Guyb132a972009-06-24 13:45:46 -0700247 if (syncLocked(launcher, packageName)) changed = true;
248
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700249 if (changed) {
250 adapter.sort(new ApplicationInfoComparator());
251 adapter.notifyDataSetChanged();
252 }
253 }
254 }
255
256 private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700257 ApplicationInfo applicationInfo, Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700258
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700259 updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo, context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700260
261 ComponentName componentName = new ComponentName(
262 info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
263 mAppInfoCache.put(componentName, applicationInfo);
264 }
265
266 synchronized void syncPackage(Launcher launcher, String packageName) {
267 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
Romain Guy2fcbd682009-06-11 13:58:26 -0700268 startApplicationsLoader(launcher, false);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700269 return;
270 }
271
272 if (packageName != null && packageName.length() > 0) {
Romain Guyb132a972009-06-24 13:45:46 -0700273 if (syncLocked(launcher, packageName)) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700274 final ApplicationsAdapter adapter = mApplicationsAdapter;
Romain Guyb132a972009-06-24 13:45:46 -0700275 adapter.sort(new ApplicationInfoComparator());
276 adapter.notifyDataSetChanged();
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700277 }
278 }
279 }
280
Romain Guyb132a972009-06-24 13:45:46 -0700281 private boolean syncLocked(Launcher launcher, String packageName) {
282 final PackageManager packageManager = launcher.getPackageManager();
283 final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
284
285 if (matches.size() > 0) {
286 final ApplicationsAdapter adapter = mApplicationsAdapter;
287
288 // Find disabled activities and remove them from the adapter
289 boolean removed = removeDisabledActivities(packageName, matches, adapter);
290 // Find enable activities and add them to the adapter
291 // Also updates existing activities with new labels/icons
292 boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher);
293
294 return added || removed;
295 }
296
297 return false;
298 }
299
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700300 private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager,
301 String packageName) {
302
303 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
304 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
305
306 final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
307 final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
308
309 if (apps != null) {
310 // Find all activities that match the packageName
311 int count = apps.size();
312 for (int i = 0; i < count; i++) {
313 final ResolveInfo info = apps.get(i);
314 final ActivityInfo activityInfo = info.activityInfo;
315 if (packageName.equals(activityInfo.packageName)) {
316 matches.add(info);
317 }
318 }
319 }
320
321 return matches;
322 }
323
324 private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches,
325 ApplicationsAdapter adapter, Launcher launcher) {
326
327 final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>();
328 final int count = matches.size();
329
330 boolean changed = false;
331
332 for (int i = 0; i < count; i++) {
333 final ResolveInfo info = matches.get(i);
334 final ApplicationInfo applicationInfo = findIntent(adapter,
335 info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
336 if (applicationInfo == null) {
337 toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(),
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700338 mAppInfoCache, info, launcher));
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700339 changed = true;
340 } else {
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700341 updateAndCacheApplicationInfo(
342 launcher.getPackageManager(), info, applicationInfo, launcher);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700343 changed = true;
344 }
345 }
346
347 for (ApplicationInfo info : toAdd) {
348 adapter.setNotifyOnChange(false);
349 adapter.add(info);
350 }
351
352 return changed;
353 }
354
355 private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches,
356 ApplicationsAdapter adapter) {
357
358 final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
359 final int count = adapter.getCount();
360
361 boolean changed = false;
362
363 for (int i = 0; i < count; i++) {
364 final ApplicationInfo applicationInfo = adapter.getItem(i);
365 final Intent intent = applicationInfo.intent;
366 final ComponentName component = intent.getComponent();
367 if (packageName.equals(component.getPackageName())) {
368 if (!findIntent(matches, component)) {
369 toRemove.add(applicationInfo);
370 changed = true;
371 }
372 }
373 }
374
375 final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
376 for (ApplicationInfo info : toRemove) {
377 adapter.setNotifyOnChange(false);
378 adapter.remove(info);
379 cache.remove(info.intent.getComponent());
380 }
381
382 return changed;
383 }
384
385 private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName,
386 String name) {
387
388 final int count = adapter.getCount();
389 for (int i = 0; i < count; i++) {
390 final ApplicationInfo applicationInfo = adapter.getItem(i);
391 final Intent intent = applicationInfo.intent;
392 final ComponentName component = intent.getComponent();
393 if (packageName.equals(component.getPackageName()) &&
394 name.equals(component.getClassName())) {
395 return applicationInfo;
396 }
397 }
398
399 return null;
400 }
401
402 private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) {
403 final String className = component.getClassName();
404 for (ResolveInfo info : apps) {
405 final ActivityInfo activityInfo = info.activityInfo;
406 if (activityInfo.name.equals(className)) {
407 return true;
408 }
409 }
410 return false;
411 }
412
413 Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) {
414 final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0);
415 if (resolveInfo == null) {
416 return null;
417 }
418
419 ComponentName componentName = new ComponentName(
420 resolveInfo.activityInfo.applicationInfo.packageName,
421 resolveInfo.activityInfo.name);
422 ApplicationInfo application = mAppInfoCache.get(componentName);
423
424 if (application == null) {
425 return resolveInfo.activityInfo.loadIcon(manager);
426 }
427
428 return application.icon;
429 }
430
431 private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700432 HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info,
433 Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700434
435 ComponentName componentName = new ComponentName(
436 info.activityInfo.applicationInfo.packageName,
437 info.activityInfo.name);
438 ApplicationInfo application = appInfoCache.get(componentName);
439
440 if (application == null) {
441 application = new ApplicationInfo();
442 application.container = ItemInfo.NO_ID;
443
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700444 updateApplicationInfoTitleAndIcon(manager, info, application, context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700445
446 application.setActivity(componentName,
447 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
448
449 appInfoCache.put(componentName, application);
450 }
451
452 return application;
453 }
454
455 private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700456 ApplicationInfo application, Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700457
458 application.title = info.loadLabel(manager);
459 if (application.title == null) {
460 application.title = info.activityInfo.name;
461 }
462
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700463 application.icon =
464 Utilities.createIconThumbnail(info.activityInfo.loadIcon(manager), context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700465 application.filtered = false;
466 }
467
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800468 private class ApplicationsLoader implements Runnable {
469 private final WeakReference<Launcher> mLauncher;
470
471 private volatile boolean mStopped;
472 private volatile boolean mRunning;
Romain Guy2fcbd682009-06-11 13:58:26 -0700473 private final boolean mIsLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800474
Romain Guy2fcbd682009-06-11 13:58:26 -0700475 ApplicationsLoader(Launcher launcher, boolean isLaunching) {
476 mIsLaunching = isLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800477 mLauncher = new WeakReference<Launcher>(launcher);
478 }
479
480 void stop() {
481 mStopped = true;
482 }
483
484 boolean isRunning() {
485 return mRunning;
486 }
487
488 public void run() {
489 mRunning = true;
490
Romain Guy2fcbd682009-06-11 13:58:26 -0700491 // Elevate priority when Home launches for the first time to avoid
492 // starving at boot time. Staring at a blank home is not cool.
493 android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT :
494 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800495
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700496 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800497 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
498
499 final Launcher launcher = mLauncher.get();
500 final PackageManager manager = launcher.getPackageManager();
501 final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
502
503 if (apps != null && !mStopped) {
504 final int count = apps.size();
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700505 // Can be set to null on the UI thread by the unbind() method
506 // Do not access without checking for null first
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800507 final ApplicationsAdapter applicationList = mApplicationsAdapter;
508
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700509 ChangeNotifier action = new ChangeNotifier(applicationList, true);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700510 final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800511
512 for (int i = 0; i < count && !mStopped; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800513 ResolveInfo info = apps.get(i);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700514 ApplicationInfo application =
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700515 makeAndCacheApplicationInfo(manager, appInfoCache, info, launcher);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800516
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700517 if (action.add(application) && !mStopped) {
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700518 launcher.runOnUiThread(action);
519 action = new ChangeNotifier(applicationList, false);
520 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800521 }
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700522
523 launcher.runOnUiThread(action);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800524 }
525
526 if (!mStopped) {
527 mApplicationsLoaded = true;
528 }
529 mRunning = false;
530 }
531 }
532
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700533 private static class ChangeNotifier implements Runnable {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800534 private final ApplicationsAdapter mApplicationList;
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700535 private final ArrayList<ApplicationInfo> mBuffer;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800536
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700537 private boolean mFirst = true;
538
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700539 ChangeNotifier(ApplicationsAdapter applicationList, boolean first) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800540 mApplicationList = applicationList;
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700541 mFirst = first;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800542 mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE);
543 }
544
545 public void run() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800546 final ApplicationsAdapter applicationList = mApplicationList;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700547 // Can be set to null on the UI thread by the unbind() method
548 if (applicationList == null) return;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800549
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700550 if (mFirst) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800551 applicationList.setNotifyOnChange(false);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700552 applicationList.clear();
553 mFirst = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800554 }
555
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700556 final ArrayList<ApplicationInfo> buffer = mBuffer;
557 final int count = buffer.size();
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700558
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700559 for (int i = 0; i < count; i++) {
560 applicationList.setNotifyOnChange(false);
561 applicationList.add(buffer.get(i));
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700562 }
563
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700564 buffer.clear();
565
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700566 applicationList.sort(new ApplicationInfoComparator());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800567 applicationList.notifyDataSetChanged();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800568 }
569
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700570 boolean add(ApplicationInfo application) {
571 final ArrayList<ApplicationInfo> buffer = mBuffer;
572 buffer.add(application);
573 return buffer.size() >= UI_NOTIFICATION_RATE;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800574 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700575 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800576
Romain Guy73b979d2009-06-09 12:57:21 -0700577 static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700578 public final int compare(ApplicationInfo a, ApplicationInfo b) {
579 return sCollator.compare(a.title.toString(), b.title.toString());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800580 }
581 }
582
583 boolean isDesktopLoaded() {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700584 return mDesktopItems != null && mDesktopAppWidgets != null && mDesktopItemsLoaded;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800585 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700586
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800587 /**
588 * Loads all of the items on the desktop, in folders, or in the dock.
589 * These can be apps, shortcuts or widgets
590 */
591 void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
592 boolean loadApplications) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700593 if (DEBUG_LOADERS) d(LOG_TAG, "loading user items");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800594
595 if (isLaunching && isDesktopLoaded()) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700596 if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return");
Romain Guy2fcbd682009-06-11 13:58:26 -0700597 if (loadApplications) startApplicationsLoader(launcher, true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800598 // We have already loaded our data from the DB
599 launcher.onDesktopItemsLoaded();
600 return;
601 }
602
603 if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
Romain Guyfedc4fc2009-03-27 20:48:20 -0700604 if (DEBUG_LOADERS) d(LOG_TAG, " --> stopping workspace loader");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800605 mDesktopItemsLoader.stop();
606 // Wait for the currently running thread to finish, this can take a little
607 // time but it should be well below the timeout limit
608 try {
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700609 mDesktopLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800610 } catch (InterruptedException e) {
611 // Empty
612 }
Romain Guyfedc4fc2009-03-27 20:48:20 -0700613
614 // If the thread we are interrupting was tasked to load the list of
615 // applications make sure we keep that information in the new loader
616 // spawned below
617 // note: we don't apply this to localeChanged because the thread can
618 // only be stopped *after* the localeChanged handling has occured
619 loadApplications = mDesktopItemsLoader.mLoadApplications;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800620 }
621
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700622 if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800623 mDesktopItemsLoaded = false;
Romain Guy2fcbd682009-06-11 13:58:26 -0700624 mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications,
625 isLaunching);
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700626 mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
627 mDesktopLoaderThread.start();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800628 }
629
630 private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
631 final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
Romain Guy73b979d2009-06-09 12:57:21 -0700632 new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800633 LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
634 null, null, null);
635
Romain Guy73b979d2009-06-09 12:57:21 -0700636 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800637 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
638 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
639 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
640
641 // boolean changed = false;
642
643 try {
644 while (c.moveToNext()) {
645 try {
646 if (c.getInt(itemTypeIndex) !=
647 LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
648 continue;
649 }
650
651 final String intentUri = c.getString(intentIndex);
652 if (intentUri != null) {
Romain Guy1ce1a242009-06-23 17:34:54 -0700653 final Intent shortcut = Intent.parseUri(intentUri, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800654 if (Intent.ACTION_MAIN.equals(shortcut.getAction())) {
655 final ComponentName name = shortcut.getComponent();
656 if (name != null) {
657 final ActivityInfo activityInfo = manager.getActivityInfo(name, 0);
658 final String title = c.getString(titleIndex);
659 String label = getLabel(manager, activityInfo);
660
661 if (title == null || !title.equals(label)) {
662 final ContentValues values = new ContentValues();
663 values.put(LauncherSettings.Favorites.TITLE, label);
664
Romain Guyfedc4fc2009-03-27 20:48:20 -0700665 resolver.update(
666 LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800667 values, "_id=?",
668 new String[] { String.valueOf(c.getLong(idIndex)) });
669
670 // changed = true;
671 }
672 }
673 }
674 }
675 } catch (URISyntaxException e) {
676 // Ignore
677 } catch (PackageManager.NameNotFoundException e) {
678 // Ignore
679 }
680 }
681 } finally {
682 c.close();
683 }
684
685 // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null);
686 }
687
688 private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
689 String label = activityInfo.loadLabel(manager).toString();
690 if (label == null) {
691 label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
692 if (label == null) {
693 label = activityInfo.name;
694 }
695 }
696 return label;
697 }
698
699 private class DesktopItemsLoader implements Runnable {
700 private volatile boolean mStopped;
701 private volatile boolean mRunning;
702
703 private final WeakReference<Launcher> mLauncher;
704 private final boolean mLocaleChanged;
705 private final boolean mLoadApplications;
Romain Guy2fcbd682009-06-11 13:58:26 -0700706 private final boolean mIsLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800707
Romain Guy2fcbd682009-06-11 13:58:26 -0700708 DesktopItemsLoader(Launcher launcher, boolean localeChanged, boolean loadApplications,
709 boolean isLaunching) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800710 mLoadApplications = loadApplications;
Romain Guy2fcbd682009-06-11 13:58:26 -0700711 mIsLaunching = isLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800712 mLauncher = new WeakReference<Launcher>(launcher);
713 mLocaleChanged = localeChanged;
714 }
715
716 void stop() {
717 mStopped = true;
718 }
719
720 boolean isRunning() {
721 return mRunning;
722 }
723
724 public void run() {
725 mRunning = true;
726
Romain Guy2fcbd682009-06-11 13:58:26 -0700727 android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
728
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800729 final Launcher launcher = mLauncher.get();
730 final ContentResolver contentResolver = launcher.getContentResolver();
731 final PackageManager manager = launcher.getPackageManager();
732
733 if (mLocaleChanged) {
734 updateShortcutLabels(contentResolver, manager);
735 }
736
737 mDesktopItems = new ArrayList<ItemInfo>();
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700738 mDesktopAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800739 mFolders = new HashMap<Long, FolderInfo>();
740
741 final ArrayList<ItemInfo> desktopItems = mDesktopItems;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700742 final ArrayList<LauncherAppWidgetInfo> desktopAppWidgets = mDesktopAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800743
744 final Cursor c = contentResolver.query(
745 LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
746
747 try {
Romain Guy73b979d2009-06-09 12:57:21 -0700748 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800749 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
750 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
751 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
752 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
753 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
754 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
755 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
756 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700757 final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800758 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
759 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
760 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
761 final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
762 final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
763 final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
764 final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
765
766 ApplicationInfo info;
767 String intentDescription;
768 Widget widgetInfo;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700769 LauncherAppWidgetInfo appWidgetInfo;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800770 int container;
771 long id;
772 Intent intent;
773
774 final HashMap<Long, FolderInfo> folders = mFolders;
775
776 while (!mStopped && c.moveToNext()) {
777 try {
778 int itemType = c.getInt(itemTypeIndex);
779
780 switch (itemType) {
781 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
782 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
783 intentDescription = c.getString(intentIndex);
784 try {
Romain Guy1ce1a242009-06-23 17:34:54 -0700785 intent = Intent.parseUri(intentDescription, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800786 } catch (java.net.URISyntaxException e) {
787 continue;
788 }
789
790 if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700791 info = getApplicationInfo(manager, intent, launcher);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800792 } else {
793 info = getApplicationInfoShortcut(c, launcher, iconTypeIndex,
794 iconPackageIndex, iconResourceIndex, iconIndex);
795 }
796
797 if (info == null) {
798 info = new ApplicationInfo();
799 info.icon = manager.getDefaultActivityIcon();
800 }
801
802 if (info != null) {
803 info.title = c.getString(titleIndex);
804 info.intent = intent;
805
806 info.id = c.getLong(idIndex);
807 container = c.getInt(containerIndex);
808 info.container = container;
809 info.screen = c.getInt(screenIndex);
810 info.cellX = c.getInt(cellXIndex);
811 info.cellY = c.getInt(cellYIndex);
812
813 switch (container) {
814 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
815 desktopItems.add(info);
816 break;
817 default:
818 // Item is in a user folder
819 UserFolderInfo folderInfo =
820 findOrMakeUserFolder(folders, container);
821 folderInfo.add(info);
822 break;
823 }
824 }
825 break;
826 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
827
828 id = c.getLong(idIndex);
829 UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id);
830
831 folderInfo.title = c.getString(titleIndex);
832
833 folderInfo.id = id;
834 container = c.getInt(containerIndex);
835 folderInfo.container = container;
836 folderInfo.screen = c.getInt(screenIndex);
837 folderInfo.cellX = c.getInt(cellXIndex);
838 folderInfo.cellY = c.getInt(cellYIndex);
839
840 switch (container) {
841 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
842 desktopItems.add(folderInfo);
843 break;
844 }
845 break;
846 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
847
848 id = c.getLong(idIndex);
849 LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id);
850
851 intentDescription = c.getString(intentIndex);
852 intent = null;
853 if (intentDescription != null) {
854 try {
Romain Guy1ce1a242009-06-23 17:34:54 -0700855 intent = Intent.parseUri(intentDescription, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800856 } catch (java.net.URISyntaxException e) {
857 // Ignore, a live folder might not have a base intent
858 }
859 }
860
861 liveFolderInfo.title = c.getString(titleIndex);
862 liveFolderInfo.id = id;
863 container = c.getInt(containerIndex);
864 liveFolderInfo.container = container;
865 liveFolderInfo.screen = c.getInt(screenIndex);
866 liveFolderInfo.cellX = c.getInt(cellXIndex);
867 liveFolderInfo.cellY = c.getInt(cellYIndex);
868 liveFolderInfo.uri = Uri.parse(c.getString(uriIndex));
869 liveFolderInfo.baseIntent = intent;
870 liveFolderInfo.displayMode = c.getInt(displayModeIndex);
871
872 loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex,
873 iconResourceIndex, liveFolderInfo);
874
875 switch (container) {
876 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
877 desktopItems.add(liveFolderInfo);
878 break;
879 }
880 break;
881 case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
882 widgetInfo = Widget.makeSearch();
883
884 container = c.getInt(containerIndex);
885 if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700886 e(Launcher.LOG_TAG, "Widget found where container "
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800887 + "!= CONTAINER_DESKTOP ignoring!");
888 continue;
889 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700890
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800891 widgetInfo.id = c.getLong(idIndex);
892 widgetInfo.screen = c.getInt(screenIndex);
893 widgetInfo.container = container;
894 widgetInfo.cellX = c.getInt(cellXIndex);
895 widgetInfo.cellY = c.getInt(cellYIndex);
896
897 desktopItems.add(widgetInfo);
898 break;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700899 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
900 // Read all Launcher-specific widget details
901 int appWidgetId = c.getInt(appWidgetIdIndex);
902 appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
903 appWidgetInfo.id = c.getLong(idIndex);
904 appWidgetInfo.screen = c.getInt(screenIndex);
905 appWidgetInfo.cellX = c.getInt(cellXIndex);
906 appWidgetInfo.cellY = c.getInt(cellYIndex);
907 appWidgetInfo.spanX = c.getInt(spanXIndex);
908 appWidgetInfo.spanY = c.getInt(spanYIndex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800909
910 container = c.getInt(containerIndex);
911 if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700912 e(Launcher.LOG_TAG, "Widget found where container "
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800913 + "!= CONTAINER_DESKTOP -- ignoring!");
914 continue;
915 }
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700916 appWidgetInfo.container = c.getInt(containerIndex);
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700917
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700918 desktopAppWidgets.add(appWidgetInfo);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800919 break;
920 }
921 } catch (Exception e) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700922 w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800923 }
924 }
925 } finally {
926 c.close();
927 }
928
929 if (!mStopped) {
930 launcher.runOnUiThread(new Runnable() {
931 public void run() {
932 launcher.onDesktopItemsLoaded();
933 }
934 });
Romain Guy2fcbd682009-06-11 13:58:26 -0700935 if (mLoadApplications) startApplicationsLoader(launcher, mIsLaunching);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800936 }
937
938 if (!mStopped) {
939 mDesktopItemsLoaded = true;
940 }
941 mRunning = false;
942 }
943 }
944
945 private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex,
946 int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
947
948 int iconType = c.getInt(iconTypeIndex);
949 switch (iconType) {
950 case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
951 String packageName = c.getString(iconPackageIndex);
952 String resourceName = c.getString(iconResourceIndex);
953 PackageManager packageManager = launcher.getPackageManager();
954 try {
955 Resources resources = packageManager.getResourcesForApplication(packageName);
956 final int id = resources.getIdentifier(resourceName, null, null);
957 liveFolderInfo.icon = resources.getDrawable(id);
958 } catch (Exception e) {
959 liveFolderInfo.icon =
960 launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
961 }
962 liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
963 liveFolderInfo.iconResource.packageName = packageName;
964 liveFolderInfo.iconResource.resourceName = resourceName;
965 break;
966 default:
967 liveFolderInfo.icon =
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700968 launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800969 }
970 }
971
972 /**
973 * Finds the user folder defined by the specified id.
974 *
975 * @param id The id of the folder to look for.
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700976 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800977 * @return A UserFolderInfo if the folder exists or null otherwise.
978 */
979 FolderInfo findFolderById(long id) {
980 return mFolders.get(id);
981 }
982
983 void addFolder(FolderInfo info) {
984 mFolders.put(info.id, info);
985 }
986
987 /**
988 * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
989 * new one.
990 */
991 private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
992 // See if a placeholder was created for us already
993 FolderInfo folderInfo = folders.get(id);
994 if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
995 // No placeholder -- create a new instance
996 folderInfo = new UserFolderInfo();
997 folders.put(id, folderInfo);
998 }
999 return (UserFolderInfo) folderInfo;
1000 }
1001
1002 /**
1003 * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
1004 * new one.
1005 */
1006 private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
1007 // See if a placeholder was created for us already
1008 FolderInfo folderInfo = folders.get(id);
1009 if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
1010 // No placeholder -- create a new instance
1011 folderInfo = new LiveFolderInfo();
1012 folders.put(id, folderInfo);
1013 }
1014 return (LiveFolderInfo) folderInfo;
1015 }
1016
1017 /**
1018 * Remove the callback for the cached drawables or we leak the previous
1019 * Home screen on orientation change.
1020 */
1021 void unbind() {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07001022 // Interrupt the applications loader before setting the adapter to null
1023 stopAndWaitForApplicationsLoader();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001024 mApplicationsAdapter = null;
1025 unbindAppDrawables(mApplications);
1026 unbindDrawables(mDesktopItems);
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001027 unbindAppWidgetHostViews(mDesktopAppWidgets);
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001028 unbindCachedIconDrawables();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001029 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001030
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001031 /**
1032 * Remove the callback for the cached drawables or we leak the previous
1033 * Home screen on orientation change.
1034 */
1035 private void unbindDrawables(ArrayList<ItemInfo> desktopItems) {
1036 if (desktopItems != null) {
1037 final int count = desktopItems.size();
1038 for (int i = 0; i < count; i++) {
1039 ItemInfo item = desktopItems.get(i);
1040 switch (item.itemType) {
1041 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
1042 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
1043 ((ApplicationInfo)item).icon.setCallback(null);
1044 break;
1045 }
1046 }
1047 }
1048 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001049
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001050 /**
1051 * Remove the callback for the cached drawables or we leak the previous
1052 * Home screen on orientation change.
1053 */
1054 private void unbindAppDrawables(ArrayList<ApplicationInfo> applications) {
1055 if (applications != null) {
1056 final int count = applications.size();
1057 for (int i = 0; i < count; i++) {
1058 applications.get(i).icon.setCallback(null);
1059 }
1060 }
1061 }
1062
1063 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001064 * Remove any {@link LauncherAppWidgetHostView} references in our widgets.
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001065 */
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001066 private void unbindAppWidgetHostViews(ArrayList<LauncherAppWidgetInfo> appWidgets) {
1067 if (appWidgets != null) {
1068 final int count = appWidgets.size();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001069 for (int i = 0; i < count; i++) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001070 LauncherAppWidgetInfo launcherInfo = appWidgets.get(i);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001071 launcherInfo.hostView = null;
1072 }
1073 }
1074 }
1075
1076 /**
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001077 * Remove the callback for the cached drawables or we leak the previous
1078 * Home screen on orientation change.
1079 */
1080 private void unbindCachedIconDrawables() {
1081 for (ApplicationInfo appInfo : mAppInfoCache.values()) {
1082 appInfo.icon.setCallback(null);
1083 }
1084 }
1085
1086 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001087 * @return The current list of applications
1088 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001089 ApplicationsAdapter getApplicationsAdapter() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001090 return mApplicationsAdapter;
1091 }
1092
1093 /**
1094 * @return The current list of desktop items
1095 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001096 ArrayList<ItemInfo> getDesktopItems() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001097 return mDesktopItems;
1098 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001099
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001100 /**
1101 * @return The current list of desktop items
1102 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001103 ArrayList<LauncherAppWidgetInfo> getDesktopAppWidgets() {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001104 return mDesktopAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001105 }
1106
1107 /**
1108 * Add an item to the desktop
1109 * @param info
1110 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001111 void addDesktopItem(ItemInfo info) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001112 // TODO: write to DB; also check that folder has been added to folders list
1113 mDesktopItems.add(info);
1114 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001115
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001116 /**
1117 * Remove an item from the desktop
1118 * @param info
1119 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001120 void removeDesktopItem(ItemInfo info) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001121 // TODO: write to DB; figure out if we should remove folder from folders list
1122 mDesktopItems.remove(info);
1123 }
1124
1125 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001126 * Add a widget to the desktop
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001127 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001128 void addDesktopAppWidget(LauncherAppWidgetInfo info) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001129 mDesktopAppWidgets.add(info);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001130 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001131
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001132 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001133 * Remove a widget from the desktop
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001134 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001135 void removeDesktopAppWidget(LauncherAppWidgetInfo info) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001136 mDesktopAppWidgets.remove(info);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001137 }
1138
1139 /**
1140 * Make an ApplicationInfo object for an application
1141 */
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -07001142 private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent,
1143 Context context) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001144 final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
1145
1146 if (resolveInfo == null) {
1147 return null;
1148 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001149
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001150 final ApplicationInfo info = new ApplicationInfo();
1151 final ActivityInfo activityInfo = resolveInfo.activityInfo;
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -07001152 info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001153 if (info.title == null || info.title.length() == 0) {
1154 info.title = activityInfo.loadLabel(manager);
1155 }
1156 if (info.title == null) {
1157 info.title = "";
1158 }
1159 info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
1160 return info;
1161 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001162
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001163 /**
1164 * Make an ApplicationInfo object for a sortcut
1165 */
Romain Guy73b979d2009-06-09 12:57:21 -07001166 private ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001167 int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
1168
1169 final ApplicationInfo info = new ApplicationInfo();
1170 info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
1171
1172 int iconType = c.getInt(iconTypeIndex);
1173 switch (iconType) {
1174 case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
1175 String packageName = c.getString(iconPackageIndex);
1176 String resourceName = c.getString(iconResourceIndex);
Romain Guy73b979d2009-06-09 12:57:21 -07001177 PackageManager packageManager = context.getPackageManager();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001178 try {
1179 Resources resources = packageManager.getResourcesForApplication(packageName);
1180 final int id = resources.getIdentifier(resourceName, null, null);
Romain Guy73b979d2009-06-09 12:57:21 -07001181 info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001182 } catch (Exception e) {
1183 info.icon = packageManager.getDefaultActivityIcon();
1184 }
1185 info.iconResource = new Intent.ShortcutIconResource();
1186 info.iconResource.packageName = packageName;
1187 info.iconResource.resourceName = resourceName;
1188 info.customIcon = false;
1189 break;
1190 case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
1191 byte[] data = c.getBlob(iconIndex);
Romain Guyc2ad7a62009-05-14 17:43:39 -07001192 try {
1193 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
1194 info.icon = new FastBitmapDrawable(
Romain Guy73b979d2009-06-09 12:57:21 -07001195 Utilities.createBitmapThumbnail(bitmap, context));
Romain Guyc2ad7a62009-05-14 17:43:39 -07001196 } catch (Exception e) {
Romain Guy73b979d2009-06-09 12:57:21 -07001197 packageManager = context.getPackageManager();
Romain Guyc2ad7a62009-05-14 17:43:39 -07001198 info.icon = packageManager.getDefaultActivityIcon();
1199 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001200 info.filtered = true;
1201 info.customIcon = true;
1202 break;
1203 default:
Romain Guy73b979d2009-06-09 12:57:21 -07001204 info.icon = context.getPackageManager().getDefaultActivityIcon();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001205 info.customIcon = false;
1206 break;
1207 }
1208 return info;
1209 }
1210
1211 /**
1212 * Remove an item from the in-memory represention of a user folder. Does not change the DB.
1213 */
1214 void removeUserFolderItem(UserFolderInfo folder, ItemInfo info) {
1215 //noinspection SuspiciousMethodCalls
1216 folder.contents.remove(info);
1217 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001218
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001219 /**
1220 * Removes a UserFolder from the in-memory list of folders. Does not change the DB.
1221 * @param userFolderInfo
1222 */
1223 void removeUserFolder(UserFolderInfo userFolderInfo) {
1224 mFolders.remove(userFolderInfo.id);
1225 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001226
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001227 /**
1228 * Adds an item to the DB if it was not created previously, or move it to a new
1229 * <container, screen, cellX, cellY>
1230 */
1231 static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
1232 int screen, int cellX, int cellY) {
1233 if (item.container == ItemInfo.NO_ID) {
1234 // From all apps
1235 addItemToDatabase(context, item, container, screen, cellX, cellY, false);
1236 } else {
1237 // From somewhere else
1238 moveItemInDatabase(context, item, container, screen, cellX, cellY);
1239 }
1240 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001241
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001242 /**
1243 * Move an item in the DB to a new <container, screen, cellX, cellY>
1244 */
1245 static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
1246 int cellX, int cellY) {
1247 item.container = container;
1248 item.screen = screen;
1249 item.cellX = cellX;
1250 item.cellY = cellY;
Romain Guy2fcbd682009-06-11 13:58:26 -07001251
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001252 final ContentValues values = new ContentValues();
1253 final ContentResolver cr = context.getContentResolver();
1254
1255 values.put(LauncherSettings.Favorites.CONTAINER, item.container);
1256 values.put(LauncherSettings.Favorites.CELLX, item.cellX);
1257 values.put(LauncherSettings.Favorites.CELLY, item.cellY);
1258 values.put(LauncherSettings.Favorites.SCREEN, item.screen);
1259
1260 cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
1261 }
1262
1263 /**
1264 * Returns true if the shortcuts already exists in the database.
1265 * we identify a shortcut by its title and intent.
1266 */
1267 static boolean shortcutExists(Context context, String title, Intent intent) {
1268 final ContentResolver cr = context.getContentResolver();
1269 Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
1270 new String[] { "title", "intent" }, "title=? and intent=?",
Romain Guy1ce1a242009-06-23 17:34:54 -07001271 new String[] { title, intent.toUri(0) }, null);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001272 boolean result = false;
1273 try {
1274 result = c.moveToFirst();
1275 } finally {
1276 c.close();
1277 }
1278 return result;
1279 }
1280
1281 FolderInfo getFolderById(Context context, long id) {
1282 final ContentResolver cr = context.getContentResolver();
1283 Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
Jeffrey Sharkey591d6d72009-03-27 19:45:21 -07001284 "_id=? and (itemType=? or itemType=?)",
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001285 new String[] { String.valueOf(id),
1286 String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
1287 String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
1288
1289 try {
1290 if (c.moveToFirst()) {
1291 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
1292 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
1293 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
1294 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
1295 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
1296 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
1297
1298 FolderInfo folderInfo = null;
1299 switch (c.getInt(itemTypeIndex)) {
1300 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
1301 folderInfo = findOrMakeUserFolder(mFolders, id);
1302 break;
1303 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
1304 folderInfo = findOrMakeLiveFolder(mFolders, id);
1305 break;
1306 }
1307
1308 folderInfo.title = c.getString(titleIndex);
1309 folderInfo.id = id;
1310 folderInfo.container = c.getInt(containerIndex);
1311 folderInfo.screen = c.getInt(screenIndex);
1312 folderInfo.cellX = c.getInt(cellXIndex);
1313 folderInfo.cellY = c.getInt(cellYIndex);
1314
1315 return folderInfo;
1316 }
1317 } finally {
1318 c.close();
1319 }
1320
1321 return null;
1322 }
1323
1324 /**
1325 * Add an item to the database in a specified container. Sets the container, screen, cellX and
1326 * cellY fields of the item. Also assigns an ID to the item.
1327 */
1328 static void addItemToDatabase(Context context, ItemInfo item, long container,
1329 int screen, int cellX, int cellY, boolean notify) {
1330 item.container = container;
1331 item.screen = screen;
1332 item.cellX = cellX;
1333 item.cellY = cellY;
Romain Guy2fcbd682009-06-11 13:58:26 -07001334
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001335 final ContentValues values = new ContentValues();
1336 final ContentResolver cr = context.getContentResolver();
Romain Guy2fcbd682009-06-11 13:58:26 -07001337
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001338 item.onAddToDatabase(values);
Romain Guy2fcbd682009-06-11 13:58:26 -07001339
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001340 Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
1341 LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
1342
1343 if (result != null) {
1344 item.id = Integer.parseInt(result.getPathSegments().get(1));
1345 }
1346 }
1347
1348 /**
Romain Guy73b979d2009-06-09 12:57:21 -07001349 * Add an item to the database in a specified container. Sets the container, screen, cellX and
1350 * cellY fields of the item. Also assigns an ID to the item.
1351 */
1352 static boolean addGestureToDatabase(Context context, ItemInfo item, boolean notify) {
1353 final ContentValues values = new ContentValues();
1354 final ContentResolver cr = context.getContentResolver();
1355
1356 item.onAddToDatabase(values);
1357
1358 Uri result = cr.insert(notify ? LauncherSettings.Gestures.CONTENT_URI :
1359 LauncherSettings.Gestures.CONTENT_URI_NO_NOTIFICATION, values);
1360
1361 if (result != null) {
1362 item.id = Integer.parseInt(result.getPathSegments().get(1));
1363 }
1364
1365 return result != null;
1366 }
1367
1368 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001369 * Update an item to the database in a specified container.
1370 */
1371 static void updateItemInDatabase(Context context, ItemInfo item) {
1372 final ContentValues values = new ContentValues();
1373 final ContentResolver cr = context.getContentResolver();
1374
1375 item.onAddToDatabase(values);
1376
1377 cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
1378 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001379
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001380 /**
1381 * Removes the specified item from the database
1382 * @param context
1383 * @param item
1384 */
1385 static void deleteItemFromDatabase(Context context, ItemInfo item) {
1386 final ContentResolver cr = context.getContentResolver();
1387
1388 cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null);
1389 }
1390
1391
1392 /**
1393 * Remove the contents of the specified folder from the database
1394 */
1395 static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
1396 final ContentResolver cr = context.getContentResolver();
1397
1398 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
1399 cr.delete(LauncherSettings.Favorites.CONTENT_URI,
1400 LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
1401 }
Romain Guy73b979d2009-06-09 12:57:21 -07001402
1403 static void deleteGestureFromDatabase(Context context, ItemInfo item) {
1404 final ContentResolver cr = context.getContentResolver();
1405
1406 cr.delete(LauncherSettings.Gestures.getContentUri(item.id, false), null, null);
1407 }
1408
1409 static void updateGestureInDatabase(Context context, ItemInfo item) {
1410 final ContentValues values = new ContentValues();
1411 final ContentResolver cr = context.getContentResolver();
1412
1413 item.onAddToDatabase(values);
1414
1415 cr.update(LauncherSettings.Gestures.getContentUri(item.id, false), values, null, null);
1416 }
1417
1418
1419 ApplicationInfo queryGesture(Context context, String id) {
1420 final ContentResolver contentResolver = context.getContentResolver();
1421 final PackageManager manager = context.getPackageManager();
1422 final Cursor c = contentResolver.query(
1423 LauncherSettings.Gestures.CONTENT_URI, null, LauncherSettings.Gestures._ID + "=?",
1424 new String[] { id }, null);
1425
1426 ApplicationInfo info = null;
1427
1428 try {
1429 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures._ID);
1430 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.INTENT);
1431 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.TITLE);
1432 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_TYPE);
1433 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON);
1434 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_PACKAGE);
1435 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_RESOURCE);
1436 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ITEM_TYPE);
1437
1438 String intentDescription;
1439 Intent intent;
1440
1441 if (c.moveToNext()) {
1442 int itemType = c.getInt(itemTypeIndex);
1443
1444 switch (itemType) {
1445 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
1446 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
1447 intentDescription = c.getString(intentIndex);
1448 try {
Romain Guy1ce1a242009-06-23 17:34:54 -07001449 intent = Intent.parseUri(intentDescription, 0);
Romain Guy73b979d2009-06-09 12:57:21 -07001450 } catch (java.net.URISyntaxException e) {
1451 return null;
1452 }
1453
1454 if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
1455 info = getApplicationInfo(manager, intent, context);
1456 } else {
1457 info = getApplicationInfoShortcut(c, context, iconTypeIndex,
1458 iconPackageIndex, iconResourceIndex, iconIndex);
1459 }
1460
1461 if (info == null) {
1462 info = new ApplicationInfo();
1463 info.icon = manager.getDefaultActivityIcon();
1464 }
1465
1466 info.isGesture = true;
1467 info.title = c.getString(titleIndex);
1468 info.intent = intent;
1469 info.id = c.getLong(idIndex);
1470
1471 break;
1472 }
1473 }
1474 } catch (Exception e) {
1475 w(LOG_TAG, "Could not load gesture with name " + id);
1476 } finally {
1477 c.close();
1478 }
1479
1480 return info;
1481 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001482}