diff options
Diffstat (limited to 'src/com/android/launcher2/LauncherModel.java')
-rw-r--r-- | src/com/android/launcher2/LauncherModel.java | 1482 |
1 files changed, 1482 insertions, 0 deletions
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java new file mode 100644 index 000000000..591463bd0 --- /dev/null +++ b/src/com/android/launcher2/LauncherModel.java @@ -0,0 +1,1482 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher; + +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Intent; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import static android.util.Log.*; +import android.os.Process; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Comparator; +import java.lang.ref.WeakReference; +import java.text.Collator; +import java.net.URISyntaxException; + +/** + * Maintains in-memory state of the Launcher. It is expected that there should be only one + * LauncherModel object held in a static. Also provide APIs for updating the database state + * for the Launcher. + */ +public class LauncherModel { + static final boolean DEBUG_LOADERS = true; + static final String LOG_TAG = "HomeLoaders"; + + private static final int UI_NOTIFICATION_RATE = 4; + private static final int DEFAULT_APPLICATIONS_NUMBER = 42; + private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000; + private static final int INITIAL_ICON_CACHE_CAPACITY = 50; + + private static final Collator sCollator = Collator.getInstance(); + + private boolean mApplicationsLoaded; + private boolean mDesktopItemsLoaded; + + private ArrayList<ItemInfo> mDesktopItems; + private ArrayList<LauncherAppWidgetInfo> mDesktopAppWidgets; + private HashMap<Long, FolderInfo> mFolders; + + private ArrayList<ApplicationInfo> mApplications; + private ApplicationsAdapter mApplicationsAdapter; + private ApplicationsLoader mApplicationsLoader; + private DesktopItemsLoader mDesktopItemsLoader; + private Thread mApplicationsLoaderThread; + private Thread mDesktopLoaderThread; + + private final HashMap<ComponentName, ApplicationInfo> mAppInfoCache = + new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY); + + synchronized void abortLoaders() { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + mApplicationsLoader.stop(); + mApplicationsLoaded = false; + } + + if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) { + mDesktopItemsLoader.stop(); + mDesktopItemsLoaded = false; + } + } + + /** + * Drop our cache of components to their lables & icons. We do + * this from Launcher when applications are added/removed. It's a + * bit overkill, but it's a rare operation anyway. + */ + synchronized void dropApplicationCache() { + mAppInfoCache.clear(); + } + + /** + * Loads the list of installed applications in mApplications. + * + * @return true if the applications loader must be started + * (see startApplicationsLoader()), false otherwise. + */ + synchronized boolean loadApplications(boolean isLaunching, Launcher launcher, + boolean localeChanged) { + + if (DEBUG_LOADERS) d(LOG_TAG, "load applications"); + + if (isLaunching && mApplicationsLoaded && !localeChanged) { + mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications); + if (DEBUG_LOADERS) d(LOG_TAG, " --> applications loaded, return"); + return false; + } + + stopAndWaitForApplicationsLoader(); + + if (localeChanged) { + dropApplicationCache(); + } + + if (mApplicationsAdapter == null || isLaunching || localeChanged) { + mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); + mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications); + } + + mApplicationsLoaded = false; + + if (!isLaunching) { + startApplicationsLoader(launcher, false); + return false; + } + + return true; + } + + private synchronized void stopAndWaitForApplicationsLoader() { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + if (DEBUG_LOADERS) d(LOG_TAG, " --> wait for applications loader"); + + mApplicationsLoader.stop(); + // Wait for the currently running thread to finish, this can take a little + // time but it should be well below the timeout limit + try { + mApplicationsLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT); + } catch (InterruptedException e) { + // EMpty + } + } + } + + private synchronized void startApplicationsLoader(Launcher launcher, boolean isLaunching) { + if (DEBUG_LOADERS) d(LOG_TAG, " --> starting applications loader"); + + stopAndWaitForApplicationsLoader(); + + mApplicationsLoader = new ApplicationsLoader(launcher, isLaunching); + mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader"); + mApplicationsLoaderThread.start(); + } + + synchronized void addPackage(Launcher launcher, String packageName) { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + startApplicationsLoader(launcher, false); + return; + } + + if (packageName != null && packageName.length() > 0) { + final PackageManager packageManager = launcher.getPackageManager(); + final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName); + + if (matches.size() > 0) { + final ApplicationsAdapter adapter = mApplicationsAdapter; + final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache; + + for (ResolveInfo info : matches) { + adapter.setNotifyOnChange(false); + adapter.add(makeAndCacheApplicationInfo(packageManager, cache, info, launcher)); + } + + adapter.sort(new ApplicationInfoComparator()); + adapter.notifyDataSetChanged(); + } + } + } + + synchronized void removePackage(Launcher launcher, String packageName) { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + dropApplicationCache(); // TODO: this could be optimized + startApplicationsLoader(launcher, false); + return; + } + + if (packageName != null && packageName.length() > 0) { + final ApplicationsAdapter adapter = mApplicationsAdapter; + + final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>(); + final int count = adapter.getCount(); + + for (int i = 0; i < count; i++) { + final ApplicationInfo applicationInfo = adapter.getItem(i); + final Intent intent = applicationInfo.intent; + final ComponentName component = intent.getComponent(); + if (packageName.equals(component.getPackageName())) { + toRemove.add(applicationInfo); + } + } + + final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache; + for (ApplicationInfo info : toRemove) { + adapter.setNotifyOnChange(false); + adapter.remove(info); + cache.remove(info.intent.getComponent()); + } + + if (toRemove.size() > 0) { + adapter.sort(new ApplicationInfoComparator()); + adapter.notifyDataSetChanged(); + } + } + } + + synchronized void updatePackage(Launcher launcher, String packageName) { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + startApplicationsLoader(launcher, false); + return; + } + + if (packageName != null && packageName.length() > 0) { + final PackageManager packageManager = launcher.getPackageManager(); + final ApplicationsAdapter adapter = mApplicationsAdapter; + + final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName); + final int count = matches.size(); + + boolean changed = false; + + for (int i = 0; i < count; i++) { + final ResolveInfo info = matches.get(i); + final ApplicationInfo applicationInfo = findIntent(adapter, + info.activityInfo.applicationInfo.packageName, info.activityInfo.name); + if (applicationInfo != null) { + updateAndCacheApplicationInfo(packageManager, info, applicationInfo, launcher); + changed = true; + } + } + + if (syncLocked(launcher, packageName)) changed = true; + + if (changed) { + adapter.sort(new ApplicationInfoComparator()); + adapter.notifyDataSetChanged(); + } + } + } + + private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info, + ApplicationInfo applicationInfo, Context context) { + + updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo, context); + + ComponentName componentName = new ComponentName( + info.activityInfo.applicationInfo.packageName, info.activityInfo.name); + mAppInfoCache.put(componentName, applicationInfo); + } + + synchronized void syncPackage(Launcher launcher, String packageName) { + if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) { + startApplicationsLoader(launcher, false); + return; + } + + if (packageName != null && packageName.length() > 0) { + if (syncLocked(launcher, packageName)) { + final ApplicationsAdapter adapter = mApplicationsAdapter; + adapter.sort(new ApplicationInfoComparator()); + adapter.notifyDataSetChanged(); + } + } + } + + private boolean syncLocked(Launcher launcher, String packageName) { + final PackageManager packageManager = launcher.getPackageManager(); + final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName); + + if (matches.size() > 0) { + final ApplicationsAdapter adapter = mApplicationsAdapter; + + // Find disabled activities and remove them from the adapter + boolean removed = removeDisabledActivities(packageName, matches, adapter); + // Find enable activities and add them to the adapter + // Also updates existing activities with new labels/icons + boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher); + + return added || removed; + } + + return false; + } + + private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager, + String packageName) { + + final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); + final List<ResolveInfo> matches = new ArrayList<ResolveInfo>(); + + if (apps != null) { + // Find all activities that match the packageName + int count = apps.size(); + for (int i = 0; i < count; i++) { + final ResolveInfo info = apps.get(i); + final ActivityInfo activityInfo = info.activityInfo; + if (packageName.equals(activityInfo.packageName)) { + matches.add(info); + } + } + } + + return matches; + } + + private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches, + ApplicationsAdapter adapter, Launcher launcher) { + + final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>(); + final int count = matches.size(); + + boolean changed = false; + + for (int i = 0; i < count; i++) { + final ResolveInfo info = matches.get(i); + final ApplicationInfo applicationInfo = findIntent(adapter, + info.activityInfo.applicationInfo.packageName, info.activityInfo.name); + if (applicationInfo == null) { + toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(), + mAppInfoCache, info, launcher)); + changed = true; + } else { + updateAndCacheApplicationInfo( + launcher.getPackageManager(), info, applicationInfo, launcher); + changed = true; + } + } + + for (ApplicationInfo info : toAdd) { + adapter.setNotifyOnChange(false); + adapter.add(info); + } + + return changed; + } + + private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches, + ApplicationsAdapter adapter) { + + final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>(); + final int count = adapter.getCount(); + + boolean changed = false; + + for (int i = 0; i < count; i++) { + final ApplicationInfo applicationInfo = adapter.getItem(i); + final Intent intent = applicationInfo.intent; + final ComponentName component = intent.getComponent(); + if (packageName.equals(component.getPackageName())) { + if (!findIntent(matches, component)) { + toRemove.add(applicationInfo); + changed = true; + } + } + } + + final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache; + for (ApplicationInfo info : toRemove) { + adapter.setNotifyOnChange(false); + adapter.remove(info); + cache.remove(info.intent.getComponent()); + } + + return changed; + } + + private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName, + String name) { + + final int count = adapter.getCount(); + for (int i = 0; i < count; i++) { + final ApplicationInfo applicationInfo = adapter.getItem(i); + final Intent intent = applicationInfo.intent; + final ComponentName component = intent.getComponent(); + if (packageName.equals(component.getPackageName()) && + name.equals(component.getClassName())) { + return applicationInfo; + } + } + + return null; + } + + private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) { + final String className = component.getClassName(); + for (ResolveInfo info : apps) { + final ActivityInfo activityInfo = info.activityInfo; + if (activityInfo.name.equals(className)) { + return true; + } + } + return false; + } + + Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) { + final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0); + if (resolveInfo == null) { + return null; + } + + ComponentName componentName = new ComponentName( + resolveInfo.activityInfo.applicationInfo.packageName, + resolveInfo.activityInfo.name); + ApplicationInfo application = mAppInfoCache.get(componentName); + + if (application == null) { + return resolveInfo.activityInfo.loadIcon(manager); + } + + return application.icon; + } + + private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager, + HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info, + Context context) { + + ComponentName componentName = new ComponentName( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name); + ApplicationInfo application = appInfoCache.get(componentName); + + if (application == null) { + application = new ApplicationInfo(); + application.container = ItemInfo.NO_ID; + + updateApplicationInfoTitleAndIcon(manager, info, application, context); + + application.setActivity(componentName, + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + appInfoCache.put(componentName, application); + } + + return application; + } + + private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info, + ApplicationInfo application, Context context) { + + application.title = info.loadLabel(manager); + if (application.title == null) { + application.title = info.activityInfo.name; + } + + application.icon = + Utilities.createIconThumbnail(info.activityInfo.loadIcon(manager), context); + application.filtered = false; + } + + private class ApplicationsLoader implements Runnable { + private final WeakReference<Launcher> mLauncher; + + private volatile boolean mStopped; + private volatile boolean mRunning; + private final boolean mIsLaunching; + + ApplicationsLoader(Launcher launcher, boolean isLaunching) { + mIsLaunching = isLaunching; + mLauncher = new WeakReference<Launcher>(launcher); + } + + void stop() { + mStopped = true; + } + + boolean isRunning() { + return mRunning; + } + + public void run() { + mRunning = true; + + // Elevate priority when Home launches for the first time to avoid + // starving at boot time. Staring at a blank home is not cool. + android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT : + Process.THREAD_PRIORITY_BACKGROUND); + + final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + final Launcher launcher = mLauncher.get(); + final PackageManager manager = launcher.getPackageManager(); + final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0); + + if (apps != null && !mStopped) { + final int count = apps.size(); + // Can be set to null on the UI thread by the unbind() method + // Do not access without checking for null first + final ApplicationsAdapter applicationList = mApplicationsAdapter; + + ChangeNotifier action = new ChangeNotifier(applicationList, true); + final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache; + + for (int i = 0; i < count && !mStopped; i++) { + ResolveInfo info = apps.get(i); + ApplicationInfo application = + makeAndCacheApplicationInfo(manager, appInfoCache, info, launcher); + + if (action.add(application) && !mStopped) { + launcher.runOnUiThread(action); + action = new ChangeNotifier(applicationList, false); + } + } + + launcher.runOnUiThread(action); + } + + if (!mStopped) { + mApplicationsLoaded = true; + } + mRunning = false; + } + } + + private static class ChangeNotifier implements Runnable { + private final ApplicationsAdapter mApplicationList; + private final ArrayList<ApplicationInfo> mBuffer; + + private boolean mFirst = true; + + ChangeNotifier(ApplicationsAdapter applicationList, boolean first) { + mApplicationList = applicationList; + mFirst = first; + mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE); + } + + public void run() { + final ApplicationsAdapter applicationList = mApplicationList; + // Can be set to null on the UI thread by the unbind() method + if (applicationList == null) return; + + if (mFirst) { + applicationList.setNotifyOnChange(false); + applicationList.clear(); + mFirst = false; + } + + final ArrayList<ApplicationInfo> buffer = mBuffer; + final int count = buffer.size(); + + for (int i = 0; i < count; i++) { + applicationList.setNotifyOnChange(false); + applicationList.add(buffer.get(i)); + } + + buffer.clear(); + + applicationList.sort(new ApplicationInfoComparator()); + applicationList.notifyDataSetChanged(); + } + + boolean add(ApplicationInfo application) { + final ArrayList<ApplicationInfo> buffer = mBuffer; + buffer.add(application); + return buffer.size() >= UI_NOTIFICATION_RATE; + } + } + + static class ApplicationInfoComparator implements Comparator<ApplicationInfo> { + public final int compare(ApplicationInfo a, ApplicationInfo b) { + return sCollator.compare(a.title.toString(), b.title.toString()); + } + } + + boolean isDesktopLoaded() { + return mDesktopItems != null && mDesktopAppWidgets != null && mDesktopItemsLoaded; + } + + /** + * Loads all of the items on the desktop, in folders, or in the dock. + * These can be apps, shortcuts or widgets + */ + void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged, + boolean loadApplications) { + if (DEBUG_LOADERS) d(LOG_TAG, "loading user items"); + + if (isLaunching && isDesktopLoaded()) { + if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return"); + if (loadApplications) startApplicationsLoader(launcher, true); + // We have already loaded our data from the DB + launcher.onDesktopItemsLoaded(); + return; + } + + if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) { + if (DEBUG_LOADERS) d(LOG_TAG, " --> stopping workspace loader"); + mDesktopItemsLoader.stop(); + // Wait for the currently running thread to finish, this can take a little + // time but it should be well below the timeout limit + try { + mDesktopLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT); + } catch (InterruptedException e) { + // Empty + } + + // If the thread we are interrupting was tasked to load the list of + // applications make sure we keep that information in the new loader + // spawned below + // note: we don't apply this to localeChanged because the thread can + // only be stopped *after* the localeChanged handling has occured + loadApplications = mDesktopItemsLoader.mLoadApplications; + } + + if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader"); + mDesktopItemsLoaded = false; + mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications, + isLaunching); + mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader"); + mDesktopLoaderThread.start(); + } + + private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) { + final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE, + LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE }, + null, null, null); + + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + + // boolean changed = false; + + try { + while (c.moveToNext()) { + try { + if (c.getInt(itemTypeIndex) != + LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + continue; + } + + final String intentUri = c.getString(intentIndex); + if (intentUri != null) { + final Intent shortcut = Intent.parseUri(intentUri, 0); + if (Intent.ACTION_MAIN.equals(shortcut.getAction())) { + final ComponentName name = shortcut.getComponent(); + if (name != null) { + final ActivityInfo activityInfo = manager.getActivityInfo(name, 0); + final String title = c.getString(titleIndex); + String label = getLabel(manager, activityInfo); + + if (title == null || !title.equals(label)) { + final ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.TITLE, label); + + resolver.update( + LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, + values, "_id=?", + new String[] { String.valueOf(c.getLong(idIndex)) }); + + // changed = true; + } + } + } + } + } catch (URISyntaxException e) { + // Ignore + } catch (PackageManager.NameNotFoundException e) { + // Ignore + } + } + } finally { + c.close(); + } + + // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null); + } + + private static String getLabel(PackageManager manager, ActivityInfo activityInfo) { + String label = activityInfo.loadLabel(manager).toString(); + if (label == null) { + label = manager.getApplicationLabel(activityInfo.applicationInfo).toString(); + if (label == null) { + label = activityInfo.name; + } + } + return label; + } + + private class DesktopItemsLoader implements Runnable { + private volatile boolean mStopped; + private volatile boolean mRunning; + + private final WeakReference<Launcher> mLauncher; + private final boolean mLocaleChanged; + private final boolean mLoadApplications; + private final boolean mIsLaunching; + + DesktopItemsLoader(Launcher launcher, boolean localeChanged, boolean loadApplications, + boolean isLaunching) { + mLoadApplications = loadApplications; + mIsLaunching = isLaunching; + mLauncher = new WeakReference<Launcher>(launcher); + mLocaleChanged = localeChanged; + } + + void stop() { + mStopped = true; + } + + boolean isRunning() { + return mRunning; + } + + public void run() { + mRunning = true; + + android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + + final Launcher launcher = mLauncher.get(); + final ContentResolver contentResolver = launcher.getContentResolver(); + final PackageManager manager = launcher.getPackageManager(); + + if (mLocaleChanged) { + updateShortcutLabels(contentResolver, manager); + } + + mDesktopItems = new ArrayList<ItemInfo>(); + mDesktopAppWidgets = new ArrayList<LauncherAppWidgetInfo>(); + mFolders = new HashMap<Long, FolderInfo>(); + + final ArrayList<ItemInfo> desktopItems = mDesktopItems; + final ArrayList<LauncherAppWidgetInfo> desktopAppWidgets = mDesktopAppWidgets; + + final Cursor c = contentResolver.query( + LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); + + try { + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE); + final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); + final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE); + final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE); + final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID); + final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX); + final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY); + final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); + final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE); + + ApplicationInfo info; + String intentDescription; + Widget widgetInfo; + LauncherAppWidgetInfo appWidgetInfo; + int container; + long id; + Intent intent; + + final HashMap<Long, FolderInfo> folders = mFolders; + + while (!mStopped && c.moveToNext()) { + try { + int itemType = c.getInt(itemTypeIndex); + + switch (itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + intentDescription = c.getString(intentIndex); + try { + intent = Intent.parseUri(intentDescription, 0); + } catch (java.net.URISyntaxException e) { + continue; + } + + if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + info = getApplicationInfo(manager, intent, launcher); + } else { + info = getApplicationInfoShortcut(c, launcher, iconTypeIndex, + iconPackageIndex, iconResourceIndex, iconIndex); + } + + if (info == null) { + info = new ApplicationInfo(); + info.icon = manager.getDefaultActivityIcon(); + } + + if (info != null) { + info.title = c.getString(titleIndex); + info.intent = intent; + + info.id = c.getLong(idIndex); + container = c.getInt(containerIndex); + info.container = container; + info.screen = c.getInt(screenIndex); + info.cellX = c.getInt(cellXIndex); + info.cellY = c.getInt(cellYIndex); + + switch (container) { + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + desktopItems.add(info); + break; + default: + // Item is in a user folder + UserFolderInfo folderInfo = + findOrMakeUserFolder(folders, container); + folderInfo.add(info); + break; + } + } + break; + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: + + id = c.getLong(idIndex); + UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id); + + folderInfo.title = c.getString(titleIndex); + + folderInfo.id = id; + container = c.getInt(containerIndex); + folderInfo.container = container; + folderInfo.screen = c.getInt(screenIndex); + folderInfo.cellX = c.getInt(cellXIndex); + folderInfo.cellY = c.getInt(cellYIndex); + + switch (container) { + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + desktopItems.add(folderInfo); + break; + } + break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + + id = c.getLong(idIndex); + LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id); + + intentDescription = c.getString(intentIndex); + intent = null; + if (intentDescription != null) { + try { + intent = Intent.parseUri(intentDescription, 0); + } catch (java.net.URISyntaxException e) { + // Ignore, a live folder might not have a base intent + } + } + + liveFolderInfo.title = c.getString(titleIndex); + liveFolderInfo.id = id; + container = c.getInt(containerIndex); + liveFolderInfo.container = container; + liveFolderInfo.screen = c.getInt(screenIndex); + liveFolderInfo.cellX = c.getInt(cellXIndex); + liveFolderInfo.cellY = c.getInt(cellYIndex); + liveFolderInfo.uri = Uri.parse(c.getString(uriIndex)); + liveFolderInfo.baseIntent = intent; + liveFolderInfo.displayMode = c.getInt(displayModeIndex); + + loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex, + iconResourceIndex, liveFolderInfo); + + switch (container) { + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + desktopItems.add(liveFolderInfo); + break; + } + break; + case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH: + widgetInfo = Widget.makeSearch(); + + container = c.getInt(containerIndex); + if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { + e(Launcher.LOG_TAG, "Widget found where container " + + "!= CONTAINER_DESKTOP ignoring!"); + continue; + } + + widgetInfo.id = c.getLong(idIndex); + widgetInfo.screen = c.getInt(screenIndex); + widgetInfo.container = container; + widgetInfo.cellX = c.getInt(cellXIndex); + widgetInfo.cellY = c.getInt(cellYIndex); + + desktopItems.add(widgetInfo); + break; + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + // Read all Launcher-specific widget details + int appWidgetId = c.getInt(appWidgetIdIndex); + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId); + appWidgetInfo.id = c.getLong(idIndex); + appWidgetInfo.screen = c.getInt(screenIndex); + appWidgetInfo.cellX = c.getInt(cellXIndex); + appWidgetInfo.cellY = c.getInt(cellYIndex); + appWidgetInfo.spanX = c.getInt(spanXIndex); + appWidgetInfo.spanY = c.getInt(spanYIndex); + + container = c.getInt(containerIndex); + if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { + e(Launcher.LOG_TAG, "Widget found where container " + + "!= CONTAINER_DESKTOP -- ignoring!"); + continue; + } + appWidgetInfo.container = c.getInt(containerIndex); + + desktopAppWidgets.add(appWidgetInfo); + break; + } + } catch (Exception e) { + w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e); + } + } + } finally { + c.close(); + } + + if (!mStopped) { + launcher.runOnUiThread(new Runnable() { + public void run() { + launcher.onDesktopItemsLoaded(); + } + }); + if (mLoadApplications) startApplicationsLoader(launcher, mIsLaunching); + } + + if (!mStopped) { + mDesktopItemsLoaded = true; + } + mRunning = false; + } + } + + private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex, + int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) { + + int iconType = c.getInt(iconTypeIndex); + switch (iconType) { + case LauncherSettings.Favorites.ICON_TYPE_RESOURCE: + String packageName = c.getString(iconPackageIndex); + String resourceName = c.getString(iconResourceIndex); + PackageManager packageManager = launcher.getPackageManager(); + try { + Resources resources = packageManager.getResourcesForApplication(packageName); + final int id = resources.getIdentifier(resourceName, null, null); + liveFolderInfo.icon = resources.getDrawable(id); + } catch (Exception e) { + liveFolderInfo.icon = + launcher.getResources().getDrawable(R.drawable.ic_launcher_folder); + } + liveFolderInfo.iconResource = new Intent.ShortcutIconResource(); + liveFolderInfo.iconResource.packageName = packageName; + liveFolderInfo.iconResource.resourceName = resourceName; + break; + default: + liveFolderInfo.icon = + launcher.getResources().getDrawable(R.drawable.ic_launcher_folder); + } + } + + /** + * Finds the user folder defined by the specified id. + * + * @param id The id of the folder to look for. + * + * @return A UserFolderInfo if the folder exists or null otherwise. + */ + FolderInfo findFolderById(long id) { + return mFolders.get(id); + } + + void addFolder(FolderInfo info) { + mFolders.put(info.id, info); + } + + /** + * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a + * new one. + */ + private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) { + // See if a placeholder was created for us already + FolderInfo folderInfo = folders.get(id); + if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) { + // No placeholder -- create a new instance + folderInfo = new UserFolderInfo(); + folders.put(id, folderInfo); + } + return (UserFolderInfo) folderInfo; + } + + /** + * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a + * new one. + */ + private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) { + // See if a placeholder was created for us already + FolderInfo folderInfo = folders.get(id); + if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) { + // No placeholder -- create a new instance + folderInfo = new LiveFolderInfo(); + folders.put(id, folderInfo); + } + return (LiveFolderInfo) folderInfo; + } + + /** + * Remove the callback for the cached drawables or we leak the previous + * Home screen on orientation change. + */ + void unbind() { + // Interrupt the applications loader before setting the adapter to null + stopAndWaitForApplicationsLoader(); + mApplicationsAdapter = null; + unbindAppDrawables(mApplications); + unbindDrawables(mDesktopItems); + unbindAppWidgetHostViews(mDesktopAppWidgets); + unbindCachedIconDrawables(); + } + + /** + * Remove the callback for the cached drawables or we leak the previous + * Home screen on orientation change. + */ + private void unbindDrawables(ArrayList<ItemInfo> desktopItems) { + if (desktopItems != null) { + final int count = desktopItems.size(); + for (int i = 0; i < count; i++) { + ItemInfo item = desktopItems.get(i); + switch (item.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + ((ApplicationInfo)item).icon.setCallback(null); + break; + } + } + } + } + + /** + * Remove the callback for the cached drawables or we leak the previous + * Home screen on orientation change. + */ + private void unbindAppDrawables(ArrayList<ApplicationInfo> applications) { + if (applications != null) { + final int count = applications.size(); + for (int i = 0; i < count; i++) { + applications.get(i).icon.setCallback(null); + } + } + } + + /** + * Remove any {@link LauncherAppWidgetHostView} references in our widgets. + */ + private void unbindAppWidgetHostViews(ArrayList<LauncherAppWidgetInfo> appWidgets) { + if (appWidgets != null) { + final int count = appWidgets.size(); + for (int i = 0; i < count; i++) { + LauncherAppWidgetInfo launcherInfo = appWidgets.get(i); + launcherInfo.hostView = null; + } + } + } + + /** + * Remove the callback for the cached drawables or we leak the previous + * Home screen on orientation change. + */ + private void unbindCachedIconDrawables() { + for (ApplicationInfo appInfo : mAppInfoCache.values()) { + appInfo.icon.setCallback(null); + } + } + + /** + * @return The current list of applications + */ + ApplicationsAdapter getApplicationsAdapter() { + return mApplicationsAdapter; + } + + /** + * @return The current list of desktop items + */ + ArrayList<ItemInfo> getDesktopItems() { + return mDesktopItems; + } + + /** + * @return The current list of desktop items + */ + ArrayList<LauncherAppWidgetInfo> getDesktopAppWidgets() { + return mDesktopAppWidgets; + } + + /** + * Add an item to the desktop + * @param info + */ + void addDesktopItem(ItemInfo info) { + // TODO: write to DB; also check that folder has been added to folders list + mDesktopItems.add(info); + } + + /** + * Remove an item from the desktop + * @param info + */ + void removeDesktopItem(ItemInfo info) { + // TODO: write to DB; figure out if we should remove folder from folders list + mDesktopItems.remove(info); + } + + /** + * Add a widget to the desktop + */ + void addDesktopAppWidget(LauncherAppWidgetInfo info) { + mDesktopAppWidgets.add(info); + } + + /** + * Remove a widget from the desktop + */ + void removeDesktopAppWidget(LauncherAppWidgetInfo info) { + mDesktopAppWidgets.remove(info); + } + + /** + * Make an ApplicationInfo object for an application + */ + private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent, + Context context) { + final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0); + + if (resolveInfo == null) { + return null; + } + + final ApplicationInfo info = new ApplicationInfo(); + final ActivityInfo activityInfo = resolveInfo.activityInfo; + info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context); + if (info.title == null || info.title.length() == 0) { + info.title = activityInfo.loadLabel(manager); + } + if (info.title == null) { + info.title = ""; + } + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + return info; + } + + /** + * Make an ApplicationInfo object for a sortcut + */ + private ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context, + int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) { + + final ApplicationInfo info = new ApplicationInfo(); + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + + int iconType = c.getInt(iconTypeIndex); + switch (iconType) { + case LauncherSettings.Favorites.ICON_TYPE_RESOURCE: + String packageName = c.getString(iconPackageIndex); + String resourceName = c.getString(iconResourceIndex); + PackageManager packageManager = context.getPackageManager(); + try { + Resources resources = packageManager.getResourcesForApplication(packageName); + final int id = resources.getIdentifier(resourceName, null, null); + info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context); + } catch (Exception e) { + info.icon = packageManager.getDefaultActivityIcon(); + } + info.iconResource = new Intent.ShortcutIconResource(); + info.iconResource.packageName = packageName; + info.iconResource.resourceName = resourceName; + info.customIcon = false; + break; + case LauncherSettings.Favorites.ICON_TYPE_BITMAP: + byte[] data = c.getBlob(iconIndex); + try { + Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); + info.icon = new FastBitmapDrawable( + Utilities.createBitmapThumbnail(bitmap, context)); + } catch (Exception e) { + packageManager = context.getPackageManager(); + info.icon = packageManager.getDefaultActivityIcon(); + } + info.filtered = true; + info.customIcon = true; + break; + default: + info.icon = context.getPackageManager().getDefaultActivityIcon(); + info.customIcon = false; + break; + } + return info; + } + + /** + * Remove an item from the in-memory represention of a user folder. Does not change the DB. + */ + void removeUserFolderItem(UserFolderInfo folder, ItemInfo info) { + //noinspection SuspiciousMethodCalls + folder.contents.remove(info); + } + + /** + * Removes a UserFolder from the in-memory list of folders. Does not change the DB. + * @param userFolderInfo + */ + void removeUserFolder(UserFolderInfo userFolderInfo) { + mFolders.remove(userFolderInfo.id); + } + + /** + * Adds an item to the DB if it was not created previously, or move it to a new + * <container, screen, cellX, cellY> + */ + static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container, + int screen, int cellX, int cellY) { + if (item.container == ItemInfo.NO_ID) { + // From all apps + addItemToDatabase(context, item, container, screen, cellX, cellY, false); + } else { + // From somewhere else + moveItemInDatabase(context, item, container, screen, cellX, cellY); + } + } + + /** + * Move an item in the DB to a new <container, screen, cellX, cellY> + */ + static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen, + int cellX, int cellY) { + item.container = container; + item.screen = screen; + item.cellX = cellX; + item.cellY = cellY; + + final ContentValues values = new ContentValues(); + final ContentResolver cr = context.getContentResolver(); + + values.put(LauncherSettings.Favorites.CONTAINER, item.container); + values.put(LauncherSettings.Favorites.CELLX, item.cellX); + values.put(LauncherSettings.Favorites.CELLY, item.cellY); + values.put(LauncherSettings.Favorites.SCREEN, item.screen); + + cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); + } + + /** + * Returns true if the shortcuts already exists in the database. + * we identify a shortcut by its title and intent. + */ + static boolean shortcutExists(Context context, String title, Intent intent) { + final ContentResolver cr = context.getContentResolver(); + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { "title", "intent" }, "title=? and intent=?", + new String[] { title, intent.toUri(0) }, null); + boolean result = false; + try { + result = c.moveToFirst(); + } finally { + c.close(); + } + return result; + } + + FolderInfo getFolderById(Context context, long id) { + final ContentResolver cr = context.getContentResolver(); + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null, + "_id=? and (itemType=? or itemType=?)", + new String[] { String.valueOf(id), + String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER), + String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null); + + try { + if (c.moveToFirst()) { + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); + final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + + FolderInfo folderInfo = null; + switch (c.getInt(itemTypeIndex)) { + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: + folderInfo = findOrMakeUserFolder(mFolders, id); + break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + folderInfo = findOrMakeLiveFolder(mFolders, id); + break; + } + + folderInfo.title = c.getString(titleIndex); + folderInfo.id = id; + folderInfo.container = c.getInt(containerIndex); + folderInfo.screen = c.getInt(screenIndex); + folderInfo.cellX = c.getInt(cellXIndex); + folderInfo.cellY = c.getInt(cellYIndex); + + return folderInfo; + } + } finally { + c.close(); + } + + return null; + } + + /** + * Add an item to the database in a specified container. Sets the container, screen, cellX and + * cellY fields of the item. Also assigns an ID to the item. + */ + static void addItemToDatabase(Context context, ItemInfo item, long container, + int screen, int cellX, int cellY, boolean notify) { + item.container = container; + item.screen = screen; + item.cellX = cellX; + item.cellY = cellY; + + final ContentValues values = new ContentValues(); + final ContentResolver cr = context.getContentResolver(); + + item.onAddToDatabase(values); + + Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI : + LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values); + + if (result != null) { + item.id = Integer.parseInt(result.getPathSegments().get(1)); + } + } + + /** + * Add an item to the database in a specified container. Sets the container, screen, cellX and + * cellY fields of the item. Also assigns an ID to the item. + */ + static boolean addGestureToDatabase(Context context, ItemInfo item, boolean notify) { + final ContentValues values = new ContentValues(); + final ContentResolver cr = context.getContentResolver(); + + item.onAddToDatabase(values); + + Uri result = cr.insert(notify ? LauncherSettings.Gestures.CONTENT_URI : + LauncherSettings.Gestures.CONTENT_URI_NO_NOTIFICATION, values); + + if (result != null) { + item.id = Integer.parseInt(result.getPathSegments().get(1)); + } + + return result != null; + } + + /** + * Update an item to the database in a specified container. + */ + static void updateItemInDatabase(Context context, ItemInfo item) { + final ContentValues values = new ContentValues(); + final ContentResolver cr = context.getContentResolver(); + + item.onAddToDatabase(values); + + cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); + } + + /** + * Removes the specified item from the database + * @param context + * @param item + */ + static void deleteItemFromDatabase(Context context, ItemInfo item) { + final ContentResolver cr = context.getContentResolver(); + + cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null); + } + + + /** + * Remove the contents of the specified folder from the database + */ + static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) { + final ContentResolver cr = context.getContentResolver(); + + cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null); + cr.delete(LauncherSettings.Favorites.CONTENT_URI, + LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); + } + + static void deleteGestureFromDatabase(Context context, ItemInfo item) { + final ContentResolver cr = context.getContentResolver(); + + cr.delete(LauncherSettings.Gestures.getContentUri(item.id, false), null, null); + } + + static void updateGestureInDatabase(Context context, ItemInfo item) { + final ContentValues values = new ContentValues(); + final ContentResolver cr = context.getContentResolver(); + + item.onAddToDatabase(values); + + cr.update(LauncherSettings.Gestures.getContentUri(item.id, false), values, null, null); + } + + + ApplicationInfo queryGesture(Context context, String id) { + final ContentResolver contentResolver = context.getContentResolver(); + final PackageManager manager = context.getPackageManager(); + final Cursor c = contentResolver.query( + LauncherSettings.Gestures.CONTENT_URI, null, LauncherSettings.Gestures._ID + "=?", + new String[] { id }, null); + + ApplicationInfo info = null; + + try { + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures._ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.INTENT); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.TITLE); + final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_TYPE); + final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON); + final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_PACKAGE); + final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_RESOURCE); + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ITEM_TYPE); + + String intentDescription; + Intent intent; + + if (c.moveToNext()) { + int itemType = c.getInt(itemTypeIndex); + + switch (itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + intentDescription = c.getString(intentIndex); + try { + intent = Intent.parseUri(intentDescription, 0); + } catch (java.net.URISyntaxException e) { + return null; + } + + if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + info = getApplicationInfo(manager, intent, context); + } else { + info = getApplicationInfoShortcut(c, context, iconTypeIndex, + iconPackageIndex, iconResourceIndex, iconIndex); + } + + if (info == null) { + info = new ApplicationInfo(); + info.icon = manager.getDefaultActivityIcon(); + } + + info.isGesture = true; + info.title = c.getString(titleIndex); + info.intent = intent; + info.id = c.getLong(idIndex); + + break; + } + } + } catch (Exception e) { + w(LOG_TAG, "Could not load gesture with name " + id); + } finally { + c.close(); + } + + return info; + } +} |