blob: a1398d437c4de2b83673026a150ddd4fa59e6d2d [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
247 if (changed) {
248 adapter.sort(new ApplicationInfoComparator());
249 adapter.notifyDataSetChanged();
250 }
251 }
252 }
253
254 private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700255 ApplicationInfo applicationInfo, Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700256
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700257 updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo, context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700258
259 ComponentName componentName = new ComponentName(
260 info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
261 mAppInfoCache.put(componentName, applicationInfo);
262 }
263
264 synchronized void syncPackage(Launcher launcher, String packageName) {
265 if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
Romain Guy2fcbd682009-06-11 13:58:26 -0700266 startApplicationsLoader(launcher, false);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700267 return;
268 }
269
270 if (packageName != null && packageName.length() > 0) {
271 final PackageManager packageManager = launcher.getPackageManager();
272 final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
273
274 if (matches.size() > 0) {
275 final ApplicationsAdapter adapter = mApplicationsAdapter;
276
277 // Find disabled activities and remove them from the adapter
278 boolean removed = removeDisabledActivities(packageName, matches, adapter);
279 // Find enable activities and add them to the adapter
280 // Also updates existing activities with new labels/icons
281 boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher);
282
283 if (added || removed) {
284 adapter.sort(new ApplicationInfoComparator());
285 adapter.notifyDataSetChanged();
286 }
287 }
288 }
289 }
290
291 private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager,
292 String packageName) {
293
294 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
295 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
296
297 final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
298 final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
299
300 if (apps != null) {
301 // Find all activities that match the packageName
302 int count = apps.size();
303 for (int i = 0; i < count; i++) {
304 final ResolveInfo info = apps.get(i);
305 final ActivityInfo activityInfo = info.activityInfo;
306 if (packageName.equals(activityInfo.packageName)) {
307 matches.add(info);
308 }
309 }
310 }
311
312 return matches;
313 }
314
315 private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches,
316 ApplicationsAdapter adapter, Launcher launcher) {
317
318 final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>();
319 final int count = matches.size();
320
321 boolean changed = false;
322
323 for (int i = 0; i < count; i++) {
324 final ResolveInfo info = matches.get(i);
325 final ApplicationInfo applicationInfo = findIntent(adapter,
326 info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
327 if (applicationInfo == null) {
328 toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(),
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700329 mAppInfoCache, info, launcher));
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700330 changed = true;
331 } else {
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700332 updateAndCacheApplicationInfo(
333 launcher.getPackageManager(), info, applicationInfo, launcher);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700334 changed = true;
335 }
336 }
337
338 for (ApplicationInfo info : toAdd) {
339 adapter.setNotifyOnChange(false);
340 adapter.add(info);
341 }
342
343 return changed;
344 }
345
346 private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches,
347 ApplicationsAdapter adapter) {
348
349 final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
350 final int count = adapter.getCount();
351
352 boolean changed = false;
353
354 for (int i = 0; i < count; i++) {
355 final ApplicationInfo applicationInfo = adapter.getItem(i);
356 final Intent intent = applicationInfo.intent;
357 final ComponentName component = intent.getComponent();
358 if (packageName.equals(component.getPackageName())) {
359 if (!findIntent(matches, component)) {
360 toRemove.add(applicationInfo);
361 changed = true;
362 }
363 }
364 }
365
366 final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
367 for (ApplicationInfo info : toRemove) {
368 adapter.setNotifyOnChange(false);
369 adapter.remove(info);
370 cache.remove(info.intent.getComponent());
371 }
372
373 return changed;
374 }
375
376 private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName,
377 String name) {
378
379 final int count = adapter.getCount();
380 for (int i = 0; i < count; i++) {
381 final ApplicationInfo applicationInfo = adapter.getItem(i);
382 final Intent intent = applicationInfo.intent;
383 final ComponentName component = intent.getComponent();
384 if (packageName.equals(component.getPackageName()) &&
385 name.equals(component.getClassName())) {
386 return applicationInfo;
387 }
388 }
389
390 return null;
391 }
392
393 private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) {
394 final String className = component.getClassName();
395 for (ResolveInfo info : apps) {
396 final ActivityInfo activityInfo = info.activityInfo;
397 if (activityInfo.name.equals(className)) {
398 return true;
399 }
400 }
401 return false;
402 }
403
404 Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) {
405 final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0);
406 if (resolveInfo == null) {
407 return null;
408 }
409
410 ComponentName componentName = new ComponentName(
411 resolveInfo.activityInfo.applicationInfo.packageName,
412 resolveInfo.activityInfo.name);
413 ApplicationInfo application = mAppInfoCache.get(componentName);
414
415 if (application == null) {
416 return resolveInfo.activityInfo.loadIcon(manager);
417 }
418
419 return application.icon;
420 }
421
422 private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700423 HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info,
424 Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700425
426 ComponentName componentName = new ComponentName(
427 info.activityInfo.applicationInfo.packageName,
428 info.activityInfo.name);
429 ApplicationInfo application = appInfoCache.get(componentName);
430
431 if (application == null) {
432 application = new ApplicationInfo();
433 application.container = ItemInfo.NO_ID;
434
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700435 updateApplicationInfoTitleAndIcon(manager, info, application, context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700436
437 application.setActivity(componentName,
438 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
439
440 appInfoCache.put(componentName, application);
441 }
442
443 return application;
444 }
445
446 private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info,
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700447 ApplicationInfo application, Context context) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700448
449 application.title = info.loadLabel(manager);
450 if (application.title == null) {
451 application.title = info.activityInfo.name;
452 }
453
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700454 application.icon =
455 Utilities.createIconThumbnail(info.activityInfo.loadIcon(manager), context);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700456 application.filtered = false;
457 }
458
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800459 private class ApplicationsLoader implements Runnable {
460 private final WeakReference<Launcher> mLauncher;
461
462 private volatile boolean mStopped;
463 private volatile boolean mRunning;
Romain Guy2fcbd682009-06-11 13:58:26 -0700464 private final boolean mIsLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800465
Romain Guy2fcbd682009-06-11 13:58:26 -0700466 ApplicationsLoader(Launcher launcher, boolean isLaunching) {
467 mIsLaunching = isLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800468 mLauncher = new WeakReference<Launcher>(launcher);
469 }
470
471 void stop() {
472 mStopped = true;
473 }
474
475 boolean isRunning() {
476 return mRunning;
477 }
478
479 public void run() {
480 mRunning = true;
481
Romain Guy2fcbd682009-06-11 13:58:26 -0700482 // Elevate priority when Home launches for the first time to avoid
483 // starving at boot time. Staring at a blank home is not cool.
484 android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT :
485 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800486
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700487 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800488 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
489
490 final Launcher launcher = mLauncher.get();
491 final PackageManager manager = launcher.getPackageManager();
492 final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
493
494 if (apps != null && !mStopped) {
495 final int count = apps.size();
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700496 // Can be set to null on the UI thread by the unbind() method
497 // Do not access without checking for null first
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800498 final ApplicationsAdapter applicationList = mApplicationsAdapter;
499
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700500 ChangeNotifier action = new ChangeNotifier(applicationList, true);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700501 final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800502
503 for (int i = 0; i < count && !mStopped; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800504 ResolveInfo info = apps.get(i);
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700505 ApplicationInfo application =
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700506 makeAndCacheApplicationInfo(manager, appInfoCache, info, launcher);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800507
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700508 if (action.add(application) && !mStopped) {
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700509 launcher.runOnUiThread(action);
510 action = new ChangeNotifier(applicationList, false);
511 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800512 }
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700513
514 launcher.runOnUiThread(action);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800515 }
516
517 if (!mStopped) {
518 mApplicationsLoaded = true;
519 }
520 mRunning = false;
521 }
522 }
523
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700524 private static class ChangeNotifier implements Runnable {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800525 private final ApplicationsAdapter mApplicationList;
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700526 private final ArrayList<ApplicationInfo> mBuffer;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800527
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700528 private boolean mFirst = true;
529
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700530 ChangeNotifier(ApplicationsAdapter applicationList, boolean first) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800531 mApplicationList = applicationList;
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700532 mFirst = first;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800533 mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE);
534 }
535
536 public void run() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800537 final ApplicationsAdapter applicationList = mApplicationList;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700538 // Can be set to null on the UI thread by the unbind() method
539 if (applicationList == null) return;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800540
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700541 if (mFirst) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800542 applicationList.setNotifyOnChange(false);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700543 applicationList.clear();
544 mFirst = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800545 }
546
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700547 final ArrayList<ApplicationInfo> buffer = mBuffer;
548 final int count = buffer.size();
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700549
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700550 for (int i = 0; i < count; i++) {
551 applicationList.setNotifyOnChange(false);
552 applicationList.add(buffer.get(i));
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700553 }
554
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700555 buffer.clear();
556
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700557 applicationList.sort(new ApplicationInfoComparator());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800558 applicationList.notifyDataSetChanged();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800559 }
560
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700561 boolean add(ApplicationInfo application) {
562 final ArrayList<ApplicationInfo> buffer = mBuffer;
563 buffer.add(application);
564 return buffer.size() >= UI_NOTIFICATION_RATE;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800565 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700566 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800567
Romain Guy73b979d2009-06-09 12:57:21 -0700568 static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700569 public final int compare(ApplicationInfo a, ApplicationInfo b) {
570 return sCollator.compare(a.title.toString(), b.title.toString());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800571 }
572 }
573
574 boolean isDesktopLoaded() {
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700575 return mDesktopItems != null && mDesktopAppWidgets != null && mDesktopItemsLoaded;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800576 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700577
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800578 /**
579 * Loads all of the items on the desktop, in folders, or in the dock.
580 * These can be apps, shortcuts or widgets
581 */
582 void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
583 boolean loadApplications) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700584 if (DEBUG_LOADERS) d(LOG_TAG, "loading user items");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800585
586 if (isLaunching && isDesktopLoaded()) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700587 if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return");
Romain Guy2fcbd682009-06-11 13:58:26 -0700588 if (loadApplications) startApplicationsLoader(launcher, true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800589 // We have already loaded our data from the DB
590 launcher.onDesktopItemsLoaded();
591 return;
592 }
593
594 if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
Romain Guyfedc4fc2009-03-27 20:48:20 -0700595 if (DEBUG_LOADERS) d(LOG_TAG, " --> stopping workspace loader");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800596 mDesktopItemsLoader.stop();
597 // Wait for the currently running thread to finish, this can take a little
598 // time but it should be well below the timeout limit
599 try {
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700600 mDesktopLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800601 } catch (InterruptedException e) {
602 // Empty
603 }
Romain Guyfedc4fc2009-03-27 20:48:20 -0700604
605 // If the thread we are interrupting was tasked to load the list of
606 // applications make sure we keep that information in the new loader
607 // spawned below
608 // note: we don't apply this to localeChanged because the thread can
609 // only be stopped *after* the localeChanged handling has occured
610 loadApplications = mDesktopItemsLoader.mLoadApplications;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800611 }
612
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700613 if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader");
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800614 mDesktopItemsLoaded = false;
Romain Guy2fcbd682009-06-11 13:58:26 -0700615 mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications,
616 isLaunching);
The Android Open Source Projectca9475f2009-03-13 13:04:24 -0700617 mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
618 mDesktopLoaderThread.start();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800619 }
620
621 private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
622 final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
Romain Guy73b979d2009-06-09 12:57:21 -0700623 new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800624 LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
625 null, null, null);
626
Romain Guy73b979d2009-06-09 12:57:21 -0700627 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800628 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
629 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
630 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
631
632 // boolean changed = false;
633
634 try {
635 while (c.moveToNext()) {
636 try {
637 if (c.getInt(itemTypeIndex) !=
638 LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
639 continue;
640 }
641
642 final String intentUri = c.getString(intentIndex);
643 if (intentUri != null) {
Romain Guy1ce1a242009-06-23 17:34:54 -0700644 final Intent shortcut = Intent.parseUri(intentUri, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800645 if (Intent.ACTION_MAIN.equals(shortcut.getAction())) {
646 final ComponentName name = shortcut.getComponent();
647 if (name != null) {
648 final ActivityInfo activityInfo = manager.getActivityInfo(name, 0);
649 final String title = c.getString(titleIndex);
650 String label = getLabel(manager, activityInfo);
651
652 if (title == null || !title.equals(label)) {
653 final ContentValues values = new ContentValues();
654 values.put(LauncherSettings.Favorites.TITLE, label);
655
Romain Guyfedc4fc2009-03-27 20:48:20 -0700656 resolver.update(
657 LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800658 values, "_id=?",
659 new String[] { String.valueOf(c.getLong(idIndex)) });
660
661 // changed = true;
662 }
663 }
664 }
665 }
666 } catch (URISyntaxException e) {
667 // Ignore
668 } catch (PackageManager.NameNotFoundException e) {
669 // Ignore
670 }
671 }
672 } finally {
673 c.close();
674 }
675
676 // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null);
677 }
678
679 private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
680 String label = activityInfo.loadLabel(manager).toString();
681 if (label == null) {
682 label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
683 if (label == null) {
684 label = activityInfo.name;
685 }
686 }
687 return label;
688 }
689
690 private class DesktopItemsLoader implements Runnable {
691 private volatile boolean mStopped;
692 private volatile boolean mRunning;
693
694 private final WeakReference<Launcher> mLauncher;
695 private final boolean mLocaleChanged;
696 private final boolean mLoadApplications;
Romain Guy2fcbd682009-06-11 13:58:26 -0700697 private final boolean mIsLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800698
Romain Guy2fcbd682009-06-11 13:58:26 -0700699 DesktopItemsLoader(Launcher launcher, boolean localeChanged, boolean loadApplications,
700 boolean isLaunching) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800701 mLoadApplications = loadApplications;
Romain Guy2fcbd682009-06-11 13:58:26 -0700702 mIsLaunching = isLaunching;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800703 mLauncher = new WeakReference<Launcher>(launcher);
704 mLocaleChanged = localeChanged;
705 }
706
707 void stop() {
708 mStopped = true;
709 }
710
711 boolean isRunning() {
712 return mRunning;
713 }
714
715 public void run() {
716 mRunning = true;
717
Romain Guy2fcbd682009-06-11 13:58:26 -0700718 android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
719
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800720 final Launcher launcher = mLauncher.get();
721 final ContentResolver contentResolver = launcher.getContentResolver();
722 final PackageManager manager = launcher.getPackageManager();
723
724 if (mLocaleChanged) {
725 updateShortcutLabels(contentResolver, manager);
726 }
727
728 mDesktopItems = new ArrayList<ItemInfo>();
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700729 mDesktopAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800730 mFolders = new HashMap<Long, FolderInfo>();
731
732 final ArrayList<ItemInfo> desktopItems = mDesktopItems;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700733 final ArrayList<LauncherAppWidgetInfo> desktopAppWidgets = mDesktopAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800734
735 final Cursor c = contentResolver.query(
736 LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
737
738 try {
Romain Guy73b979d2009-06-09 12:57:21 -0700739 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800740 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
741 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
742 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
743 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
744 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
745 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
746 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
747 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700748 final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800749 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
750 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
751 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
752 final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
753 final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
754 final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
755 final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
756
757 ApplicationInfo info;
758 String intentDescription;
759 Widget widgetInfo;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700760 LauncherAppWidgetInfo appWidgetInfo;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800761 int container;
762 long id;
763 Intent intent;
764
765 final HashMap<Long, FolderInfo> folders = mFolders;
766
767 while (!mStopped && c.moveToNext()) {
768 try {
769 int itemType = c.getInt(itemTypeIndex);
770
771 switch (itemType) {
772 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
773 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
774 intentDescription = c.getString(intentIndex);
775 try {
Romain Guy1ce1a242009-06-23 17:34:54 -0700776 intent = Intent.parseUri(intentDescription, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800777 } catch (java.net.URISyntaxException e) {
778 continue;
779 }
780
781 if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -0700782 info = getApplicationInfo(manager, intent, launcher);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800783 } else {
784 info = getApplicationInfoShortcut(c, launcher, iconTypeIndex,
785 iconPackageIndex, iconResourceIndex, iconIndex);
786 }
787
788 if (info == null) {
789 info = new ApplicationInfo();
790 info.icon = manager.getDefaultActivityIcon();
791 }
792
793 if (info != null) {
794 info.title = c.getString(titleIndex);
795 info.intent = intent;
796
797 info.id = c.getLong(idIndex);
798 container = c.getInt(containerIndex);
799 info.container = container;
800 info.screen = c.getInt(screenIndex);
801 info.cellX = c.getInt(cellXIndex);
802 info.cellY = c.getInt(cellYIndex);
803
804 switch (container) {
805 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
806 desktopItems.add(info);
807 break;
808 default:
809 // Item is in a user folder
810 UserFolderInfo folderInfo =
811 findOrMakeUserFolder(folders, container);
812 folderInfo.add(info);
813 break;
814 }
815 }
816 break;
817 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
818
819 id = c.getLong(idIndex);
820 UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id);
821
822 folderInfo.title = c.getString(titleIndex);
823
824 folderInfo.id = id;
825 container = c.getInt(containerIndex);
826 folderInfo.container = container;
827 folderInfo.screen = c.getInt(screenIndex);
828 folderInfo.cellX = c.getInt(cellXIndex);
829 folderInfo.cellY = c.getInt(cellYIndex);
830
831 switch (container) {
832 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
833 desktopItems.add(folderInfo);
834 break;
835 }
836 break;
837 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
838
839 id = c.getLong(idIndex);
840 LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id);
841
842 intentDescription = c.getString(intentIndex);
843 intent = null;
844 if (intentDescription != null) {
845 try {
Romain Guy1ce1a242009-06-23 17:34:54 -0700846 intent = Intent.parseUri(intentDescription, 0);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800847 } catch (java.net.URISyntaxException e) {
848 // Ignore, a live folder might not have a base intent
849 }
850 }
851
852 liveFolderInfo.title = c.getString(titleIndex);
853 liveFolderInfo.id = id;
854 container = c.getInt(containerIndex);
855 liveFolderInfo.container = container;
856 liveFolderInfo.screen = c.getInt(screenIndex);
857 liveFolderInfo.cellX = c.getInt(cellXIndex);
858 liveFolderInfo.cellY = c.getInt(cellYIndex);
859 liveFolderInfo.uri = Uri.parse(c.getString(uriIndex));
860 liveFolderInfo.baseIntent = intent;
861 liveFolderInfo.displayMode = c.getInt(displayModeIndex);
862
863 loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex,
864 iconResourceIndex, liveFolderInfo);
865
866 switch (container) {
867 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
868 desktopItems.add(liveFolderInfo);
869 break;
870 }
871 break;
872 case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
873 widgetInfo = Widget.makeSearch();
874
875 container = c.getInt(containerIndex);
876 if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700877 e(Launcher.LOG_TAG, "Widget found where container "
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800878 + "!= CONTAINER_DESKTOP ignoring!");
879 continue;
880 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700881
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800882 widgetInfo.id = c.getLong(idIndex);
883 widgetInfo.screen = c.getInt(screenIndex);
884 widgetInfo.container = container;
885 widgetInfo.cellX = c.getInt(cellXIndex);
886 widgetInfo.cellY = c.getInt(cellYIndex);
887
888 desktopItems.add(widgetInfo);
889 break;
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700890 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
891 // Read all Launcher-specific widget details
892 int appWidgetId = c.getInt(appWidgetIdIndex);
893 appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
894 appWidgetInfo.id = c.getLong(idIndex);
895 appWidgetInfo.screen = c.getInt(screenIndex);
896 appWidgetInfo.cellX = c.getInt(cellXIndex);
897 appWidgetInfo.cellY = c.getInt(cellYIndex);
898 appWidgetInfo.spanX = c.getInt(spanXIndex);
899 appWidgetInfo.spanY = c.getInt(spanYIndex);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800900
901 container = c.getInt(containerIndex);
902 if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700903 e(Launcher.LOG_TAG, "Widget found where container "
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800904 + "!= CONTAINER_DESKTOP -- ignoring!");
905 continue;
906 }
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700907 appWidgetInfo.container = c.getInt(containerIndex);
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700908
The Android Open Source Project7376fae2009-03-11 12:11:58 -0700909 desktopAppWidgets.add(appWidgetInfo);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800910 break;
911 }
912 } catch (Exception e) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -0700913 w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800914 }
915 }
916 } finally {
917 c.close();
918 }
919
920 if (!mStopped) {
921 launcher.runOnUiThread(new Runnable() {
922 public void run() {
923 launcher.onDesktopItemsLoaded();
924 }
925 });
Romain Guy2fcbd682009-06-11 13:58:26 -0700926 if (mLoadApplications) startApplicationsLoader(launcher, mIsLaunching);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800927 }
928
929 if (!mStopped) {
930 mDesktopItemsLoaded = true;
931 }
932 mRunning = false;
933 }
934 }
935
936 private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex,
937 int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
938
939 int iconType = c.getInt(iconTypeIndex);
940 switch (iconType) {
941 case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
942 String packageName = c.getString(iconPackageIndex);
943 String resourceName = c.getString(iconResourceIndex);
944 PackageManager packageManager = launcher.getPackageManager();
945 try {
946 Resources resources = packageManager.getResourcesForApplication(packageName);
947 final int id = resources.getIdentifier(resourceName, null, null);
948 liveFolderInfo.icon = resources.getDrawable(id);
949 } catch (Exception e) {
950 liveFolderInfo.icon =
951 launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
952 }
953 liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
954 liveFolderInfo.iconResource.packageName = packageName;
955 liveFolderInfo.iconResource.resourceName = resourceName;
956 break;
957 default:
958 liveFolderInfo.icon =
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700959 launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800960 }
961 }
962
963 /**
964 * Finds the user folder defined by the specified id.
965 *
966 * @param id The id of the folder to look for.
The Android Open Source Projectbc219c32009-03-09 11:52:14 -0700967 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800968 * @return A UserFolderInfo if the folder exists or null otherwise.
969 */
970 FolderInfo findFolderById(long id) {
971 return mFolders.get(id);
972 }
973
974 void addFolder(FolderInfo info) {
975 mFolders.put(info.id, info);
976 }
977
978 /**
979 * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
980 * new one.
981 */
982 private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
983 // See if a placeholder was created for us already
984 FolderInfo folderInfo = folders.get(id);
985 if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
986 // No placeholder -- create a new instance
987 folderInfo = new UserFolderInfo();
988 folders.put(id, folderInfo);
989 }
990 return (UserFolderInfo) folderInfo;
991 }
992
993 /**
994 * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
995 * new one.
996 */
997 private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
998 // See if a placeholder was created for us already
999 FolderInfo folderInfo = folders.get(id);
1000 if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
1001 // No placeholder -- create a new instance
1002 folderInfo = new LiveFolderInfo();
1003 folders.put(id, folderInfo);
1004 }
1005 return (LiveFolderInfo) folderInfo;
1006 }
1007
1008 /**
1009 * Remove the callback for the cached drawables or we leak the previous
1010 * Home screen on orientation change.
1011 */
1012 void unbind() {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07001013 // Interrupt the applications loader before setting the adapter to null
1014 stopAndWaitForApplicationsLoader();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001015 mApplicationsAdapter = null;
1016 unbindAppDrawables(mApplications);
1017 unbindDrawables(mDesktopItems);
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001018 unbindAppWidgetHostViews(mDesktopAppWidgets);
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001019 unbindCachedIconDrawables();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001020 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001021
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001022 /**
1023 * Remove the callback for the cached drawables or we leak the previous
1024 * Home screen on orientation change.
1025 */
1026 private void unbindDrawables(ArrayList<ItemInfo> desktopItems) {
1027 if (desktopItems != null) {
1028 final int count = desktopItems.size();
1029 for (int i = 0; i < count; i++) {
1030 ItemInfo item = desktopItems.get(i);
1031 switch (item.itemType) {
1032 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
1033 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
1034 ((ApplicationInfo)item).icon.setCallback(null);
1035 break;
1036 }
1037 }
1038 }
1039 }
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001040
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001041 /**
1042 * Remove the callback for the cached drawables or we leak the previous
1043 * Home screen on orientation change.
1044 */
1045 private void unbindAppDrawables(ArrayList<ApplicationInfo> applications) {
1046 if (applications != null) {
1047 final int count = applications.size();
1048 for (int i = 0; i < count; i++) {
1049 applications.get(i).icon.setCallback(null);
1050 }
1051 }
1052 }
1053
1054 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001055 * Remove any {@link LauncherAppWidgetHostView} references in our widgets.
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001056 */
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001057 private void unbindAppWidgetHostViews(ArrayList<LauncherAppWidgetInfo> appWidgets) {
1058 if (appWidgets != null) {
1059 final int count = appWidgets.size();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001060 for (int i = 0; i < count; i++) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001061 LauncherAppWidgetInfo launcherInfo = appWidgets.get(i);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001062 launcherInfo.hostView = null;
1063 }
1064 }
1065 }
1066
1067 /**
The Android Open Source Projectbc219c32009-03-09 11:52:14 -07001068 * Remove the callback for the cached drawables or we leak the previous
1069 * Home screen on orientation change.
1070 */
1071 private void unbindCachedIconDrawables() {
1072 for (ApplicationInfo appInfo : mAppInfoCache.values()) {
1073 appInfo.icon.setCallback(null);
1074 }
1075 }
1076
1077 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001078 * @return The current list of applications
1079 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001080 ApplicationsAdapter getApplicationsAdapter() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001081 return mApplicationsAdapter;
1082 }
1083
1084 /**
1085 * @return The current list of desktop items
1086 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001087 ArrayList<ItemInfo> getDesktopItems() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001088 return mDesktopItems;
1089 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001090
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001091 /**
1092 * @return The current list of desktop items
1093 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001094 ArrayList<LauncherAppWidgetInfo> getDesktopAppWidgets() {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001095 return mDesktopAppWidgets;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001096 }
1097
1098 /**
1099 * Add an item to the desktop
1100 * @param info
1101 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001102 void addDesktopItem(ItemInfo info) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001103 // TODO: write to DB; also check that folder has been added to folders list
1104 mDesktopItems.add(info);
1105 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001106
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001107 /**
1108 * Remove an item from the desktop
1109 * @param info
1110 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001111 void removeDesktopItem(ItemInfo info) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001112 // TODO: write to DB; figure out if we should remove folder from folders list
1113 mDesktopItems.remove(info);
1114 }
1115
1116 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001117 * Add a widget to the desktop
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001118 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001119 void addDesktopAppWidget(LauncherAppWidgetInfo info) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001120 mDesktopAppWidgets.add(info);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001121 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001122
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001123 /**
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001124 * Remove a widget from the desktop
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001125 */
The Android Open Source Projectca9475f2009-03-13 13:04:24 -07001126 void removeDesktopAppWidget(LauncherAppWidgetInfo info) {
The Android Open Source Project7376fae2009-03-11 12:11:58 -07001127 mDesktopAppWidgets.remove(info);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001128 }
1129
1130 /**
1131 * Make an ApplicationInfo object for an application
1132 */
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -07001133 private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent,
1134 Context context) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001135 final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
1136
1137 if (resolveInfo == null) {
1138 return null;
1139 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001140
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001141 final ApplicationInfo info = new ApplicationInfo();
1142 final ActivityInfo activityInfo = resolveInfo.activityInfo;
Mitsuru Oshima583ed3b2009-05-12 19:19:10 -07001143 info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001144 if (info.title == null || info.title.length() == 0) {
1145 info.title = activityInfo.loadLabel(manager);
1146 }
1147 if (info.title == null) {
1148 info.title = "";
1149 }
1150 info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
1151 return info;
1152 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001153
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001154 /**
1155 * Make an ApplicationInfo object for a sortcut
1156 */
Romain Guy73b979d2009-06-09 12:57:21 -07001157 private ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001158 int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
1159
1160 final ApplicationInfo info = new ApplicationInfo();
1161 info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
1162
1163 int iconType = c.getInt(iconTypeIndex);
1164 switch (iconType) {
1165 case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
1166 String packageName = c.getString(iconPackageIndex);
1167 String resourceName = c.getString(iconResourceIndex);
Romain Guy73b979d2009-06-09 12:57:21 -07001168 PackageManager packageManager = context.getPackageManager();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001169 try {
1170 Resources resources = packageManager.getResourcesForApplication(packageName);
1171 final int id = resources.getIdentifier(resourceName, null, null);
Romain Guy73b979d2009-06-09 12:57:21 -07001172 info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001173 } catch (Exception e) {
1174 info.icon = packageManager.getDefaultActivityIcon();
1175 }
1176 info.iconResource = new Intent.ShortcutIconResource();
1177 info.iconResource.packageName = packageName;
1178 info.iconResource.resourceName = resourceName;
1179 info.customIcon = false;
1180 break;
1181 case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
1182 byte[] data = c.getBlob(iconIndex);
Romain Guyc2ad7a62009-05-14 17:43:39 -07001183 try {
1184 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
1185 info.icon = new FastBitmapDrawable(
Romain Guy73b979d2009-06-09 12:57:21 -07001186 Utilities.createBitmapThumbnail(bitmap, context));
Romain Guyc2ad7a62009-05-14 17:43:39 -07001187 } catch (Exception e) {
Romain Guy73b979d2009-06-09 12:57:21 -07001188 packageManager = context.getPackageManager();
Romain Guyc2ad7a62009-05-14 17:43:39 -07001189 info.icon = packageManager.getDefaultActivityIcon();
1190 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001191 info.filtered = true;
1192 info.customIcon = true;
1193 break;
1194 default:
Romain Guy73b979d2009-06-09 12:57:21 -07001195 info.icon = context.getPackageManager().getDefaultActivityIcon();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001196 info.customIcon = false;
1197 break;
1198 }
1199 return info;
1200 }
1201
1202 /**
1203 * Remove an item from the in-memory represention of a user folder. Does not change the DB.
1204 */
1205 void removeUserFolderItem(UserFolderInfo folder, ItemInfo info) {
1206 //noinspection SuspiciousMethodCalls
1207 folder.contents.remove(info);
1208 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001209
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001210 /**
1211 * Removes a UserFolder from the in-memory list of folders. Does not change the DB.
1212 * @param userFolderInfo
1213 */
1214 void removeUserFolder(UserFolderInfo userFolderInfo) {
1215 mFolders.remove(userFolderInfo.id);
1216 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001217
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001218 /**
1219 * Adds an item to the DB if it was not created previously, or move it to a new
1220 * <container, screen, cellX, cellY>
1221 */
1222 static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
1223 int screen, int cellX, int cellY) {
1224 if (item.container == ItemInfo.NO_ID) {
1225 // From all apps
1226 addItemToDatabase(context, item, container, screen, cellX, cellY, false);
1227 } else {
1228 // From somewhere else
1229 moveItemInDatabase(context, item, container, screen, cellX, cellY);
1230 }
1231 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001232
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001233 /**
1234 * Move an item in the DB to a new <container, screen, cellX, cellY>
1235 */
1236 static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
1237 int cellX, int cellY) {
1238 item.container = container;
1239 item.screen = screen;
1240 item.cellX = cellX;
1241 item.cellY = cellY;
Romain Guy2fcbd682009-06-11 13:58:26 -07001242
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001243 final ContentValues values = new ContentValues();
1244 final ContentResolver cr = context.getContentResolver();
1245
1246 values.put(LauncherSettings.Favorites.CONTAINER, item.container);
1247 values.put(LauncherSettings.Favorites.CELLX, item.cellX);
1248 values.put(LauncherSettings.Favorites.CELLY, item.cellY);
1249 values.put(LauncherSettings.Favorites.SCREEN, item.screen);
1250
1251 cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
1252 }
1253
1254 /**
1255 * Returns true if the shortcuts already exists in the database.
1256 * we identify a shortcut by its title and intent.
1257 */
1258 static boolean shortcutExists(Context context, String title, Intent intent) {
1259 final ContentResolver cr = context.getContentResolver();
1260 Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
1261 new String[] { "title", "intent" }, "title=? and intent=?",
Romain Guy1ce1a242009-06-23 17:34:54 -07001262 new String[] { title, intent.toUri(0) }, null);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001263 boolean result = false;
1264 try {
1265 result = c.moveToFirst();
1266 } finally {
1267 c.close();
1268 }
1269 return result;
1270 }
1271
1272 FolderInfo getFolderById(Context context, long id) {
1273 final ContentResolver cr = context.getContentResolver();
1274 Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
Jeffrey Sharkey591d6d72009-03-27 19:45:21 -07001275 "_id=? and (itemType=? or itemType=?)",
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001276 new String[] { String.valueOf(id),
1277 String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
1278 String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
1279
1280 try {
1281 if (c.moveToFirst()) {
1282 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
1283 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
1284 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
1285 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
1286 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
1287 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
1288
1289 FolderInfo folderInfo = null;
1290 switch (c.getInt(itemTypeIndex)) {
1291 case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
1292 folderInfo = findOrMakeUserFolder(mFolders, id);
1293 break;
1294 case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
1295 folderInfo = findOrMakeLiveFolder(mFolders, id);
1296 break;
1297 }
1298
1299 folderInfo.title = c.getString(titleIndex);
1300 folderInfo.id = id;
1301 folderInfo.container = c.getInt(containerIndex);
1302 folderInfo.screen = c.getInt(screenIndex);
1303 folderInfo.cellX = c.getInt(cellXIndex);
1304 folderInfo.cellY = c.getInt(cellYIndex);
1305
1306 return folderInfo;
1307 }
1308 } finally {
1309 c.close();
1310 }
1311
1312 return null;
1313 }
1314
1315 /**
1316 * Add an item to the database in a specified container. Sets the container, screen, cellX and
1317 * cellY fields of the item. Also assigns an ID to the item.
1318 */
1319 static void addItemToDatabase(Context context, ItemInfo item, long container,
1320 int screen, int cellX, int cellY, boolean notify) {
1321 item.container = container;
1322 item.screen = screen;
1323 item.cellX = cellX;
1324 item.cellY = cellY;
Romain Guy2fcbd682009-06-11 13:58:26 -07001325
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001326 final ContentValues values = new ContentValues();
1327 final ContentResolver cr = context.getContentResolver();
Romain Guy2fcbd682009-06-11 13:58:26 -07001328
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001329 item.onAddToDatabase(values);
Romain Guy2fcbd682009-06-11 13:58:26 -07001330
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001331 Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
1332 LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
1333
1334 if (result != null) {
1335 item.id = Integer.parseInt(result.getPathSegments().get(1));
1336 }
1337 }
1338
1339 /**
Romain Guy73b979d2009-06-09 12:57:21 -07001340 * Add an item to the database in a specified container. Sets the container, screen, cellX and
1341 * cellY fields of the item. Also assigns an ID to the item.
1342 */
1343 static boolean addGestureToDatabase(Context context, ItemInfo item, boolean notify) {
1344 final ContentValues values = new ContentValues();
1345 final ContentResolver cr = context.getContentResolver();
1346
1347 item.onAddToDatabase(values);
1348
1349 Uri result = cr.insert(notify ? LauncherSettings.Gestures.CONTENT_URI :
1350 LauncherSettings.Gestures.CONTENT_URI_NO_NOTIFICATION, values);
1351
1352 if (result != null) {
1353 item.id = Integer.parseInt(result.getPathSegments().get(1));
1354 }
1355
1356 return result != null;
1357 }
1358
1359 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001360 * Update an item to the database in a specified container.
1361 */
1362 static void updateItemInDatabase(Context context, ItemInfo item) {
1363 final ContentValues values = new ContentValues();
1364 final ContentResolver cr = context.getContentResolver();
1365
1366 item.onAddToDatabase(values);
1367
1368 cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
1369 }
Romain Guy2fcbd682009-06-11 13:58:26 -07001370
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001371 /**
1372 * Removes the specified item from the database
1373 * @param context
1374 * @param item
1375 */
1376 static void deleteItemFromDatabase(Context context, ItemInfo item) {
1377 final ContentResolver cr = context.getContentResolver();
1378
1379 cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null);
1380 }
1381
1382
1383 /**
1384 * Remove the contents of the specified folder from the database
1385 */
1386 static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
1387 final ContentResolver cr = context.getContentResolver();
1388
1389 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
1390 cr.delete(LauncherSettings.Favorites.CONTENT_URI,
1391 LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
1392 }
Romain Guy73b979d2009-06-09 12:57:21 -07001393
1394 static void deleteGestureFromDatabase(Context context, ItemInfo item) {
1395 final ContentResolver cr = context.getContentResolver();
1396
1397 cr.delete(LauncherSettings.Gestures.getContentUri(item.id, false), null, null);
1398 }
1399
1400 static void updateGestureInDatabase(Context context, ItemInfo item) {
1401 final ContentValues values = new ContentValues();
1402 final ContentResolver cr = context.getContentResolver();
1403
1404 item.onAddToDatabase(values);
1405
1406 cr.update(LauncherSettings.Gestures.getContentUri(item.id, false), values, null, null);
1407 }
1408
1409
1410 ApplicationInfo queryGesture(Context context, String id) {
1411 final ContentResolver contentResolver = context.getContentResolver();
1412 final PackageManager manager = context.getPackageManager();
1413 final Cursor c = contentResolver.query(
1414 LauncherSettings.Gestures.CONTENT_URI, null, LauncherSettings.Gestures._ID + "=?",
1415 new String[] { id }, null);
1416
1417 ApplicationInfo info = null;
1418
1419 try {
1420 final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures._ID);
1421 final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.INTENT);
1422 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.TITLE);
1423 final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_TYPE);
1424 final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON);
1425 final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_PACKAGE);
1426 final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_RESOURCE);
1427 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ITEM_TYPE);
1428
1429 String intentDescription;
1430 Intent intent;
1431
1432 if (c.moveToNext()) {
1433 int itemType = c.getInt(itemTypeIndex);
1434
1435 switch (itemType) {
1436 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
1437 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
1438 intentDescription = c.getString(intentIndex);
1439 try {
Romain Guy1ce1a242009-06-23 17:34:54 -07001440 intent = Intent.parseUri(intentDescription, 0);
Romain Guy73b979d2009-06-09 12:57:21 -07001441 } catch (java.net.URISyntaxException e) {
1442 return null;
1443 }
1444
1445 if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
1446 info = getApplicationInfo(manager, intent, context);
1447 } else {
1448 info = getApplicationInfoShortcut(c, context, iconTypeIndex,
1449 iconPackageIndex, iconResourceIndex, iconIndex);
1450 }
1451
1452 if (info == null) {
1453 info = new ApplicationInfo();
1454 info.icon = manager.getDefaultActivityIcon();
1455 }
1456
1457 info.isGesture = true;
1458 info.title = c.getString(titleIndex);
1459 info.intent = intent;
1460 info.id = c.getLong(idIndex);
1461
1462 break;
1463 }
1464 }
1465 } catch (Exception e) {
1466 w(LOG_TAG, "Could not load gesture with name " + id);
1467 } finally {
1468 c.close();
1469 }
1470
1471 return info;
1472 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001473}