From 3a5a9d18daacb878a3eb379fce540ee6c67063e6 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 1 Oct 2014 15:33:41 -0700 Subject: Refactoring layout parsing code Change-Id: Iee5b2280cb1e841bcfe91fdcf523de6fa7f7f3b8 --- src/com/android/launcher3/AutoInstallsLayout.java | 245 ++++++++++++++-------- 1 file changed, 157 insertions(+), 88 deletions(-) (limited to 'src/com/android/launcher3/AutoInstallsLayout.java') 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 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 screenIds) + /** + * Parses the layout and returns the number of elements added on the homescreen. + */ + protected int parseLayout(int layoutId, ArrayList 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 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 tagParserMap, + ArrayList 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 parsers = new HashMap(); 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 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 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: + */ + 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 mFolderElements = getFolderElementsMap(); + protected class FolderParser implements TagParser { + private final HashMap mFolderElements; + + public FolderParser() { + this(getFolderElementsMap()); + } + + public FolderParser(HashMap 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, -- cgit v1.2.3