summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3')
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java3
-rw-r--r--src/com/android/launcher3/AutoInstallsLayout.java245
-rw-r--r--src/com/android/launcher3/DefaultLayoutParser.java290
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java8
-rw-r--r--src/com/android/launcher3/DeviceProfile.java7
-rw-r--r--src/com/android/launcher3/DynamicGrid.java33
-rw-r--r--src/com/android/launcher3/FocusIndicatorView.java66
-rw-r--r--src/com/android/launcher3/IconCache.java176
-rw-r--r--src/com/android/launcher3/InstallShortcutReceiver.java28
-rw-r--r--src/com/android/launcher3/Launcher.java290
-rw-r--r--src/com/android/launcher3/LauncherAppState.java3
-rw-r--r--src/com/android/launcher3/LauncherCallbacks.java89
-rw-r--r--src/com/android/launcher3/LauncherFiles.java21
-rw-r--r--src/com/android/launcher3/LauncherModel.java23
-rw-r--r--src/com/android/launcher3/LauncherProvider.java668
-rw-r--r--src/com/android/launcher3/PendingAppWidgetHostView.java57
-rw-r--r--src/com/android/launcher3/Stats.java14
-rw-r--r--src/com/android/launcher3/WidgetPreviewLoader.java2
-rw-r--r--src/com/android/launcher3/Workspace.java1
19 files changed, 988 insertions, 1036 deletions
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 1bd290777..7f3b7fb35 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -728,7 +728,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
!(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
// Exit spring loaded mode if we have not successfully dropped or have not handled the
// drop in Workspace
- mLauncher.exitSpringLoadedDragMode();
+ mLauncher.exitSpringLoadedDragModeDelayed(true,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
mLauncher.unlockScreenOrientation(false);
} else {
mLauncher.unlockScreenOrientation(false);
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 08ed89b43..a5d22286d 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -36,7 +36,6 @@ import android.util.Pair;
import android.util.Patterns;
import com.android.launcher3.LauncherProvider.SqlArguments;
-import com.android.launcher3.LauncherProvider.WorkspaceLoader;
import com.android.launcher3.LauncherSettings.Favorites;
import org.xmlpull.v1.XmlPullParser;
@@ -47,13 +46,11 @@ import java.util.ArrayList;
import java.util.HashMap;
/**
- * This class contains contains duplication of functionality as found in
- * LauncherProvider#DatabaseHelper. It has been isolated and differentiated in order
- * to cleanly and separately represent AutoInstall default layout format and policy.
+ * Layout parsing code for auto installs layout
*/
-public class AutoInstallsLayout implements WorkspaceLoader {
+public class AutoInstallsLayout {
private static final String TAG = "AutoInstalls";
- private static final boolean LOGD = true;
+ private static final boolean LOGD = false;
/** Marker action used to discover a package which defines launcher customization */
static final String ACTION_LAUNCHER_CUSTOMIZATION =
@@ -76,7 +73,8 @@ public class AutoInstallsLayout implements WorkspaceLoader {
Log.e(TAG, "Layout definition not found in package: " + pkg);
return null;
}
- return new AutoInstallsLayout(context, appWidgetHost, callback, pkg, res, layoutId);
+ return new AutoInstallsLayout(context, appWidgetHost, callback, res, layoutId,
+ TAG_WORKSPACE);
}
// Object Tags
@@ -116,45 +114,55 @@ public class AutoInstallsLayout implements WorkspaceLoader {
private final AppWidgetHost mAppWidgetHost;
private final LayoutParserCallback mCallback;
- private final PackageManager mPackageManager;
- private final ContentValues mValues;
+ protected final PackageManager mPackageManager;
+ protected final Resources mSourceRes;
+ protected final int mLayoutId;
+
+ private final int mHotseatAllAppsRank;
- private final Resources mRes;
- private final int mLayoutId;
+ private final long[] mTemp = new long[2];
+ private final ContentValues mValues;
+ private final String mRootTag;
- private SQLiteDatabase mDb;
+ protected SQLiteDatabase mDb;
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
- LayoutParserCallback callback, String packageName, Resources res, int layoutId) {
+ LayoutParserCallback callback, Resources res,
+ int layoutId, String rootTag) {
mContext = context;
mAppWidgetHost = appWidgetHost;
mCallback = callback;
mPackageManager = context.getPackageManager();
mValues = new ContentValues();
+ mRootTag = rootTag;
- mRes = res;
+ mSourceRes = res;
mLayoutId = layoutId;
+ mHotseatAllAppsRank = LauncherAppState.getInstance()
+ .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
}
- @Override
+ /**
+ * Loads the layout in the db and returns the number of entries added on the desktop.
+ */
public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) {
mDb = db;
try {
- return parseLayout(mRes, mLayoutId, screenIds);
+ return parseLayout(mLayoutId, screenIds);
} catch (Exception e) {
Log.w(TAG, "Got exception parsing layout.", e);
return -1;
}
}
- private int parseLayout(Resources res, int layoutId, ArrayList<Long> screenIds)
+ /**
+ * Parses the layout and returns the number of elements added on the homescreen.
+ */
+ protected int parseLayout(int layoutId, ArrayList<Long> screenIds)
throws XmlPullParserException, IOException {
- final int hotseatAllAppsRank = LauncherAppState.getInstance()
- .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
-
- XmlResourceParser parser = res.getXml(layoutId);
- beginDocument(parser, TAG_WORKSPACE);
+ XmlResourceParser parser = mSourceRes.getXml(layoutId);
+ beginDocument(parser, mRootTag);
final int depth = parser.getDepth();
int type;
HashMap<String, TagParser> tagParserMap = getLayoutElementsMap();
@@ -165,45 +173,60 @@ public class AutoInstallsLayout implements WorkspaceLoader {
if (type != XmlPullParser.START_TAG) {
continue;
}
+ count += parseAndAddNode(parser, tagParserMap, screenIds);
+ }
+ return count;
+ }
- mValues.clear();
- final int container;
- final long screenId;
-
- if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
- container = Favorites.CONTAINER_HOTSEAT;
-
- // Hack: hotseat items are stored using screen ids
- long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
- screenId = (rank < hotseatAllAppsRank) ? rank : (rank + 1);
-
- } else {
- container = Favorites.CONTAINER_DESKTOP;
- screenId = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
-
- mValues.put(Favorites.CELLX, getAttributeValue(parser, ATTR_X));
- mValues.put(Favorites.CELLY, getAttributeValue(parser, ATTR_Y));
- }
-
- mValues.put(Favorites.CONTAINER, container);
- mValues.put(Favorites.SCREEN, screenId);
+ /**
+ * Parses container and screenId attribute from the current tag, and puts it in the out.
+ * @param out array of size 2.
+ */
+ protected void parseContainerAndScreen(XmlResourceParser parser, long[] out) {
+ if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
+ out[0] = Favorites.CONTAINER_HOTSEAT;
+ // Hack: hotseat items are stored using screen ids
+ long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
+ out[1] = (rank < mHotseatAllAppsRank) ? rank : (rank + 1);
+ } else {
+ out[0] = Favorites.CONTAINER_DESKTOP;
+ out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
+ }
+ }
- TagParser tagParser = tagParserMap.get(parser.getName());
- if (tagParser == null) {
- if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName());
- continue;
- }
- long newElementId = tagParser.parseAndAdd(parser, res);
- if (newElementId >= 0) {
- // Keep track of the set of screens which need to be added to the db.
- if (!screenIds.contains(screenId) &&
- container == Favorites.CONTAINER_DESKTOP) {
- screenIds.add(screenId);
- }
- count++;
+ /**
+ * Parses the current node and returns the number of elements added.
+ */
+ protected int parseAndAddNode(
+ XmlResourceParser parser,
+ HashMap<String, TagParser> tagParserMap,
+ ArrayList<Long> screenIds)
+ throws XmlPullParserException, IOException {
+ mValues.clear();
+ parseContainerAndScreen(parser, mTemp);
+ final long container = mTemp[0];
+ final long screenId = mTemp[1];
+
+ mValues.put(Favorites.CONTAINER, container);
+ mValues.put(Favorites.SCREEN, screenId);
+ mValues.put(Favorites.CELLX, getAttributeValue(parser, ATTR_X));
+ mValues.put(Favorites.CELLY, getAttributeValue(parser, ATTR_Y));
+
+ TagParser tagParser = tagParserMap.get(parser.getName());
+ if (tagParser == null) {
+ if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName());
+ return 0;
+ }
+ long newElementId = tagParser.parseAndAdd(parser);
+ if (newElementId >= 0) {
+ // Keep track of the set of screens which need to be added to the db.
+ if (!screenIds.contains(screenId) &&
+ container == Favorites.CONTAINER_DESKTOP) {
+ screenIds.add(screenId);
}
+ return 1;
}
- return count;
+ return 0;
}
protected long addShortcut(String title, Intent intent, int type) {
@@ -225,7 +248,7 @@ public class AutoInstallsLayout implements WorkspaceLoader {
HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
parsers.put(TAG_APP_ICON, new AppShortcutParser());
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser());
+ parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
return parsers;
}
@@ -235,23 +258,26 @@ public class AutoInstallsLayout implements WorkspaceLoader {
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
parsers.put(TAG_FOLDER, new FolderParser());
parsers.put(TAG_APPWIDGET, new AppWidgetParser());
- parsers.put(TAG_SHORTCUT, new ShortcutParser());
+ parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
return parsers;
}
- private interface TagParser {
+ protected interface TagParser {
/**
* Parses the tag and adds to the db
* @return the id of the row added or -1;
*/
- long parseAndAdd(XmlResourceParser parser, Resources res)
+ long parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException;
}
- private class AppShortcutParser implements TagParser {
+ /**
+ * App shortcuts: required attributes packageName and className
+ */
+ protected class AppShortcutParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser, Resources res) {
+ public long parseAndAdd(XmlResourceParser parser) {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
@@ -277,20 +303,30 @@ public class AutoInstallsLayout implements WorkspaceLoader {
return addShortcut(info.loadLabel(mPackageManager).toString(),
intent, Favorites.ITEM_TYPE_APPLICATION);
} catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to add favorite: " + packageName + "/" + className, e);
+ if (LOGD) Log.w(TAG, "Unable to add favorite: " + packageName + "/" + className, e);
}
return -1;
} else {
- if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component or uri");
- return -1;
+ return invalidPackageOrClass(parser);
}
}
+
+ /**
+ * Helper method to allow extending the parser capabilities
+ */
+ protected long invalidPackageOrClass(XmlResourceParser parser) {
+ if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component");
+ return -1;
+ }
}
- private class AutoInstallParser implements TagParser {
+ /**
+ * AutoInstall: required attributes packageName and className
+ */
+ protected class AutoInstallParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser, Resources res) {
+ public long parseAndAdd(XmlResourceParser parser) {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
@@ -309,11 +345,19 @@ public class AutoInstallsLayout implements WorkspaceLoader {
}
}
- private class ShortcutParser implements TagParser {
+ /**
+ * Parses a web shortcut. Required attributes url, icon, title
+ */
+ protected class ShortcutParser implements TagParser {
+
+ private final Resources mIconRes;
+
+ public ShortcutParser(Resources iconRes) {
+ mIconRes = iconRes;
+ }
@Override
- public long parseAndAdd(XmlResourceParser parser, Resources res) {
- final String url = getAttributeValue(parser, ATTR_URL);
+ public long parseAndAdd(XmlResourceParser parser) {
final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
@@ -322,29 +366,46 @@ public class AutoInstallsLayout implements WorkspaceLoader {
return -1;
}
- if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
- if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
+ final Intent intent = parseIntent(parser);
+ if (intent == null) {
return -1;
}
- Drawable icon = res.getDrawable(iconId);
+
+ Drawable icon = mIconRes.getDrawable(iconId);
if (icon == null) {
if (LOGD) Log.d(TAG, "Ignoring shortcut, can't load icon");
return -1;
}
ItemInfo.writeBitmap(mValues, Utilities.createIconBitmap(icon, mContext));
- final Intent intent = new Intent(Intent.ACTION_VIEW, null)
- .setData(Uri.parse(url))
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ mValues.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
+ mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
+ mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- return addShortcut(res.getString(titleResId), intent, Favorites.ITEM_TYPE_SHORTCUT);
+ return addShortcut(mSourceRes.getString(titleResId),
+ intent, Favorites.ITEM_TYPE_SHORTCUT);
+ }
+
+ protected Intent parseIntent(XmlResourceParser parser) {
+ final String url = getAttributeValue(parser, ATTR_URL);
+ if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
+ if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
+ return null;
+ }
+ return new Intent(Intent.ACTION_VIEW, null).setData(Uri.parse(url));
}
}
- private class AppWidgetParser implements TagParser {
+ /**
+ * AppWidget parser: Required attributes packageName, className, spanX and spanY.
+ * Options child nodes: <extra key=... value=... />
+ */
+ protected class AppWidgetParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser, Resources res)
+ public long parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
@@ -429,16 +490,24 @@ public class AutoInstallsLayout implements WorkspaceLoader {
}
}
- private class FolderParser implements TagParser {
- private final HashMap<String, TagParser> mFolderElements = getFolderElementsMap();
+ protected class FolderParser implements TagParser {
+ private final HashMap<String, TagParser> mFolderElements;
+
+ public FolderParser() {
+ this(getFolderElementsMap());
+ }
+
+ public FolderParser(HashMap<String, TagParser> elements) {
+ mFolderElements = elements;
+ }
@Override
- public long parseAndAdd(XmlResourceParser parser, Resources res)
+ public long parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException {
final String title;
final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
if (titleResId != 0) {
- title = res.getString(titleResId);
+ title = mSourceRes.getString(titleResId);
} else {
title = mContext.getResources().getString(R.string.folder_name);
}
@@ -469,7 +538,7 @@ public class AutoInstallsLayout implements WorkspaceLoader {
TagParser tagParser = mFolderElements.get(parser.getName());
if (tagParser != null) {
- final long id = tagParser.parseAndAdd(parser, res);
+ final long id = tagParser.parseAndAdd(parser);
if (id >= 0) {
folderItems.add(id);
}
@@ -508,7 +577,7 @@ public class AutoInstallsLayout implements WorkspaceLoader {
}
}
- private static final void beginDocument(XmlPullParser parser, String firstElementName)
+ protected static final void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -528,7 +597,7 @@ public class AutoInstallsLayout implements WorkspaceLoader {
* Return attribute value, attempting launcher-specific namespace first
* before falling back to anonymous attribute.
*/
- private static String getAttributeValue(XmlResourceParser parser, String attribute) {
+ protected static String getAttributeValue(XmlResourceParser parser, String attribute) {
String value = parser.getAttributeValue(
"http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute);
if (value == null) {
@@ -541,7 +610,7 @@ public class AutoInstallsLayout implements WorkspaceLoader {
* Return attribute resource value, attempting launcher-specific namespace
* first before falling back to anonymous attribute.
*/
- private static int getAttributeResourceValue(XmlResourceParser parser, String attribute,
+ protected static int getAttributeResourceValue(XmlResourceParser parser, String attribute,
int defaultValue) {
int value = parser.getAttributeResourceValue(
"http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute,
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
new file mode 100644
index 000000000..e3ea40ebb
--- /dev/null
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -0,0 +1,290 @@
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetHost;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Implements the layout parser with rules for internal layouts and partner layouts.
+ */
+public class DefaultLayoutParser extends AutoInstallsLayout {
+ private static final String TAG = "DefaultLayoutParser";
+
+ private static final String TAG_RESOLVE = "resolve";
+ private static final String TAG_FAVORITES = "favorites";
+ private static final String TAG_FAVORITE = "favorite";
+ private static final String TAG_APPWIDGET = "appwidget";
+ private static final String TAG_SHORTCUT = "shortcut";
+ private static final String TAG_FOLDER = "folder";
+ private static final String TAG_PARTNER_FOLDER = "partner-folder";
+ private static final String TAG_INCLUDE = "include";
+
+ private static final String ATTR_URI = "uri";
+ private static final String ATTR_WORKSPACE = "workspace";
+ private static final String ATTR_CONTAINER = "container";
+ private static final String ATTR_SCREEN = "screen";
+ private static final String ATTR_FOLDER_ITEMS = "folderItems";
+
+ public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
+ LayoutParserCallback callback, Resources sourceRes, int layoutId) {
+ super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
+ Log.e(TAG, "Default layout parser initialized");
+ }
+
+ @Override
+ protected HashMap<String, TagParser> getFolderElementsMap() {
+ return getFolderElementsMap(mSourceRes);
+ }
+
+ private HashMap<String, TagParser> getFolderElementsMap(Resources res) {
+ HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
+ parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
+ parsers.put(TAG_SHORTCUT, new UriShortcutParser(res));
+ return parsers;
+ }
+
+ @Override
+ protected HashMap<String, TagParser> getLayoutElementsMap() {
+ HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
+ parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
+ parsers.put(TAG_APPWIDGET, new AppWidgetParser());
+ parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes));
+ parsers.put(TAG_RESOLVE, new ResolveParser());
+ parsers.put(TAG_FOLDER, new MyFolderParser());
+ parsers.put(TAG_PARTNER_FOLDER, new PartnerFolderParser());
+ return parsers;
+ }
+
+ @Override
+ protected void parseContainerAndScreen(XmlResourceParser parser, long[] out) {
+ out[0] = LauncherSettings.Favorites.CONTAINER_DESKTOP;
+ String strContainer = getAttributeValue(parser, ATTR_CONTAINER);
+ if (strContainer != null) {
+ out[0] = Long.valueOf(strContainer);
+ }
+ out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
+ }
+
+ @Override
+ protected int parseAndAddNode(
+ XmlResourceParser parser,
+ HashMap<String, TagParser> tagParserMap,
+ ArrayList<Long> screenIds)
+ throws XmlPullParserException, IOException {
+ if (TAG_INCLUDE.equals(parser.getName())) {
+ final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
+ if (resId != 0) {
+ // recursively load some more favorites, why not?
+ return parseLayout(resId, screenIds);
+ } else {
+ return 0;
+ }
+ } else {
+ return super.parseAndAddNode(parser, tagParserMap, screenIds);
+ }
+ }
+
+ /**
+ * AppShortcutParser which also supports adding URI based intents
+ */
+ private class AppShortcutWithUriParser extends AppShortcutParser {
+
+ @Override
+ protected long invalidPackageOrClass(XmlResourceParser parser) {
+ final String uri = getAttributeValue(parser, ATTR_URI);
+ if (TextUtils.isEmpty(uri)) {
+ Log.e(TAG, "Skipping invalid <favorite> with no component or uri");
+ return -1;
+ }
+
+ final Intent metaIntent;
+ try {
+ metaIntent = Intent.parseUri(uri, 0);
+ } catch (URISyntaxException e) {
+ Log.e(TAG, "Unable to add meta-favorite: " + uri, e);
+ return -1;
+ }
+
+ ResolveInfo resolved = mPackageManager.resolveActivity(metaIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ final List<ResolveInfo> appList = mPackageManager.queryIntentActivities(
+ metaIntent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ // Verify that the result is an app and not just the resolver dialog asking which
+ // app to use.
+ if (wouldLaunchResolverActivity(resolved, appList)) {
+ // If only one of the results is a system app then choose that as the default.
+ final ResolveInfo systemApp = getSingleSystemActivity(appList);
+ if (systemApp == null) {
+ // There is no logical choice for this meta-favorite, so rather than making
+ // a bad choice just add nothing.
+ Log.w(TAG, "No preference or single system activity found for "
+ + metaIntent.toString());
+ return -1;
+ }
+ resolved = systemApp;
+ }
+ final ActivityInfo info = resolved.activityInfo;
+ final Intent intent = mPackageManager.getLaunchIntentForPackage(info.packageName);
+ if (intent == null) {
+ return -1;
+ }
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+ return addShortcut(info.loadLabel(mPackageManager).toString(), intent,
+ Favorites.ITEM_TYPE_APPLICATION);
+ }
+
+ private ResolveInfo getSingleSystemActivity(List<ResolveInfo> appList) {
+ ResolveInfo systemResolve = null;
+ final int N = appList.size();
+ for (int i = 0; i < N; ++i) {
+ try {
+ ApplicationInfo info = mPackageManager.getApplicationInfo(
+ appList.get(i).activityInfo.packageName, 0);
+ if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (systemResolve != null) {
+ return null;
+ } else {
+ systemResolve = appList.get(i);
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to get info about resolve results", e);
+ return null;
+ }
+ }
+ return systemResolve;
+ }
+
+ private boolean wouldLaunchResolverActivity(ResolveInfo resolved,
+ List<ResolveInfo> appList) {
+ // If the list contains the above resolved activity, then it can't be
+ // ResolverActivity itself.
+ for (int i = 0; i < appList.size(); ++i) {
+ ResolveInfo tmp = appList.get(i);
+ if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
+ && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+
+ /**
+ * Shortcut parser which allows any uri and not just web urls.
+ */
+ private class UriShortcutParser extends ShortcutParser {
+
+ public UriShortcutParser(Resources iconRes) {
+ super(iconRes);
+ }
+
+ @Override
+ protected Intent parseIntent(XmlResourceParser parser) {
+ String uri = null;
+ try {
+ uri = getAttributeValue(parser, ATTR_URI);
+ return Intent.parseUri(uri, 0);
+ } catch (URISyntaxException e) {
+ Log.w(TAG, "Shortcut has malformed uri: " + uri);
+ return null; // Oh well
+ }
+ }
+ }
+
+ /**
+ * Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
+ */
+ private class ResolveParser implements TagParser {
+
+ private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
+
+ @Override
+ public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ IOException {
+ final int groupDepth = parser.getDepth();
+ int type;
+ long addedId = -1;
+ while ((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > groupDepth) {
+ if (type != XmlPullParser.START_TAG || addedId > -1) {
+ continue;
+ }
+ final String fallback_item_name = parser.getName();
+ if (TAG_FAVORITE.equals(fallback_item_name)) {
+ addedId = mChildParser.parseAndAdd(parser);
+ } else {
+ Log.e(TAG, "Fallback groups can contain only favorites, found "
+ + fallback_item_name);
+ }
+ }
+ return addedId;
+ }
+ }
+
+ /**
+ * A parser which adds a folder whose contents come from partner apk.
+ */
+ private class PartnerFolderParser implements TagParser {
+
+ @Override
+ public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ IOException {
+ // Folder contents come from an external XML resource
+ final Partner partner = Partner.get(mPackageManager);
+ if (partner != null) {
+ final Resources partnerRes = partner.getResources();
+ final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER,
+ "xml", partner.getPackageName());
+ if (resId != 0) {
+ final XmlResourceParser partnerParser = partnerRes.getXml(resId);
+ beginDocument(partnerParser, TAG_FOLDER);
+
+ FolderParser folderParser = new FolderParser(getFolderElementsMap(partnerRes));
+ return folderParser.parseAndAdd(partnerParser);
+ }
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * An extension of FolderParser which allows adding items from a different xml.
+ */
+ private class MyFolderParser extends FolderParser {
+
+ @Override
+ public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ IOException {
+ final int resId = getAttributeResourceValue(parser, ATTR_FOLDER_ITEMS, 0);
+ if (resId != 0) {
+ parser = mSourceRes.getXml(resId);
+ beginDocument(parser, TAG_FOLDER);
+ }
+ return super.parseAndAdd(parser);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 05e8906cb..ea058ea71 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -21,8 +21,6 @@ import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -41,12 +39,8 @@ import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
-import java.util.List;
-import java.util.Set;
-
public class DeleteDropTarget extends ButtonDropTarget {
private static int DELETE_ANIMATION_DURATION = 285;
private static int FLING_DELETE_ANIMATION_DURATION = 350;
@@ -266,7 +260,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
public void run() {
completeDrop(d);
mSearchDropTargetBar.onDragEnd();
- mLauncher.exitSpringLoadedDragMode();
+ mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null);
}
};
dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index daf5556d4..b2366bb2b 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -75,7 +75,6 @@ public class DeviceProfile {
private float hotseatIconSize;
int defaultLayoutId;
- int defaultNoAllAppsLayoutId;
boolean isLandscape;
boolean isTablet;
@@ -136,7 +135,7 @@ public class DeviceProfile {
private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
DeviceProfile(String n, float w, float h, float r, float c,
- float is, float its, float hs, float his, int dlId, int dnalId) {
+ float is, float its, float hs, float his, int dlId) {
// Ensure that we have an odd number of hotseat items (since we need to place all apps)
if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) {
throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
@@ -152,7 +151,6 @@ public class DeviceProfile {
numHotseatIcons = hs;
hotseatIconSize = his;
defaultLayoutId = dlId;
- defaultNoAllAppsLayoutId = dnalId;
}
DeviceProfile() {
@@ -215,9 +213,6 @@ public class DeviceProfile {
// Snap to the closest default layout id
defaultLayoutId = closestProfile.defaultLayoutId;
- // Snap to the closest default no all-apps layout id
- defaultNoAllAppsLayoutId = closestProfile.defaultNoAllAppsLayoutId;
-
// Interpolate the icon size
points.clear();
for (DeviceProfile p : profiles) {
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 94a07d706..aa08148d2 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -60,41 +60,30 @@ public class DynamicGrid {
DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm);
// Our phone profiles include the bar sizes in each orientation
deviceProfiles.add(new DeviceProfile("Super Short Stubby",
- 255, 300, 2, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 255, 300, 2, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Shorter Stubby",
- 255, 400, 3, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 255, 400, 3, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Short Stubby",
- 275, 420, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 275, 420, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Stubby",
- 255, 450, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 255, 450, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus S",
- 296, 491.33f, 4, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 296, 491.33f, 4, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus 4",
- 335, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 335, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Nexus 5",
- 359, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 359, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Large Phone",
- 406, 694, 5, 5, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5,
- R.xml.default_workspace_5x5_no_all_apps));
+ 406, 694, 5, 5, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5));
// The tablet profile is odd in that the landscape orientation
// also includes the nav bar on the side
deviceProfiles.add(new DeviceProfile("Nexus 7",
- 575, 904, 5, 6, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6,
- R.xml.default_workspace_5x6_no_all_apps));
+ 575, 904, 5, 6, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6));
// Larger tablet profiles always have system bars on the top & bottom
deviceProfiles.add(new DeviceProfile("Nexus 10",
- 727, 1207, 5, 6, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6,
- R.xml.default_workspace_5x6_no_all_apps));
+ 727, 1207, 5, 6, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6));
deviceProfiles.add(new DeviceProfile("20-inch Tablet",
- 1527, 2527, 7, 7, 100, 20, 7, 72, R.xml.default_workspace_4x4,
- R.xml.default_workspace_4x4_no_all_apps));
+ 1527, 2527, 7, 7, 100, 20, 7, 72, R.xml.default_workspace_4x4));
mMinWidth = dpiFromPx(minWidthPx, dm);
mMinHeight = dpiFromPx(minHeightPx, dm);
mProfile = new DeviceProfile(context, deviceProfiles,
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
index 12b7a4076..7d4664abb 100644
--- a/src/com/android/launcher3/FocusIndicatorView.java
+++ b/src/com/android/launcher3/FocusIndicatorView.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
@@ -28,6 +30,7 @@ public class FocusIndicatorView extends View implements View.OnFocusChangeListen
// It can be any number >0. The view is resized using scaleX and scaleY.
static final int DEFAULT_LAYOUT_SIZE = 100;
private static final float MIN_VISIBLE_ALPHA = 0.2f;
+ private static final long ANIM_DURATION = 150;
private static final int[] sTempPos = new int[2];
private static final int[] sTempShift = new int[2];
@@ -35,6 +38,9 @@ public class FocusIndicatorView extends View implements View.OnFocusChangeListen
private final int[] mIndicatorPos = new int[2];
private final int[] mTargetViewPos = new int[2];
+ private ObjectAnimator mCurrentAnimation;
+ private ViewAnimState mTargetState;
+
private View mLastFocusedView;
private boolean mInitiated;
@@ -82,34 +88,58 @@ public class FocusIndicatorView extends View implements View.OnFocusChangeListen
int indicatorWidth = getWidth();
int indicatorHeight = getHeight();
- float scaleX = v.getScaleX() * v.getWidth() / indicatorWidth;
- float scaleY = v.getScaleY() * v.getHeight() / indicatorHeight;
+ endCurrentAnimation();
+ ViewAnimState nextState = new ViewAnimState();
+ nextState.scaleX = v.getScaleX() * v.getWidth() / indicatorWidth;
+ nextState.scaleY = v.getScaleY() * v.getHeight() / indicatorHeight;
getLocationRelativeToParentPagedView(v, mTargetViewPos);
- float x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - scaleX) * indicatorWidth / 2;
- float y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - scaleY) * indicatorHeight / 2;
+ nextState.x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - nextState.scaleX) * indicatorWidth / 2;
+ nextState.y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - nextState.scaleY) * indicatorHeight / 2;
if (getAlpha() > MIN_VISIBLE_ALPHA) {
- animate()
- .translationX(x)
- .translationY(y)
- .scaleX(scaleX)
- .scaleY(scaleY)
- .alpha(1);
+ mTargetState = nextState;
+ mCurrentAnimation = LauncherAnimUtils.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(View.ALPHA, 1),
+ PropertyValuesHolder.ofFloat(View.TRANSLATION_X, mTargetState.x),
+ PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, mTargetState.y),
+ PropertyValuesHolder.ofFloat(View.SCALE_X, mTargetState.scaleX),
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, mTargetState.scaleY));
} else {
- setTranslationX(x);
- setTranslationY(y);
- setScaleX(scaleX);
- setScaleY(scaleY);
- animate().alpha(1);
+ applyState(nextState);
+ mCurrentAnimation = LauncherAnimUtils.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(View.ALPHA, 1));
}
mLastFocusedView = v;
} else {
if (mLastFocusedView == v) {
mLastFocusedView = null;
- animate().alpha(0);
+ endCurrentAnimation();
+ mCurrentAnimation = LauncherAnimUtils.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(View.ALPHA, 0));
}
}
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.setDuration(ANIM_DURATION).start();
+ }
+ }
+
+ private void endCurrentAnimation() {
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.cancel();
+ mCurrentAnimation = null;
+ }
+ if (mTargetState != null) {
+ applyState(mTargetState);
+ mTargetState = null;
+ }
+ }
+
+ private void applyState(ViewAnimState state) {
+ setTranslationX(state.x);
+ setTranslationY(state.y);
+ setScaleX(state.scaleX);
+ setScaleY(state.scaleY);
}
@Override
@@ -143,4 +173,8 @@ public class FocusIndicatorView extends View implements View.OnFocusChangeListen
shift[0] = shift[1] = 0;
}
}
+
+ private static final class ViewAnimState {
+ float x, y, scaleX, scaleY;
+ }
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 06f9f2941..5a0875b30 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -24,7 +24,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -117,8 +116,7 @@ public class IconCache {
}
public Drawable getFullResDefaultActivityIcon() {
- return getFullResIcon(Resources.getSystem(),
- android.R.mipmap.sym_def_app_icon);
+ return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
}
private Drawable getFullResIcon(Resources resources, int iconId) {
@@ -151,12 +149,7 @@ public class IconCache {
return mIconDpi;
}
- public Drawable getFullResIcon(ResolveInfo info) {
- return getFullResIcon(info.activityInfo);
- }
-
public Drawable getFullResIcon(ActivityInfo info) {
-
Resources resources;
try {
resources = mPackageManager.getResourcesForApplication(
@@ -190,16 +183,14 @@ public class IconCache {
/**
* Remove any records for the supplied ComponentName.
*/
- public void remove(ComponentName componentName, UserHandleCompat user) {
- synchronized (mCache) {
- mCache.remove(new CacheKey(componentName, user));
- }
+ public synchronized void remove(ComponentName componentName, UserHandleCompat user) {
+ mCache.remove(new CacheKey(componentName, user));
}
/**
* Remove any records for the supplied package name.
*/
- public void remove(String packageName, UserHandleCompat user) {
+ public synchronized void remove(String packageName, UserHandleCompat user) {
HashSet<CacheKey> forDeletion = new HashSet<CacheKey>();
for (CacheKey key: mCache.keySet()) {
if (key.componentName.getPackageName().equals(packageName)
@@ -215,24 +206,20 @@ public class IconCache {
/**
* Empty out the cache.
*/
- public void flush() {
- synchronized (mCache) {
- mCache.clear();
- }
+ public synchronized void flush() {
+ mCache.clear();
}
/**
* Empty out the cache that aren't of the correct grid size
*/
- public void flushInvalidIcons(DeviceProfile grid) {
- synchronized (mCache) {
- Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator();
- while (it.hasNext()) {
- final CacheEntry e = it.next().getValue();
- if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx
- || e.icon.getHeight() < grid.iconSizePx)) {
- it.remove();
- }
+ public synchronized void flushInvalidIcons(DeviceProfile grid) {
+ Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator();
+ while (it.hasNext()) {
+ final CacheEntry e = it.next().getValue();
+ if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx
+ || e.icon.getHeight() < grid.iconSizePx)) {
+ it.remove();
}
}
}
@@ -240,90 +227,78 @@ public class IconCache {
/**
* Fill in "application" with the icon and label for "info."
*/
- public void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info,
+ public synchronized void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info,
HashMap<Object, CharSequence> labelCache) {
- synchronized (mCache) {
- CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
- info.getUser(), false);
-
- application.title = entry.title;
- application.iconBitmap = entry.icon;
- application.contentDescription = entry.contentDescription;
- }
- }
+ CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
+ info.getUser(), false);
- public Bitmap getIcon(Intent intent, UserHandleCompat user) {
- return getIcon(intent, null, user, true);
+ application.title = entry.title;
+ application.iconBitmap = entry.icon;
+ application.contentDescription = entry.contentDescription;
}
- private Bitmap getIcon(Intent intent, String title, UserHandleCompat user, boolean usePkgIcon) {
- synchronized (mCache) {
- ComponentName component = intent.getComponent();
- // null info means not installed, but if we have a component from the intent then
- // we should still look in the cache for restored app icons.
- if (component == null) {
- return getDefaultIcon(user);
- }
-
- LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
- CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon);
- if (title != null) {
- entry.title = title;
- entry.contentDescription = mUserManager.getBadgedLabelForUser(title, user);
- }
- return entry.icon;
+ public synchronized Bitmap getIcon(Intent intent, UserHandleCompat user) {
+ ComponentName component = intent.getComponent();
+ // null info means not installed, but if we have a component from the intent then
+ // we should still look in the cache for restored app icons.
+ if (component == null) {
+ return getDefaultIcon(user);
}
+
+ LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
+ CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, true);
+ return entry.icon;
}
/**
* Fill in "shortcutInfo" with the icon and label for "info."
*/
- public void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent, UserHandleCompat user,
- boolean usePkgIcon) {
- synchronized (mCache) {
- ComponentName component = intent.getComponent();
- // null info means not installed, but if we have a component from the intent then
- // we should still look in the cache for restored app icons.
- if (component == null) {
- shortcutInfo.setIcon(getDefaultIcon(user));
- shortcutInfo.title = "";
- shortcutInfo.usingFallbackIcon = true;
- } else {
- LauncherActivityInfoCompat launcherActInfo =
- mLauncherApps.resolveActivity(intent, user);
- CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon);
+ public synchronized void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent,
+ UserHandleCompat user, boolean usePkgIcon) {
+ ComponentName component = intent.getComponent();
+ // null info means not installed, but if we have a component from the intent then
+ // we should still look in the cache for restored app icons.
+ if (component == null) {
+ shortcutInfo.setIcon(getDefaultIcon(user));
+ shortcutInfo.title = "";
+ shortcutInfo.usingFallbackIcon = true;
+ } else {
+ LauncherActivityInfoCompat launcherActInfo =
+ mLauncherApps.resolveActivity(intent, user);
+ CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon);
- shortcutInfo.setIcon(entry.icon);
- shortcutInfo.title = entry.title;
- shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
- }
+ shortcutInfo.setIcon(entry.icon);
+ shortcutInfo.title = entry.title;
+ shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
}
}
- public Bitmap getDefaultIcon(UserHandleCompat user) {
+ public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
if (!mDefaultIcons.containsKey(user)) {
mDefaultIcons.put(user, makeDefaultIcon(user));
}
return mDefaultIcons.get(user);
}
- public Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info,
+ public synchronized Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info,
HashMap<Object, CharSequence> labelCache) {
- synchronized (mCache) {
- if (info == null || component == null) {
- return null;
- }
-
- CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false);
- return entry.icon;
+ if (info == null || component == null) {
+ return null;
}
+
+ CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false);
+ return entry.icon;
}
public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) {
return mDefaultIcons.get(user) == icon;
}
+ /**
+ * Retrieves the entry from the cache. If the entry is not present, it creates a new entry.
+ * This method is not thread safe, it must be called from a synchronized method.
+ */
private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info,
HashMap<Object, CharSequence> labelCache, UserHandleCompat user, boolean usePackageIcon) {
CacheKey cacheKey = new CacheKey(componentName, user);
@@ -380,7 +355,7 @@ public class IconCache {
* Adds a default package entry in the cache. This entry is not persisted and will be removed
* when the cache is flushed.
*/
- public void cachePackageInstallInfo(String packageName, UserHandleCompat user,
+ public synchronized void cachePackageInstallInfo(String packageName, UserHandleCompat user,
Bitmap icon, CharSequence title) {
remove(packageName, user);
@@ -395,9 +370,10 @@ public class IconCache {
/**
* Gets an entry for the package, which can be used as a fallback entry for various components.
+ * This method is not thread safe, it must be called from a synchronized method.
*/
private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) {
- ComponentName cn = getPackageComponent(packageName);
+ ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME);;
CacheKey cacheKey = new CacheKey(cn, user);
CacheEntry entry = mCache.get(cacheKey);
if (entry == null) {
@@ -420,15 +396,13 @@ public class IconCache {
return entry;
}
- public HashMap<ComponentName,Bitmap> getAllIcons() {
- synchronized (mCache) {
- HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
- for (CacheKey ck : mCache.keySet()) {
- final CacheEntry e = mCache.get(ck);
- set.put(ck.componentName, e.icon);
- }
- return set;
+ public synchronized HashMap<ComponentName,Bitmap> getAllIcons() {
+ HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
+ for (CacheKey ck : mCache.keySet()) {
+ final CacheEntry e = mCache.get(ck);
+ set.put(ck.componentName, e.icon);
}
+ return set;
}
/**
@@ -534,23 +508,15 @@ public class IconCache {
* Remove a pre-loaded icon from the persistent icon cache.
*
* @param componentName the component that should own the icon
- * @returns true on success
*/
- public boolean deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) {
+ public void deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) {
// We don't keep icons for other profiles in persistent cache.
- if (!user.equals(UserHandleCompat.myUserHandle())) {
- return false;
- }
- if (componentName == null) {
- return false;
- }
- if (mCache.remove(componentName) != null) {
- if (DEBUG) Log.d(TAG, "removed pre-loaded icon from the in-memory cache");
+ if (!user.equals(UserHandleCompat.myUserHandle()) || componentName == null) {
+ return;
}
+ remove(componentName, user);
boolean success = mContext.deleteFile(getResourceFilename(componentName));
if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache");
-
- return success;
}
private static String getResourceFilename(ComponentName component) {
@@ -558,8 +524,4 @@ public class IconCache {
String filename = resourceName.replace(File.separatorChar, '_');
return RESOURCE_FILE_PREFIX + filename;
}
-
- static ComponentName getPackageComponent(String packageName) {
- return new ComponentName(packageName, EMPTY_CLASS_NAME);
- }
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 2edde4fae..e9fb499ad 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -45,17 +44,17 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
private static final String TAG = "InstallShortcutReceiver";
private static final boolean DBG = false;
- public static final String ACTION_INSTALL_SHORTCUT =
+ private static final String ACTION_INSTALL_SHORTCUT =
"com.android.launcher.action.INSTALL_SHORTCUT";
- public static final String DATA_INTENT_KEY = "intent.data";
- public static final String LAUNCH_INTENT_KEY = "intent.launch";
- public static final String NAME_KEY = "name";
- public static final String ICON_KEY = "icon";
- public static final String ICON_RESOURCE_NAME_KEY = "iconResource";
- public static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
+ private static final String DATA_INTENT_KEY = "intent.data";
+ private static final String LAUNCH_INTENT_KEY = "intent.launch";
+ private static final String NAME_KEY = "name";
+ private static final String ICON_KEY = "icon";
+ private static final String ICON_RESOURCE_NAME_KEY = "iconResource";
+ private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
// The set of shortcuts that are pending install
- public static final String APPS_PENDING_INSTALL = "apps_to_install";
+ private static final String APPS_PENDING_INSTALL = "apps_to_install";
public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
@@ -63,17 +62,13 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
private static final int INSTALL_SHORTCUT_SUCCESSFUL = 0;
private static final int INSTALL_SHORTCUT_IS_DUPLICATE = -1;
- // A mime-type representing shortcut data
- public static final String SHORTCUT_MIMETYPE =
- "com.android.launcher3/shortcut";
-
private static Object sLock = new Object();
private static void addToStringSet(SharedPreferences sharedPrefs,
SharedPreferences.Editor editor, String key, String value) {
Set<String> strings = sharedPrefs.getStringSet(key, null);
if (strings == null) {
- strings = new HashSet<String>(0);
+ strings = new HashSet<String>(1);
} else {
strings = new HashSet<String>(strings);
}
@@ -133,6 +128,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
Intent launchIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
String pn = launchIntent.getPackage();
if (pn == null) {
+ if (launchIntent.getComponent() == null) {
+ continue;
+ }
pn = launchIntent.getComponent().getPackageName();
}
if (packageNames.contains(pn)) {
@@ -355,7 +353,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}
LauncherAppState app = LauncherAppState.getInstance();
- ShortcutInfo info = app.getModel().infoFromShortcutIntent(context, data, null);
+ ShortcutInfo info = app.getModel().infoFromShortcutIntent(context, data);
info.title = ensureValidName(context, launchIntent, info.title);
return info;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3762c2f50..178f6cb56 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -404,6 +404,10 @@ public class Launcher extends Activity
.build());
}
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.preOnCreate();
+ }
+
super.onCreate(savedInstanceState);
LauncherAppState.setApplicationContext(getApplicationContext());
@@ -500,13 +504,38 @@ public class Launcher extends Activity
showFirstRunActivity();
showFirstRunClings();
}
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onCreate(savedInstanceState);
+ }
+ }
+
+ private LauncherCallbacks mLauncherCallbacks;
+
+ public void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onPostCreate(savedInstanceState);
+ }
+ }
+
+ public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
+ mLauncherCallbacks = callbacks;
+ return true;
}
@Override
- public void onLauncherProviderChange() { }
+ public void onLauncherProviderChange() {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onLauncherProviderChange();
+ }
+ }
- /** To be overriden by subclasses to hint to Launcher that we have custom content */
+ /** To be overridden by subclasses to hint to Launcher that we have custom content */
protected boolean hasCustomContentToLeft() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.hasCustomContentToLeft();
+ }
return false;
}
@@ -516,6 +545,9 @@ public class Launcher extends Activity
* {@link #hasCustomContentToLeft()} is {@code true}.
*/
protected void populateCustomContentContainer() {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.populateCustomContentContainer();
+ }
}
/**
@@ -617,7 +649,7 @@ public class Launcher extends Activity
private static void readConfiguration(Context context, LocaleConfiguration configuration) {
DataInputStream in = null;
try {
- in = new DataInputStream(context.openFileInput(LauncherFiles.LAUNCHER_PREFS));
+ in = new DataInputStream(context.openFileInput(LauncherFiles.LAUNCHER_PREFERENCES));
configuration.locale = in.readUTF();
configuration.mcc = in.readInt();
configuration.mnc = in.readInt();
@@ -640,7 +672,7 @@ public class Launcher extends Activity
DataOutputStream out = null;
try {
out = new DataOutputStream(context.openFileOutput(
- LauncherFiles.LAUNCHER_PREFS, MODE_PRIVATE));
+ LauncherFiles.LAUNCHER_PREFERENCES, MODE_PRIVATE));
out.writeUTF(configuration.locale);
out.writeInt(configuration.mcc);
out.writeInt(configuration.mnc);
@@ -649,7 +681,7 @@ public class Launcher extends Activity
// Ignore
} catch (IOException e) {
//noinspection ResultOfMethodCallIgnored
- context.getFileStreamPath(LauncherFiles.LAUNCHER_PREFS).delete();
+ context.getFileStreamPath(LauncherFiles.LAUNCHER_PREFERENCES).delete();
} finally {
if (out != null) {
try {
@@ -954,12 +986,20 @@ public class Launcher extends Activity
protected void onStop() {
super.onStop();
FirstFrameAnimatorHelper.setIsVisible(false);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onStop();
+ }
}
@Override
protected void onStart() {
super.onStart();
FirstFrameAnimatorHelper.setIsVisible(true);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onStart();
+ }
}
@Override
@@ -969,6 +1009,11 @@ public class Launcher extends Activity
startTime = System.currentTimeMillis();
Log.v(TAG, "Launcher.onResume()");
}
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.preOnResume();
+ }
+
super.onResume();
// Restore the previous launcher state
@@ -1057,6 +1102,10 @@ public class Launcher extends Activity
mWorkspace.onResume();
PackageInstallerCompat.getInstance(this).onResume();
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onResume();
+ }
}
@Override
@@ -1075,25 +1124,10 @@ public class Launcher extends Activity
if (mWorkspace.getCustomContentCallbacks() != null) {
mWorkspace.getCustomContentCallbacks().onHide();
}
- }
-
- QSBScroller mQsbScroller = new QSBScroller() {
- int scrollY = 0;
- @Override
- public void setScrollY(int scroll) {
- scrollY = scroll;
-
- if (mWorkspace.isOnOrMovingToCustomContent()) {
- mSearchDropTargetBar.setTranslationY(- scrollY);
- getQsbBar().setTranslationY(-scrollY);
- }
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onPause();
}
- };
-
- public void resetQSBScroll() {
- mSearchDropTargetBar.animate().translationY(0).start();
- getQsbBar().animate().translationY(0).start();
}
public interface CustomContentCallbacks {
@@ -1112,17 +1146,16 @@ public class Launcher extends Activity
}
protected boolean hasSettings() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.hasSettings();
+ }
return false;
}
- public interface QSBScroller {
- public void setScrollY(int scrollY);
- }
- public QSBScroller addToCustomContentPage(View customContent,
+ public void addToCustomContentPage(View customContent,
CustomContentCallbacks callbacks, String description) {
mWorkspace.addToCustomContentPage(customContent, callbacks, description);
- return mQsbScroller;
}
// The custom content needs to offset its content to account for the QSB
@@ -1147,6 +1180,10 @@ public class Launcher extends Activity
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
mHasFocus = hasFocus;
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onWindowFocusChanged(hasFocus);
+ }
}
private boolean acceptFilter() {
@@ -1333,9 +1370,6 @@ public class Launcher extends Activity
settingsButton.setOnTouchListener(getHapticFeedbackTouchListener());
} else {
settingsButton.setVisibility(View.GONE);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) widgetButton.getLayoutParams();
- lp.gravity = Gravity.END | Gravity.TOP;
- widgetButton.requestLayout();
}
mOverviewPanel.setAlpha(0f);
@@ -1435,7 +1469,7 @@ public class Launcher extends Activity
boolean foundCellSpan = false;
- ShortcutInfo info = mModel.infoFromShortcutIntent(this, data, null);
+ ShortcutInfo info = mModel.infoFromShortcutIntent(this, data);
if (info == null) {
return;
}
@@ -1885,8 +1919,11 @@ public class Launcher extends Activity
Folder openFolder = mWorkspace.getOpenFolder();
// In all these cases, only animate if we're already on home
mWorkspace.exitWidgetResizeMode();
+
+ boolean moveToDefaultScreen = mLauncherCallbacks != null ?
+ mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true;
if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
- openFolder == null && shouldMoveToDefaultScreenOnHomeIntent()) {
+ openFolder == null && moveToDefaultScreen) {
mWorkspace.moveToDefaultScreen(true);
}
@@ -1913,27 +1950,18 @@ public class Launcher extends Activity
mAppsCustomizeTabHost.reset();
}
- onHomeIntent();
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onHomeIntent();
+ }
}
if (DEBUG_RESUME_TIME) {
Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime));
}
- }
-
- /**
- * Override point for subclasses to prevent movement to the default screen when the home
- * button is pressed. Used (for example) in GEL, to prevent movement during a search.
- */
- protected boolean shouldMoveToDefaultScreenOnHomeIntent() {
- return true;
- }
- /**
- * Override point for subclasses to provide custom behaviour for when a home intent is fired.
- */
- protected void onHomeIntent() {
- // Do nothing
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onNewIntent(intent);
+ }
}
@Override
@@ -1985,6 +2013,10 @@ public class Launcher extends Activity
outState.putInt("apps_customize_currentIndex", currentIndex);
}
outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onSaveInstanceState(outState);
+ }
}
@Override
@@ -2033,6 +2065,10 @@ public class Launcher extends Activity
mDragController = null;
LauncherAnimUtils.onDestroyActivity();
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onDestroy();
+ }
}
public DragController getDragController() {
@@ -2086,6 +2122,11 @@ public class Launcher extends Activity
*/
public boolean startSearch(String initialQuery,
boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
+ return mLauncherCallbacks.startSearch(initialQuery, selectInitialQuery, appSearchData,
+ sourceBounds);
+ }
+
startGlobalSearch(initialQuery, selectInitialQuery,
appSearchData, sourceBounds);
return false;
@@ -2112,7 +2153,7 @@ public class Launcher extends Activity
} else {
appSearchData = new Bundle(appSearchData);
}
- // Set source to package name of app that starts global search, if not set already.
+ // Set source to package name of app that starts global search if not set already.
if (!appSearchData.containsKey("source")) {
appSearchData.putString("source", getPackageName());
}
@@ -2150,6 +2191,10 @@ public class Launcher extends Activity
showWorkspace(true);
}
}
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.onPrepareOptionsMenu(menu);
+ }
+
return false;
}
@@ -2184,7 +2229,11 @@ public class Launcher extends Activity
}
}
- protected void onWorkspaceLockedChanged() { }
+ protected void onWorkspaceLockedChanged() {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onWorkspaceLockedChanged();
+ }
+ }
private void resetAddInfo() {
mPendingAddInfo.container = ItemInfo.NO_ID;
@@ -2346,6 +2395,9 @@ public class Launcher extends Activity
}
protected ComponentName getWallpaperPickerComponent() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.getWallpaperPickerComponent();
+ }
return new ComponentName(getPackageName(), LauncherWallpaperPickerActivity.class.getName());
}
@@ -2384,6 +2436,10 @@ public class Launcher extends Activity
@Override
public void onBackPressed() {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.handleBackPressed()) {
+ return;
+ }
+
if (isAllAppsVisible()) {
if (mAppsCustomizeContent.getContentType() ==
AppsCustomizePagedView.ContentType.Applications) {
@@ -2466,6 +2522,9 @@ public class Launcher extends Activity
public void onClickPagedViewIcon(View v) {
startAppShortcutOrInfoActivity(v);
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickPagedViewIcon(v);
+ }
}
public boolean onTouch(View v, MotionEvent event) {
@@ -2476,6 +2535,11 @@ public class Launcher extends Activity
* Event handler for the app widget view which has not fully restored.
*/
public void onClickPendingWidget(final PendingAppWidgetHostView v) {
+ if (mIsSafeModeEnabled) {
+ Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
if (v.isReadyForClickSetup()) {
int widgetId = info.appWidgetId;
@@ -2527,6 +2591,11 @@ public class Launcher extends Activity
}
public void startVoice() {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
+ mLauncherCallbacks.startVoice();
+ return;
+ }
+
try {
final SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
@@ -2557,6 +2626,9 @@ public class Launcher extends Activity
} else {
showAllApps(true, AppsCustomizePagedView.ContentType.Applications, false);
}
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickAllAppsButton(v);
+ }
}
private void showBrokenAppInstallDialog(final String packageName,
@@ -2631,6 +2703,10 @@ public class Launcher extends Activity
// Start activities
startAppShortcutOrInfoActivity(v);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickAppShortcut(v);
+ }
}
private void startAppShortcutOrInfoActivity(View v) {
@@ -2704,6 +2780,10 @@ public class Launcher extends Activity
}
}
}
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickFolderIcon(v);
+ }
}
/**
@@ -2712,7 +2792,14 @@ public class Launcher extends Activity
*/
protected void onClickAddWidgetButton(View view) {
if (LOGD) Log.d(TAG, "onClickAddWidgetButton");
- showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true);
+ if (mIsSafeModeEnabled) {
+ Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+ } else {
+ showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true);
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickAddWidgetButton(view);
+ }
+ }
}
/**
@@ -2724,6 +2811,10 @@ public class Launcher extends Activity
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
pickWallpaper.setComponent(getWallpaperPickerComponent());
startActivityForResult(pickWallpaper, REQUEST_PICK_WALLPAPER);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickWallpaperPicker(v);
+ }
}
/**
@@ -2732,6 +2823,9 @@ public class Launcher extends Activity
*/
protected void onClickSettingsButton(View v) {
if (LOGD) Log.d(TAG, "onClickSettingsButton");
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickSettingsButton(v);
+ }
}
public void onTouchDownAllAppsButton(View v) {
@@ -2759,13 +2853,27 @@ public class Launcher extends Activity
return mHapticFeedbackTouchListener;
}
- public void onDragStarted(View view) {}
+ public void onDragStarted(View view) {
+ if (isOnCustomContent()) {
+ // Custom content screen doesn't participate in drag and drop. If on custom
+ // content screen, move to default.
+ moveWorkspaceToDefaultScreen();
+ }
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onDragStarted(view);
+ }
+ }
/**
* Called when the user stops interacting with the launcher.
* This implies that the user is now on the homescreen and is not doing housekeeping.
*/
- protected void onInteractionEnd() {}
+ protected void onInteractionEnd() {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onInteractionEnd();
+ }
+ }
/**
* Called when the user starts interacting with the launcher.
@@ -2776,7 +2884,11 @@ public class Launcher extends Activity
* This is a good time to stop doing things that only make sense
* when the user is on the homescreen and not doing housekeeping.
*/
- protected void onInteractionBegin() {}
+ protected void onInteractionBegin() {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onInteractionBegin();
+ }
+ }
void startApplicationDetailsActivity(ComponentName componentName, UserHandleCompat user) {
String packageName = componentName.getPackageName();
@@ -3972,6 +4084,13 @@ public class Launcher extends Activity
}
public View getQsbBar() {
+ if (mLauncherCallbacks != null) {
+ View qsb = mLauncherCallbacks.getQsbBar();
+ if (qsb != null) {
+ return qsb;
+ }
+ }
+
if (mQsb == null) {
mQsb = mInflater.inflate(R.layout.qsb, mSearchDropTargetBar, false);
mSearchDropTargetBar.addView(mQsb);
@@ -3980,6 +4099,10 @@ public class Launcher extends Activity
}
protected boolean updateGlobalSearchIcon() {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
+ return true;
+ }
+
final View searchButtonContainer = findViewById(R.id.search_button_container);
final ImageView searchButton = (ImageView) findViewById(R.id.search_button);
final View voiceButtonContainer = findViewById(R.id.voice_button_container);
@@ -4015,6 +4138,7 @@ public class Launcher extends Activity
}
protected void updateGlobalSearchIcon(Drawable.ConstantState d) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) return;
final View searchButtonContainer = findViewById(R.id.search_button_container);
final View searchButton = (ImageView) findViewById(R.id.search_button);
updateButtonWithDrawable(R.id.search_button, d);
@@ -4022,6 +4146,9 @@ public class Launcher extends Activity
}
protected boolean updateVoiceSearchIcon(boolean searchVisible) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
+ return true;
+ }
final View voiceButtonContainer = findViewById(R.id.voice_button_container);
final View voiceButton = findViewById(R.id.voice_button);
@@ -4068,6 +4195,10 @@ public class Launcher extends Activity
}
protected void updateVoiceSearchIcon(Drawable.ConstantState d) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
+ return;
+ }
+
final View voiceButtonContainer = findViewById(R.id.voice_button_container);
final View voiceButton = findViewById(R.id.voice_button);
updateButtonWithDrawable(R.id.voice_button, d);
@@ -4075,6 +4206,9 @@ public class Launcher extends Activity
}
public void updateVoiceButtonProxyVisible(boolean forceDisableVoiceButtonProxy) {
+ if (mLauncherCallbacks != null) {
+ forceDisableVoiceButtonProxy |= mLauncherCallbacks.forceDisableVoiceButtonProxy();
+ }
final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
if (voiceButtonProxy != null) {
boolean visible = !forceDisableVoiceButtonProxy &&
@@ -4462,8 +4596,9 @@ public class Launcher extends Activity
final Workspace workspace = mWorkspace;
AppWidgetProviderInfo appWidgetInfo;
- if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0) &&
- ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
+ if (!mIsSafeModeEnabled
+ && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
+ && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
appWidgetInfo = mModel.findAppWidgetProviderInfoWithComponent(this, item.providerName);
if (appWidgetInfo == null) {
@@ -4513,7 +4648,7 @@ public class Launcher extends Activity
LauncherModel.updateItemInDatabase(this, item);
}
- if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
final int appWidgetId = item.appWidgetId;
appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (DEBUG_WIDGETS) {
@@ -4523,7 +4658,8 @@ public class Launcher extends Activity
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
} else {
appWidgetInfo = null;
- PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item);
+ PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item,
+ mIsSafeModeEnabled);
view.updateIcon(mIconCache);
item.hostView = view;
item.hostView.updateAppWidget(null);
@@ -4617,6 +4753,10 @@ public class Launcher extends Activity
mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
}
PackageInstallerCompat.getInstance(this).onFinishBind();
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.finishBindingItems(upgradePath);
+ }
}
private void sendLoadingCompleteBroadcastIfNecessary() {
@@ -4698,6 +4838,9 @@ public class Launcher extends Activity
LauncherModel.getSortedWidgetsAndShortcuts(this));
}
}
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.bindAllApplications(apps);
+ }
}
/**
@@ -4916,16 +5059,10 @@ public class Launcher extends Activity
}
}
- /**
- * Called when the SearchBar hint should be changed.
- *
- * @param hint the hint to be displayed in the search bar.
- */
- protected void onSearchBarHintChanged(String hint) {
-
- }
-
protected boolean isLauncherPreinstalled() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.isLauncherPreinstalled();
+ }
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(getComponentName().getPackageName(), 0);
@@ -4945,6 +5082,9 @@ public class Launcher extends Activity
* when our wallpaper cropper was not yet used to set a wallpaper.
*/
protected boolean overrideWallpaperDimensions() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.overrideWallpaperDimensions();
+ }
return true;
}
@@ -4953,6 +5093,9 @@ public class Launcher extends Activity
* before showing the standard launcher experience.
*/
protected boolean hasFirstRunActivity() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.hasFirstRunActivity();
+ }
return false;
}
@@ -4960,6 +5103,9 @@ public class Launcher extends Activity
* To be overridden by subclasses to launch any first run activity
*/
protected Intent getFirstRunActivity() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.getFirstRunActivity();
+ }
return null;
}
@@ -4996,6 +5142,9 @@ public class Launcher extends Activity
* screen that must be displayed and dismissed.
*/
protected boolean hasDismissableIntroScreen() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.hasDismissableIntroScreen();
+ }
return false;
}
@@ -5003,6 +5152,9 @@ public class Launcher extends Activity
* Full screen intro screen to be shown and dismissed before the launcher can be used.
*/
protected View getIntroScreen() {
+ if (mLauncherCallbacks != null) {
+ return mLauncherCallbacks.getIntroScreen();
+ }
return null;
}
@@ -5114,6 +5266,9 @@ public class Launcher extends Activity
@Override
public void onPageSwitch(View newPage, int newPageIndex) {
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onPageSwitch(newPage, newPageIndex);
+ }
}
/**
@@ -5145,6 +5300,9 @@ public class Launcher extends Activity
writer.println(" " + sDumpLogs.get(i));
}
}
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.dump(prefix, fd, writer, args);
+ }
}
public static void dumpDebugLogsToConsole() {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index ab0b13598..03ab94bab 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -37,7 +37,6 @@ import java.util.ArrayList;
public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
private static final String TAG = "LauncherAppState";
- private static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
private static final boolean DEBUG = false;
@@ -188,7 +187,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
}
public static String getSharedPreferencesKey() {
- return SHARED_PREFERENCES_KEY;
+ return LauncherFiles.SHARED_PREFERENCES_KEY;
}
DeviceProfile initDynamicGrid(Context context, int minWidth, int minHeight,
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
new file mode 100644
index 000000000..aef2adc7f
--- /dev/null
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -0,0 +1,89 @@
+package com.android.launcher3;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * LauncherCallbacks is an interface used to extend the Launcher activity. It includes many hooks
+ * in order to add additional functionality. Some of these are very general, and give extending
+ * classes the ability to react to Activity life-cycle or specific user interactions. Others
+ * are more specific and relate to replacing parts of the application, for example, the search
+ * interface or the wallpaper picker.
+ */
+public interface LauncherCallbacks {
+
+ /*
+ * Activity life-cycle methods. These methods are triggered after
+ * the code in the corresponding Launcher method is executed.
+ */
+ public void preOnCreate();
+ public void onCreate(Bundle savedInstanceState);
+ public void preOnResume();
+ public void onResume();
+ public void onStart();
+ public void onStop();
+ public void onPause();
+ public void onDestroy();
+ public void onSaveInstanceState(Bundle outState);
+ public void onPostCreate(Bundle savedInstanceState);
+ public void onNewIntent(Intent intent);
+ public void onActivityResult(int requestCode, int resultCode, Intent data);
+ public void onWindowFocusChanged(boolean hasFocus);
+ public boolean onPrepareOptionsMenu(Menu menu);
+ public void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args);
+ public void onHomeIntent();
+ public boolean handleBackPressed();
+
+ /*
+ * Extension points for providing custom behavior on certain user interactions.
+ */
+ public void onLauncherProviderChange();
+ public void finishBindingItems(final boolean upgradePath);
+ public void onClickAllAppsButton(View v);
+ public void bindAllApplications(ArrayList<AppInfo> apps);
+ public void onClickFolderIcon(View v);
+ public void onClickAppShortcut(View v);
+ public void onClickPagedViewIcon(View v);
+ public void onClickWallpaperPicker(View v);
+ public void onClickSettingsButton(View v);
+ public void onClickAddWidgetButton(View v);
+ public void onPageSwitch(View newPage, int newPageIndex);
+ public void onWorkspaceLockedChanged();
+ public void onDragStarted(View view);
+ public void onInteractionBegin();
+ public void onInteractionEnd();
+
+ /*
+ * Extension points for replacing the search experience
+ */
+ public boolean forceDisableVoiceButtonProxy();
+ public boolean providesSearch();
+ public boolean startSearch(String initialQuery, boolean selectInitialQuery,
+ Bundle appSearchData, Rect sourceBounds);
+ public void startVoice();
+ public boolean hasCustomContentToLeft();
+ public void populateCustomContentContainer();
+ public View getQsbBar();
+
+ /*
+ * Extensions points for adding / replacing some other aspects of the Launcher experience.
+ */
+ public Intent getFirstRunActivity();
+ public boolean hasFirstRunActivity();
+ public boolean hasDismissableIntroScreen();
+ public View getIntroScreen();
+ public boolean shouldMoveToDefaultScreenOnHomeIntent();
+ public boolean hasSettings();
+ public ComponentName getWallpaperPickerComponent();
+ public boolean overrideWallpaperDimensions();
+ public boolean isLauncherPreinstalled();
+
+}
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index 89600c2df..fa053650f 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -12,16 +12,29 @@ import java.util.List;
*/
public class LauncherFiles {
- public static final String SHARED_PREFS = "com.android.launcher3.prefs.xml";
+ private static final String XML = ".xml";
+
+ public static final String DEFAULT_WALLPAPER_THUMBNAIL = "default_thumb2.jpg";
+ public static final String DEFAULT_WALLPAPER_THUMBNAIL_OLD = "default_thumb.jpg";
public static final String LAUNCHER_DB = "launcher.db";
- public static final String LAUNCHER_PREFS = "launcher.preferences";
+ public static final String LAUNCHER_PREFERENCES = "launcher.preferences";
+ public static final String LAUNCHES_LOG = "launches.log";
+ public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
+ public static final String STATS_LOG = "stats.log";
+ public static final String WALLPAPER_CROP_PREFERENCES_KEY =
+ WallpaperCropActivity.class.getName();
public static final String WALLPAPER_IMAGES_DB = "saved_wallpaper_images.db";
public static final String WIDGET_PREVIEWS_DB = "widgetpreviews.db";
public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
- SHARED_PREFS,
+ DEFAULT_WALLPAPER_THUMBNAIL,
+ DEFAULT_WALLPAPER_THUMBNAIL_OLD,
LAUNCHER_DB,
- LAUNCHER_PREFS,
+ LAUNCHER_PREFERENCES,
+ LAUNCHES_LOG,
+ SHARED_PREFERENCES_KEY + XML,
+ STATS_LOG,
+ WALLPAPER_CROP_PREFERENCES_KEY + XML,
WALLPAPER_IMAGES_DB,
WIDGET_PREVIEWS_DB));
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 30a033776..17670d25d 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2241,7 +2241,7 @@ public class LauncherModel extends BroadcastReceiver
// App restore has started. Update the flag
appWidgetInfo.restoreStatus |=
LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- } else if (REMOVE_UNRESTORED_ICONS) {
+ } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {
Launcher.addDumpLog(TAG,
"Unrestored widget removed: " + component, true);
itemsToRemove.add(id);
@@ -3534,17 +3534,6 @@ public class LauncherModel extends BroadcastReceiver
}
}
- ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,
- int cellX, int cellY, boolean notify) {
- final ShortcutInfo info = infoFromShortcutIntent(context, data, null);
- if (info == null) {
- return null;
- }
- addItemToDatabase(context, info, container, screen, cellX, cellY, notify);
-
- return info;
- }
-
/**
* Attempts to find an AppWidgetProviderInfo that matches the given component.
*/
@@ -3560,7 +3549,7 @@ public class LauncherModel extends BroadcastReceiver
return null;
}
- ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {
+ ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
@@ -3593,12 +3582,8 @@ public class LauncherModel extends BroadcastReceiver
// users wouldn't get here without intent forwarding anyway.
info.user = UserHandleCompat.myUserHandle();
if (icon == null) {
- if (fallbackIcon != null) {
- icon = fallbackIcon;
- } else {
- icon = mIconCache.getDefaultIcon(info.user);
- info.usingFallbackIcon = true;
- }
+ icon = mIconCache.getDefaultIcon(info.user);
+ info.usingFallbackIcon = true;
}
info.setIcon(icon);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 44ccb6cb3..9150dc0c1 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -31,12 +31,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
@@ -46,7 +41,6 @@ import android.database.sqlite.SQLiteStatement;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
-import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -58,11 +52,7 @@ import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.File;
-import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
@@ -89,9 +79,6 @@ public class LauncherProvider extends ContentProvider {
static final String EMPTY_DATABASE_CREATED =
"EMPTY_DATABASE_CREATED";
- private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
- "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
-
private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
private LauncherProviderChangeListener mListener;
@@ -160,12 +147,6 @@ public class LauncherProvider extends ContentProvider {
return db.insert(table, nullColumnHack, values);
}
- private static void deleteId(SQLiteDatabase db, long id) {
- Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
- SqlArguments args = new SqlArguments(uri, null, null);
- db.delete(args.table, args.where, args.args);
- }
-
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
SqlArguments args = new SqlArguments(uri);
@@ -325,7 +306,7 @@ public class LauncherProvider extends ContentProvider {
if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
Log.d(TAG, "loading default workspace");
- WorkspaceLoader loader = AutoInstallsLayout.get(getContext(),
+ AutoInstallsLayout loader = AutoInstallsLayout.get(getContext(),
mOpenHelper.mAppWidgetHost, mOpenHelper);
if (loader == null) {
@@ -335,14 +316,15 @@ public class LauncherProvider extends ContentProvider {
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
"xml", partner.getPackageName());
if (workspaceResId != 0) {
- loader = new SimpleWorkspaceLoader(mOpenHelper, partnerRes, workspaceResId);
+ loader = new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
+ mOpenHelper, partnerRes, workspaceResId);
}
}
}
if (loader == null) {
- loader = new SimpleWorkspaceLoader(mOpenHelper, getContext().getResources(),
- getDefaultWorkspaceResourceId());
+ loader = new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
+ mOpenHelper, getContext().getResources(), getDefaultWorkspaceResourceId());
}
// Populate favorites table with initial favorites
@@ -360,11 +342,7 @@ public class LauncherProvider extends ContentProvider {
private static int getDefaultWorkspaceResourceId() {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- if (LauncherAppState.isDisableAllApps()) {
- return grid.defaultNoAllAppsLayoutId;
- } else {
- return grid.defaultLayoutId;
- }
+ return grid.defaultLayoutId;
}
private static interface ContentValuesCallback {
@@ -390,38 +368,7 @@ public class LauncherProvider extends ContentProvider {
}
private static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
- private static final String TAG_RESOLVE = "resolve";
- private static final String TAG_FAVORITES = "favorites";
- private static final String TAG_FAVORITE = "favorite";
- private static final String TAG_APPWIDGET = "appwidget";
- private static final String TAG_SHORTCUT = "shortcut";
- private static final String TAG_FOLDER = "folder";
- private static final String TAG_PARTNER_FOLDER = "partner-folder";
- private static final String TAG_EXTRA = "extra";
- private static final String TAG_INCLUDE = "include";
-
- // Style attrs -- "Favorite"
- private static final String ATTR_CLASS_NAME = "className";
- private static final String ATTR_PACKAGE_NAME = "packageName";
- private static final String ATTR_CONTAINER = "container";
- private static final String ATTR_SCREEN = "screen";
- private static final String ATTR_X = "x";
- private static final String ATTR_Y = "y";
- private static final String ATTR_SPAN_X = "spanX";
- private static final String ATTR_SPAN_Y = "spanY";
- private static final String ATTR_ICON = "icon";
- private static final String ATTR_TITLE = "title";
- private static final String ATTR_URI = "uri";
-
- // Style attrs -- "Include"
- private static final String ATTR_WORKSPACE = "workspace";
-
- // Style attrs -- "Extra"
- private static final String ATTR_KEY = "key";
- private static final String ATTR_VALUE = "value";
-
private final Context mContext;
- private final PackageManager mPackageManager;
private final AppWidgetHost mAppWidgetHost;
private long mMaxItemId = -1;
private long mMaxScreenId = -1;
@@ -431,7 +378,6 @@ public class LauncherProvider extends ContentProvider {
DatabaseHelper(Context context) {
super(context, LauncherFiles.LAUNCHER_DB, null, DATABASE_VERSION);
mContext = context;
- mPackageManager = context.getPackageManager();
mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
// In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
@@ -787,8 +733,8 @@ public class LauncherProvider extends ContentProvider {
}
// Add default hotseat icons
- loadFavorites(db, new SimpleWorkspaceLoader(this, mContext.getResources(),
- R.xml.update_workspace));
+ loadFavorites(db, new DefaultLayoutParser(mContext, mAppWidgetHost, this,
+ mContext.getResources(), R.xml.update_workspace));
version = 9;
}
@@ -1288,14 +1234,16 @@ public class LauncherProvider extends ContentProvider {
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
- if (appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
- return true;
+ if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
+ return false;
}
} catch (RuntimeException e) {
Log.e(TAG, "Failed to initialize external widget", e);
+ return false;
}
+ } else {
+ return false;
}
- return false;
}
// Add screen id if not present
@@ -1353,31 +1301,7 @@ public class LauncherProvider extends ContentProvider {
return rank;
}
- private static final void beginDocument(XmlPullParser parser, String firstElementName)
- throws XmlPullParserException, IOException {
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new XmlPullParserException("No start tag found");
- }
-
- if (!parser.getName().equals(firstElementName)) {
- throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
- ", expected " + firstElementName);
- }
- }
-
- private static Intent buildMainIntent() {
- Intent intent = new Intent(Intent.ACTION_MAIN, null);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- return intent;
- }
-
- private int loadFavorites(SQLiteDatabase db, WorkspaceLoader loader) {
+ private int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
ArrayList<Long> screenIds = new ArrayList<Long>();
// TODO: Use multiple loaders with fall-back and transaction.
int count = loader.loadLayout(db, screenIds);
@@ -1404,379 +1328,6 @@ public class LauncherProvider extends ContentProvider {
return count;
}
- /**
- * Loads the default set of favorite packages from an xml file.
- *
- * @param db The database to write the values into
- * @param filterContainerId The specific container id of items to load
- * @param the set of screenIds which are used by the favorites
- */
- private int loadFavoritesRecursive(SQLiteDatabase db, Resources res, int workspaceResourceId,
- ArrayList<Long> screenIds) {
-
- ContentValues values = new ContentValues();
- if (LOGD) Log.v(TAG, String.format("Loading favorites from resid=0x%08x", workspaceResourceId));
-
- int count = 0;
- try {
- XmlResourceParser parser = res.getXml(workspaceResourceId);
- beginDocument(parser, TAG_FAVORITES);
-
- final int depth = parser.getDepth();
-
- int type;
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
-
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- boolean added = false;
- final String name = parser.getName();
-
- if (TAG_INCLUDE.equals(name)) {
-
- final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
-
- if (LOGD) Log.v(TAG, String.format(("%" + (2*(depth+1)) + "s<include workspace=%08x>"),
- "", resId));
-
- if (resId != 0 && resId != workspaceResourceId) {
- // recursively load some more favorites, why not?
- count += loadFavoritesRecursive(db, res, resId, screenIds);
- added = false;
- } else {
- Log.w(TAG, String.format("Skipping <include workspace=0x%08x>", resId));
- }
-
- if (LOGD) Log.v(TAG, String.format(("%" + (2*(depth+1)) + "s</include>"), ""));
- continue;
- }
-
- // Assuming it's a <favorite> at this point
- long container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- String strContainer = getAttributeValue(parser, ATTR_CONTAINER);
- if (strContainer != null) {
- container = Long.valueOf(strContainer);
- }
-
- String screen = getAttributeValue(parser, ATTR_SCREEN);
- String x = getAttributeValue(parser, ATTR_X);
- String y = getAttributeValue(parser, ATTR_Y);
-
- values.clear();
- values.put(LauncherSettings.Favorites.CONTAINER, container);
- values.put(LauncherSettings.Favorites.SCREEN, screen);
- values.put(LauncherSettings.Favorites.CELLX, x);
- values.put(LauncherSettings.Favorites.CELLY, y);
-
- if (LOGD) {
- final String title = getAttributeValue(parser, ATTR_TITLE);
- final String pkg = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- final String something = title != null ? title : pkg;
- Log.v(TAG, String.format(
- ("%" + (2*(depth+1)) + "s<%s%s c=%d s=%s x=%s y=%s>"),
- "", name,
- (something == null ? "" : (" \"" + something + "\"")),
- container, screen, x, y));
- }
-
- if (TAG_FAVORITE.equals(name)) {
- long id = addAppShortcut(db, values, parser);
- added = id >= 0;
- } else if (TAG_APPWIDGET.equals(name)) {
- added = addAppWidget(parser, type, db, values);
- } else if (TAG_SHORTCUT.equals(name)) {
- long id = addUriShortcut(db, values, res, parser);
- added = id >= 0;
- } else if (TAG_RESOLVE.equals(name)) {
- // This looks through the contained favorites (or meta-favorites) and
- // attempts to add them as shortcuts in the fallback group's location
- // until one is added successfully.
- added = false;
- final int groupDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > groupDepth) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final String fallback_item_name = parser.getName();
- if (!added) {
- if (TAG_FAVORITE.equals(fallback_item_name)) {
- final long id = addAppShortcut(db, values, parser);
- added = id >= 0;
- } else {
- Log.e(TAG, "Fallback groups can contain only favorites, found "
- + fallback_item_name);
- }
- }
- }
- } else if (TAG_FOLDER.equals(name)) {
- // Folder contents are nested in this XML file
- added = loadFolder(db, values, res, parser);
-
- } else if (TAG_PARTNER_FOLDER.equals(name)) {
- // Folder contents come from an external XML resource
- final Partner partner = Partner.get(mPackageManager);
- if (partner != null) {
- final Resources partnerRes = partner.getResources();
- final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER,
- "xml", partner.getPackageName());
- if (resId != 0) {
- final XmlResourceParser partnerParser = partnerRes.getXml(resId);
- beginDocument(partnerParser, TAG_FOLDER);
- added = loadFolder(db, values, partnerRes, partnerParser);
- }
- }
- }
- if (added) {
- long screenId = Long.parseLong(screen);
- // Keep track of the set of screens which need to be added to the db.
- if (!screenIds.contains(screenId) &&
- container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- screenIds.add(screenId);
- }
- count++;
- }
- }
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- } catch (IOException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- } catch (RuntimeException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- }
- return count;
- }
-
- /**
- * Parse folder starting at current {@link XmlPullParser} location.
- */
- private boolean loadFolder(SQLiteDatabase db, ContentValues values, Resources res,
- XmlResourceParser parser) throws IOException, XmlPullParserException {
- final String title;
- final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
- if (titleResId != 0) {
- title = res.getString(titleResId);
- } else {
- title = mContext.getResources().getString(R.string.folder_name);
- }
-
- values.put(LauncherSettings.Favorites.TITLE, title);
- long folderId = addFolder(db, values);
- boolean added = folderId >= 0;
-
- ArrayList<Long> folderItems = new ArrayList<Long>();
-
- int type;
- int folderDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > folderDepth) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final String tag = parser.getName();
-
- final ContentValues childValues = new ContentValues();
- childValues.put(LauncherSettings.Favorites.CONTAINER, folderId);
-
- if (LOGD) {
- final String pkg = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- final String uri = getAttributeValue(parser, ATTR_URI);
- Log.v(TAG, String.format(("%" + (2*(folderDepth+1)) + "s<%s \"%s\">"), "",
- tag, uri != null ? uri : pkg));
- }
-
- if (TAG_FAVORITE.equals(tag) && folderId >= 0) {
- final long id = addAppShortcut(db, childValues, parser);
- if (id >= 0) {
- folderItems.add(id);
- }
- } else if (TAG_SHORTCUT.equals(tag) && folderId >= 0) {
- final long id = addUriShortcut(db, childValues, res, parser);
- if (id >= 0) {
- folderItems.add(id);
- }
- } else {
- throw new RuntimeException("Folders can contain only shortcuts");
- }
- }
-
- // We can only have folders with >= 2 items, so we need to remove the
- // folder and clean up if less than 2 items were included, or some
- // failed to add, and less than 2 were actually added
- if (folderItems.size() < 2 && folderId >= 0) {
- // Delete the folder
- deleteId(db, folderId);
-
- // If we have a single item, promote it to where the folder
- // would have been.
- if (folderItems.size() == 1) {
- final ContentValues childValues = new ContentValues();
- copyInteger(values, childValues, LauncherSettings.Favorites.CONTAINER);
- copyInteger(values, childValues, LauncherSettings.Favorites.SCREEN);
- copyInteger(values, childValues, LauncherSettings.Favorites.CELLX);
- copyInteger(values, childValues, LauncherSettings.Favorites.CELLY);
-
- final long id = folderItems.get(0);
- db.update(TABLE_FAVORITES, childValues,
- LauncherSettings.Favorites._ID + "=" + id, null);
- } else {
- added = false;
- }
- }
- return added;
- }
-
- // A meta shortcut attempts to resolve an intent specified as a URI in the XML, if a
- // logical choice for what shortcut should be used for that intent exists, then it is
- // added. Otherwise add nothing.
- private long addAppShortcutByUri(SQLiteDatabase db, ContentValues values,
- String intentUri) {
- Intent metaIntent;
- try {
- metaIntent = Intent.parseUri(intentUri, 0);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Unable to add meta-favorite: " + intentUri, e);
- return -1;
- }
-
- ResolveInfo resolved = mPackageManager.resolveActivity(metaIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- final List<ResolveInfo> appList = mPackageManager.queryIntentActivities(
- metaIntent, PackageManager.MATCH_DEFAULT_ONLY);
-
- // Verify that the result is an app and not just the resolver dialog asking which
- // app to use.
- if (wouldLaunchResolverActivity(resolved, appList)) {
- // If only one of the results is a system app then choose that as the default.
- final ResolveInfo systemApp = getSingleSystemActivity(appList);
- if (systemApp == null) {
- // There is no logical choice for this meta-favorite, so rather than making
- // a bad choice just add nothing.
- Log.w(TAG, "No preference or single system activity found for "
- + metaIntent.toString());
- return -1;
- }
- resolved = systemApp;
- }
- final ActivityInfo info = resolved.activityInfo;
- final Intent intent = mPackageManager.getLaunchIntentForPackage(info.packageName);
- if (intent == null) {
- return -1;
- }
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- return addAppShortcut(db, values, info.loadLabel(mPackageManager).toString(), intent);
- }
-
- private ResolveInfo getSingleSystemActivity(List<ResolveInfo> appList) {
- ResolveInfo systemResolve = null;
- final int N = appList.size();
- for (int i = 0; i < N; ++i) {
- try {
- ApplicationInfo info = mPackageManager.getApplicationInfo(
- appList.get(i).activityInfo.packageName, 0);
- if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (systemResolve != null) {
- return null;
- } else {
- systemResolve = appList.get(i);
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to get info about resolve results", e);
- return null;
- }
- }
- return systemResolve;
- }
-
- private boolean wouldLaunchResolverActivity(ResolveInfo resolved,
- List<ResolveInfo> appList) {
- // If the list contains the above resolved activity, then it can't be
- // ResolverActivity itself.
- for (int i = 0; i < appList.size(); ++i) {
- ResolveInfo tmp = appList.get(i);
- if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
- && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
- return false;
- }
- }
- return true;
- }
-
- private long addAppShortcut(SQLiteDatabase db, ContentValues values,
- XmlResourceParser parser) {
- final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
- final String uri = getAttributeValue(parser, ATTR_URI);
-
- if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
- ActivityInfo info;
- try {
- ComponentName cn;
- try {
- cn = new ComponentName(packageName, className);
- info = mPackageManager.getActivityInfo(cn, 0);
- } catch (PackageManager.NameNotFoundException nnfe) {
- String[] packages = mPackageManager.currentToCanonicalPackageNames(
- new String[] { packageName });
- cn = new ComponentName(packages[0], className);
- info = mPackageManager.getActivityInfo(cn, 0);
- }
- final Intent intent = buildMainIntent();
- intent.setComponent(cn);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- return addAppShortcut(db, values, info.loadLabel(mPackageManager).toString(),
- intent);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to add favorite: " + packageName +
- "/" + className, e);
- }
- return -1;
- } else if (!TextUtils.isEmpty(uri)) {
- // If no component specified try to find a shortcut to add from the URI.
- return addAppShortcutByUri(db, values, uri);
- } else {
- Log.e(TAG, "Skipping invalid <favorite> with no component or uri");
- return -1;
- }
- }
-
- private long addAppShortcut(SQLiteDatabase db, ContentValues values, String title,
- Intent intent) {
- long id = generateNewItemId();
- values.put(Favorites.INTENT, intent.toUri(0));
- values.put(Favorites.TITLE, title);
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- values.put(Favorites._ID, id);
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
- return -1;
- } else {
- return id;
- }
- }
-
- private long addFolder(SQLiteDatabase db, ContentValues values) {
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- long id = generateNewItemId();
- values.put(Favorites._ID, id);
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) <= 0) {
- return -1;
- } else {
- return id;
- }
- }
-
private ComponentName getSearchWidgetProvider() {
SearchManager searchManager =
(SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
@@ -1803,140 +1354,6 @@ public class LauncherProvider extends ContentProvider {
return null;
}
- private boolean addAppWidget(XmlResourceParser parser, int type,
- SQLiteDatabase db, ContentValues values)
- throws XmlPullParserException, IOException {
-
- String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
- String className = getAttributeValue(parser, ATTR_CLASS_NAME);
-
- if (packageName == null || className == null) {
- return false;
- }
-
- boolean hasPackage = true;
- ComponentName cn = new ComponentName(packageName, className);
- try {
- mPackageManager.getReceiverInfo(cn, 0);
- } catch (Exception e) {
- String[] packages = mPackageManager.currentToCanonicalPackageNames(
- new String[] { packageName });
- cn = new ComponentName(packages[0], className);
- try {
- mPackageManager.getReceiverInfo(cn, 0);
- } catch (Exception e1) {
- System.out.println("Can't find widget provider: " + className);
- hasPackage = false;
- }
- }
-
- if (hasPackage) {
- String spanX = getAttributeValue(parser, ATTR_SPAN_X);
- String spanY = getAttributeValue(parser, ATTR_SPAN_Y);
-
- values.put(Favorites.SPANX, spanX);
- values.put(Favorites.SPANY, spanY);
-
- // Read the extras
- Bundle extras = new Bundle();
- int widgetDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > widgetDepth) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (TAG_EXTRA.equals(parser.getName())) {
- String key = getAttributeValue(parser, ATTR_KEY);
- String value = getAttributeValue(parser, ATTR_VALUE);
- if (key != null && value != null) {
- extras.putString(key, value);
- } else {
- throw new RuntimeException("Widget extras must have a key and value");
- }
- } else {
- throw new RuntimeException("Widgets can contain only extras");
- }
- }
-
- return addAppWidget(db, values, cn, extras);
- }
-
- return false;
- }
-
- private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
- Bundle extras) {
- boolean allocatedAppWidgets = false;
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-
- try {
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
- values.put(Favorites.APPWIDGET_ID, appWidgetId);
- values.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
- values.put(Favorites._ID, generateNewItemId());
- dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
-
- allocatedAppWidgets = true;
-
- // TODO: need to check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn);
-
- // Send a broadcast to configure the widget
- if (extras != null && !extras.isEmpty()) {
- Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
- intent.setComponent(cn);
- intent.putExtras(extras);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- mContext.sendBroadcast(intent);
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem allocating appWidgetId", ex);
- }
-
- return allocatedAppWidgets;
- }
-
- private long addUriShortcut(SQLiteDatabase db, ContentValues values, Resources res,
- XmlResourceParser parser) {
- final int iconResId = getAttributeResourceValue(parser, ATTR_ICON, 0);
- final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
-
- Intent intent;
- String uri = null;
- try {
- uri = getAttributeValue(parser, ATTR_URI);
- intent = Intent.parseUri(uri, 0);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Shortcut has malformed uri: " + uri);
- return -1; // Oh well
- }
-
- if (iconResId == 0 || titleResId == 0) {
- Log.w(TAG, "Shortcut is missing title or icon resource ID");
- return -1;
- }
-
- long id = generateNewItemId();
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- values.put(Favorites.INTENT, intent.toUri(0));
- values.put(Favorites.TITLE, res.getString(titleResId));
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
- values.put(Favorites.ICON_PACKAGE, res.getResourcePackageName(iconResId));
- values.put(Favorites.ICON_RESOURCE, res.getResourceName(iconResId));
- values.put(Favorites._ID, id);
-
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
- return -1;
- }
- return id;
- }
-
private void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
final ContentResolver resolver = mContext.getContentResolver();
Cursor c = null;
@@ -2236,38 +1653,6 @@ public class LauncherProvider extends ContentProvider {
return selectWhere.toString();
}
- /**
- * Return attribute value, attempting launcher-specific namespace first
- * before falling back to anonymous attribute.
- */
- private static String getAttributeValue(XmlResourceParser parser, String attribute) {
- String value = parser.getAttributeValue(
- "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute);
- if (value == null) {
- value = parser.getAttributeValue(null, attribute);
- }
- return value;
- }
-
- /**
- * Return attribute resource value, attempting launcher-specific namespace
- * first before falling back to anonymous attribute.
- */
- private static int getAttributeResourceValue(XmlResourceParser parser, String attribute,
- int defaultValue) {
- int value = parser.getAttributeResourceValue(
- "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute,
- defaultValue);
- if (value == defaultValue) {
- value = parser.getAttributeResourceValue(null, attribute, defaultValue);
- }
- return value;
- }
-
- private static void copyInteger(ContentValues from, ContentValues to, String key) {
- to.put(key, from.getAsInteger(key));
- }
-
static class SqlArguments {
public final String table;
public final String where;
@@ -2299,29 +1684,4 @@ public class LauncherProvider extends ContentProvider {
}
}
}
-
- static interface WorkspaceLoader {
- /**
- * @param screenIds A mutable list of screen its
- * @return the number of workspace items added.
- */
- int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds);
- }
-
- private static class SimpleWorkspaceLoader implements WorkspaceLoader {
- private final Resources mRes;
- private final int mWorkspaceId;
- private final DatabaseHelper mHelper;
-
- SimpleWorkspaceLoader(DatabaseHelper helper, Resources res, int workspaceId) {
- mHelper = helper;
- mRes = res;
- mWorkspaceId = workspaceId;
- }
-
- @Override
- public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) {
- return mHelper.loadFavoritesRecursive(db, mRes, mWorkspaceId, screenIds);
- }
- }
}
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index d23a33033..179c60a98 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -41,9 +41,9 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
private final LauncherAppWidgetInfo mInfo;
private final int mStartState;
private final Intent mIconLookupIntent;
+ private final boolean mDisabledForSafeMode;
private Bitmap mIcon;
- private PreloadIconDrawable mDrawable;
private Drawable mCenterDrawable;
private Drawable mTopCornerDrawable;
@@ -53,11 +53,13 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
private final TextPaint mPaint;
private Layout mSetupTextLayout;
- public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info) {
+ public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
+ boolean disabledForSafeMode) {
super(context);
mInfo = info;
mStartState = info.restoreStatus;
mIconLookupIntent = new Intent().setComponent(info.providerName);
+ mDisabledForSafeMode = disabledForSafeMode;
mPaint = new TextPaint();
mPaint.setColor(0xFFFFFFFF);
@@ -106,14 +108,21 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
return;
}
mIcon = icon;
- if (mDrawable != null) {
- mDrawable.setCallback(null);
- mDrawable = null;
+ if (mCenterDrawable != null) {
+ mCenterDrawable.setCallback(null);
+ mCenterDrawable = null;
}
if (mIcon != null) {
- // The view displays two modes, one with a setup icon and another with a preload icon
- // in the center.
- if (isReadyForClickSetup()) {
+ // The view displays three modes,
+ // 1) App icon in the center
+ // 2) Preload icon in the center
+ // 3) Setup icon in the center and app icon in the top right corner.
+ if (mDisabledForSafeMode) {
+ FastBitmapDrawable disabledIcon = Utilities.createIconDrawable(mIcon);
+ disabledIcon.setGhostModeEnabled(true);
+ mCenterDrawable = disabledIcon;
+ mTopCornerDrawable = null;
+ } else if (isReadyForClickSetup()) {
mCenterDrawable = getResources().getDrawable(R.drawable.ic_setting);
mTopCornerDrawable = new FastBitmapDrawable(mIcon);
} else {
@@ -123,8 +132,9 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
}
FastBitmapDrawable drawable = Utilities.createIconDrawable(mIcon);
- mDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
- mDrawable.setCallback(this);
+ mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
+ mCenterDrawable.setCallback(this);
+ mTopCornerDrawable = null;
applyState();
}
mDrawableSizeChanged = true;
@@ -133,12 +143,12 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
@Override
protected boolean verifyDrawable(Drawable who) {
- return (who == mDrawable) || super.verifyDrawable(who);
+ return (who == mCenterDrawable) || super.verifyDrawable(who);
}
public void applyState() {
- if (mDrawable != null) {
- mDrawable.setLevel(Math.max(mInfo.installProgress, 0));
+ if (mCenterDrawable != null) {
+ mCenterDrawable.setLevel(Math.max(mInfo.installProgress, 0));
}
}
@@ -158,23 +168,30 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen
@Override
protected void onDraw(Canvas canvas) {
- if (mDrawable != null) {
+ if (mCenterDrawable == null) {
+ // Nothing to draw
+ return;
+ }
+
+ if (mTopCornerDrawable == null) {
if (mDrawableSizeChanged) {
+ int outset = (mCenterDrawable instanceof PreloadIconDrawable) ?
+ ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0;
int maxSize = LauncherAppState.getInstance().getDynamicGrid()
- .getDeviceProfile().iconSizePx + 2 * mDrawable.getOutset();
+ .getDeviceProfile().iconSizePx + 2 * outset;
int size = Math.min(maxSize, Math.min(
getWidth() - getPaddingLeft() - getPaddingRight(),
getHeight() - getPaddingTop() - getPaddingBottom()));
mRect.set(0, 0, size, size);
- mRect.inset(mDrawable.getOutset(), mDrawable.getOutset());
+ mRect.inset(outset, outset);
mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2);
- mDrawable.setBounds(mRect);
+ mCenterDrawable.setBounds(mRect);
mDrawableSizeChanged = false;
}
-
- mDrawable.draw(canvas);
- } else if ((mCenterDrawable != null) && (mTopCornerDrawable != null)) {
+ mCenterDrawable.draw(canvas);
+ } else {
+ // Draw the top corner icon and "Setup" text is possible
if (mDrawableSizeChanged) {
DeviceProfile grid = getDeviceProfile();
int iconSize = grid.iconSizePx;
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index f3977e456..a87986562 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -38,12 +38,10 @@ public class Stats {
public static final String EXTRA_CELLX = "cellX";
public static final String EXTRA_CELLY = "cellY";
- private static final String LOG_FILE_NAME = "launches.log";
private static final int LOG_VERSION = 1;
private static final int LOG_TAG_VERSION = 0x1;
private static final int LOG_TAG_LAUNCH = 0x1000;
- private static final String STATS_FILE_NAME = "stats.log";
private static final int STATS_VERSION = 1;
private static final int INITIAL_STATS_SIZE = 100;
@@ -69,7 +67,8 @@ public class Stats {
if (LOCAL_LAUNCH_LOG) {
try {
- mLog = new DataOutputStream(mLauncher.openFileOutput(LOG_FILE_NAME, Context.MODE_APPEND));
+ mLog = new DataOutputStream(mLauncher.openFileOutput(
+ LauncherFiles.LAUNCHES_LOG, Context.MODE_APPEND));
mLog.writeInt(LOG_TAG_VERSION);
mLog.writeInt(LOG_VERSION);
} catch (FileNotFoundException e) {
@@ -160,7 +159,8 @@ public class Stats {
private void saveStats() {
DataOutputStream stats = null;
try {
- stats = new DataOutputStream(mLauncher.openFileOutput(STATS_FILE_NAME + ".tmp", Context.MODE_PRIVATE));
+ stats = new DataOutputStream(mLauncher.openFileOutput(
+ LauncherFiles.STATS_LOG + ".tmp", Context.MODE_PRIVATE));
stats.writeInt(STATS_VERSION);
final int N = mHistogram.size();
stats.writeInt(N);
@@ -170,8 +170,8 @@ public class Stats {
}
stats.close();
stats = null;
- mLauncher.getFileStreamPath(STATS_FILE_NAME + ".tmp")
- .renameTo(mLauncher.getFileStreamPath(STATS_FILE_NAME));
+ mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG + ".tmp")
+ .renameTo(mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG));
} catch (FileNotFoundException e) {
Log.e(TAG, "unable to create stats data: " + e);
} catch (IOException e) {
@@ -190,7 +190,7 @@ public class Stats {
mHistogram = new ArrayList<Integer>(INITIAL_STATS_SIZE);
DataInputStream stats = null;
try {
- stats = new DataInputStream(mLauncher.openFileInput(STATS_FILE_NAME));
+ stats = new DataInputStream(mLauncher.openFileInput(LauncherFiles.STATS_LOG));
final int version = stats.readInt();
if (version == STATS_VERSION) {
final int N = stats.readInt();
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 92d7c7d7f..9cedae0f9 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -638,7 +638,7 @@ public class WidgetPreviewLoader {
c.setBitmap(null);
}
// Render the icon
- Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info));
+ Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo));
int paddingTop = mContext.
getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 5f074c1b4..79d31cdce 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1267,7 +1267,6 @@ public class Workspace extends SmoothPagedView
mCustomContentShowing = false;
if (mCustomContentCallbacks != null) {
mCustomContentCallbacks.onHide();
- mLauncher.resetQSBScroll();
mLauncher.updateVoiceButtonProxyVisible(false);
}
}