OSDN Git Service

Refactoring layout parsing code
authorSunny Goyal <sunnygoyal@google.com>
Wed, 1 Oct 2014 22:33:41 +0000 (15:33 -0700)
committerSunny Goyal <sunnygoyal@google.com>
Fri, 17 Oct 2014 21:34:49 +0000 (14:34 -0700)
Change-Id: Iee5b2280cb1e841bcfe91fdcf523de6fa7f7f3b8

src/com/android/launcher3/AutoInstallsLayout.java
src/com/android/launcher3/DefaultLayoutParser.java [new file with mode: 0644]
src/com/android/launcher3/LauncherProvider.java

index 08ed89b..a5d2228 100644 (file)
@@ -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 (file)
index 0000000..e3ea40e
--- /dev/null
@@ -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);
+        }
+    }
+}
index 0272dfd..9150dc0 100644 (file)
@@ -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
@@ -386,40 +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";
-        private static final String TAG_FOLDER_ITEMS = "folderitems";
-
-        // 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";
-        private static final String ATTR_FOLDER_ITEMS = "folderItems";
-
-        // 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;
@@ -429,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
@@ -785,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;
             }
 
@@ -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,392 +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 items starting at {@link XmlPullParser} location. Allow recursive
-         * includes of items.
-         */
-        private void addToFolder(SQLiteDatabase db, Resources res, XmlResourceParser parser,
-                ArrayList<Long> folderItems, long folderId) throws IOException, XmlPullParserException {
-            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 if (TAG_INCLUDE.equals(tag) && folderId >= 0) {
-                    final int resId = getAttributeResourceValue(parser, ATTR_FOLDER_ITEMS, 0);
-                    XmlResourceParser itemsParser = res.getXml(resId);
-                    beginDocument(itemsParser, TAG_FOLDER_ITEMS);
-                    addToFolder(db, res, itemsParser, folderItems, folderId);
-                } else {
-                    throw new RuntimeException("Folders can contain only shortcuts");
-                }
-            }
-        }
-
-        /**
-         * 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>();
-            addToFolder(db, res, parser, folderItems, folderId);
-
-            // 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);
@@ -1816,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;
@@ -2249,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;
@@ -2312,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);
-        }
-    }
 }