10fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal/*
20fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * Copyright (C) 2014 The Android Open Source Project
30fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal *
40fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * Licensed under the Apache License, Version 2.0 (the "License");
50fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * you may not use this file except in compliance with the License.
60fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * You may obtain a copy of the License at
70fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal *
80fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal *      http://www.apache.org/licenses/LICENSE-2.0
90fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal *
100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * Unless required by applicable law or agreed to in writing, software
110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * distributed under the License is distributed on an "AS IS" BASIS,
120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * See the License for the specific language governing permissions and
140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * limitations under the License.
150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal */
160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalpackage com.android.launcher3;
180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.appwidget.AppWidgetHost;
200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.appwidget.AppWidgetManager;
210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.ComponentName;
220fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.ContentValues;
230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.Context;
240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.Intent;
250fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.pm.ActivityInfo;
260fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.pm.PackageManager;
270fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.res.Resources;
280fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.content.res.XmlResourceParser;
290fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.database.sqlite.SQLiteDatabase;
300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.graphics.drawable.Drawable;
310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.net.Uri;
320fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.os.Bundle;
330fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.text.TextUtils;
340fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.util.Log;
350fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.util.Pair;
360fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.util.Patterns;
370fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport com.android.launcher3.LauncherProvider.SqlArguments;
390fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport com.android.launcher3.LauncherSettings.Favorites;
40091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
410fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport org.xmlpull.v1.XmlPullParser;
430fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport org.xmlpull.v1.XmlPullParserException;
440fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
450fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport java.io.IOException;
460fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport java.util.ArrayList;
470fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport java.util.HashMap;
48b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport java.util.Locale;
490fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
500fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal/**
513a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal * Layout parsing code for auto installs layout
520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal */
533a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyalpublic class AutoInstallsLayout {
540fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG = "AutoInstalls";
553a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    private static final boolean LOGD = false;
560fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
570fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    /** Marker action used to discover a package which defines launcher customization */
580fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    static final String ACTION_LAUNCHER_CUSTOMIZATION =
592233c8850d521defa82e358e3c5bae3ec75df426Sunny Goyal            "android.autoinstalls.config.action.PLAY_AUTO_INSTALL";
600fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
61b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal    /**
62b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal     * Layout resource which also includes grid size and hotseat count, e.g., default_layout_6x6_h5
63b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal     */
64b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal    private static final String FORMATTED_LAYOUT_RES_WITH_HOSTEAT = "default_layout_%dx%d_h%s";
65b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal    private static final String FORMATTED_LAYOUT_RES = "default_layout_%dx%d";
660fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String LAYOUT_RES = "default_layout";
670fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
680fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost,
690fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            LayoutParserCallback callback) {
700fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        Pair<String, Resources> customizationApkInfo = Utilities.findSystemApk(
710fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager());
720fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (customizationApkInfo == null) {
730fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return null;
740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
75b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        return get(context, customizationApkInfo.first, customizationApkInfo.second,
76b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal                appWidgetHost, callback);
77b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal    }
78b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal
79b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal    static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
80b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
812e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        InvariantDeviceProfile grid = LauncherAppState.getInstance().getInvariantDeviceProfile();
82b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal
83b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        // Try with grid size and hotseat count
84b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
85b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal                (int) grid.numColumns, (int) grid.numRows, (int) grid.numHotseatIcons);
86b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
87b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal
88b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        // Try with only grid size
89b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        if (layoutId == 0) {
90b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            Log.d(TAG, "Formatted layout: " + layoutName
91b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal                    + " not found. Trying layout without hosteat");
92b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
93b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal                    (int) grid.numColumns, (int) grid.numRows);
94b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
95b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        }
96b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal
97b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        // Try the default layout
98b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        if (layoutId == 0) {
99b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
100b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal            layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
101b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        }
1020fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1030fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (layoutId == 0) {
1040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            Log.e(TAG, "Layout definition not found in package: " + pkg);
1050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return null;
1060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
107b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal        return new AutoInstallsLayout(context, appWidgetHost, callback, targetRes, layoutId,
1083a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                TAG_WORKSPACE);
1090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
1100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    // Object Tags
112b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal    private static final String TAG_INCLUDE = "include";
1130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_WORKSPACE = "workspace";
1140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_APP_ICON = "appicon";
1150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_AUTO_INSTALL = "autoinstall";
1160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_FOLDER = "folder";
1170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_APPWIDGET = "appwidget";
1180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_SHORTCUT = "shortcut";
1190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String TAG_EXTRA = "extra";
1200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_CONTAINER = "container";
1220fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_RANK = "rank";
1230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_PACKAGE_NAME = "packageName";
1250fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_CLASS_NAME = "className";
1260fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_TITLE = "title";
1270fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_SCREEN = "screen";
1280fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_X = "x";
1290fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_Y = "y";
1300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_SPAN_X = "spanX";
1310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_SPAN_Y = "spanY";
1320fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_ICON = "icon";
1330fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_URL = "url";
1340fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
135b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal    // Attrs for "Include"
136b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal    private static final String ATTR_WORKSPACE = "workspace";
137b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal
1380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    // Style attrs -- "Extra"
1390fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_KEY = "key";
1400fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ATTR_VALUE = "value";
1410fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String HOTSEAT_CONTAINER_NAME =
1430fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            Favorites.containerToString(Favorites.CONTAINER_HOTSEAT);
1440fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1450fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
1460fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
1470fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
148091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final Context mContext;
149091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final AppWidgetHost mAppWidgetHost;
150bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal    protected final LayoutParserCallback mCallback;
1510fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1523a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected final PackageManager mPackageManager;
1533a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected final Resources mSourceRes;
1543a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected final int mLayoutId;
1553a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
1563a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    private final int mHotseatAllAppsRank;
1570fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1583a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    private final long[] mTemp = new long[2];
159091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final ContentValues mValues;
160bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal    protected final String mRootTag;
1610fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1623a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected SQLiteDatabase mDb;
1630fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1640fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
1653a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            LayoutParserCallback callback, Resources res,
1663a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            int layoutId, String rootTag) {
167bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal        this(context, appWidgetHost, callback, res, layoutId, rootTag,
1682e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                LauncherAppState.getInstance().getInvariantDeviceProfile().hotseatAllAppsRank);
169bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal    }
170bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal
171bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal    public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
172bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal            LayoutParserCallback callback, Resources res,
173bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal            int layoutId, String rootTag, int hotseatAllAppsRank) {
1740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mContext = context;
1750fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mAppWidgetHost = appWidgetHost;
1760fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mCallback = callback;
1770fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1780fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mPackageManager = context.getPackageManager();
1790fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues = new ContentValues();
1803a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mRootTag = rootTag;
1810fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1823a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mSourceRes = res;
1830fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mLayoutId = layoutId;
184bb3b02f562bef4de063099c085d3199a77d06cfdSunny Goyal        mHotseatAllAppsRank = hotseatAllAppsRank;
1850fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
1860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
1873a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
1883a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Loads the layout in the db and returns the number of entries added on the desktop.
1893a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
1900fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) {
1910fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mDb = db;
1920fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        try {
1933a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return parseLayout(mLayoutId, screenIds);
1948fd74831de067fbadad180c54f70fb4a5375a933Sameer Padala        } catch (Exception e) {
1950fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            Log.w(TAG, "Got exception parsing layout.", e);
1960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return -1;
1970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
1980fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
1990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2003a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
2013a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Parses the layout and returns the number of elements added on the homescreen.
2023a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
2033a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected int parseLayout(int layoutId, ArrayList<Long> screenIds)
2040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            throws XmlPullParserException, IOException {
2053a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        XmlResourceParser parser = mSourceRes.getXml(layoutId);
2063a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        beginDocument(parser, mRootTag);
2070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        final int depth = parser.getDepth();
2080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        int type;
2090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        HashMap<String, TagParser> tagParserMap = getLayoutElementsMap();
2100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        int count = 0;
2110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        while (((type = parser.next()) != XmlPullParser.END_TAG ||
2130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
2140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (type != XmlPullParser.START_TAG) {
2150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                continue;
2160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
2173a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            count += parseAndAddNode(parser, tagParserMap, screenIds);
2183a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
2193a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        return count;
2203a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    }
2210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2223a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
2233a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Parses container and screenId attribute from the current tag, and puts it in the out.
2243a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * @param out array of size 2.
2253a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
2263a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected void parseContainerAndScreen(XmlResourceParser parser, long[] out) {
2273a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
2283a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            out[0] = Favorites.CONTAINER_HOTSEAT;
2293a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            // Hack: hotseat items are stored using screen ids
2303a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
2313a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            out[1] = (rank < mHotseatAllAppsRank) ? rank : (rank + 1);
2323a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        } else {
2333a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            out[0] = Favorites.CONTAINER_DESKTOP;
2343a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
2353a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
2363a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    }
2370fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2383a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
2393a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Parses the current node and returns the number of elements added.
2403a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
2413a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected int parseAndAddNode(
2423a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            XmlResourceParser parser,
2433a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            HashMap<String, TagParser> tagParserMap,
2443a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            ArrayList<Long> screenIds)
2453a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                    throws XmlPullParserException, IOException {
246b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal
247b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal        if (TAG_INCLUDE.equals(parser.getName())) {
248b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal            final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
249b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal            if (resId != 0) {
250b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal                // recursively load some more favorites, why not?
251b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal                return parseLayout(resId, screenIds);
252b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal            } else {
253b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal                return 0;
254b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal            }
255b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal        }
256b564efb0244adf0fb8429940f9f716938c62a7acSunny Goyal
2573a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mValues.clear();
2583a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        parseContainerAndScreen(parser, mTemp);
2593a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        final long container = mTemp[0];
2603a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        final long screenId = mTemp[1];
2613a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
2623a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mValues.put(Favorites.CONTAINER, container);
2633a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mValues.put(Favorites.SCREEN, screenId);
2643a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mValues.put(Favorites.CELLX, getAttributeValue(parser, ATTR_X));
2653a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        mValues.put(Favorites.CELLY, getAttributeValue(parser, ATTR_Y));
2663a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
2673a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        TagParser tagParser = tagParserMap.get(parser.getName());
2683a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        if (tagParser == null) {
2693a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName());
2703a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return 0;
2713a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
2723a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        long newElementId = tagParser.parseAndAdd(parser);
2733a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        if (newElementId >= 0) {
2743a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            // Keep track of the set of screens which need to be added to the db.
2753a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            if (!screenIds.contains(screenId) &&
2763a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                    container == Favorites.CONTAINER_DESKTOP) {
2773a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                screenIds.add(screenId);
2780fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
2793a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return 1;
2800fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
2813a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        return 0;
2820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
2830fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2840fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    protected long addShortcut(String title, Intent intent, int type) {
2850fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        long id = mCallback.generateNewItemId();
2860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites.INTENT, intent.toUri(0));
2870fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites.TITLE, title);
2880fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites.ITEM_TYPE, type);
2890fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites.SPANX, 1);
2900fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites.SPANY, 1);
2910fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        mValues.put(Favorites._ID, id);
2920fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (mCallback.insertAndCheck(mDb, mValues) < 0) {
2930fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return -1;
2940fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        } else {
2950fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return id;
2960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
2970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
2980fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
2990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    protected HashMap<String, TagParser> getFolderElementsMap() {
3000fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
3010fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_APP_ICON, new AppShortcutParser());
3020fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
3033a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
3040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        return parsers;
3050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
3060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    protected HashMap<String, TagParser> getLayoutElementsMap() {
3080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
3090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_APP_ICON, new AppShortcutParser());
3100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
3110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_FOLDER, new FolderParser());
3120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        parsers.put(TAG_APPWIDGET, new AppWidgetParser());
3133a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
3140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        return parsers;
3150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
3160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3173a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected interface TagParser {
3180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        /**
3190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal         * Parses the tag and adds to the db
3200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal         * @return the id of the row added or -1;
3210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal         */
3223a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        long parseAndAdd(XmlResourceParser parser)
3230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                throws XmlPullParserException, IOException;
3240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
3250fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3263a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
3273a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * App shortcuts: required attributes packageName and className
3283a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
3293a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected class AppShortcutParser implements TagParser {
3300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        @Override
3323a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public long parseAndAdd(XmlResourceParser parser) {
3330fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
3340fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
3350fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3360fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
3370fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                ActivityInfo info;
3380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                try {
3390fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    ComponentName cn;
3400fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    try {
3410fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        cn = new ComponentName(packageName, className);
3420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        info = mPackageManager.getActivityInfo(cn, 0);
3430fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    } catch (PackageManager.NameNotFoundException nnfe) {
3440fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        String[] packages = mPackageManager.currentToCanonicalPackageNames(
3450fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                                new String[] { packageName });
3460fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        cn = new ComponentName(packages[0], className);
3470fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        info = mPackageManager.getActivityInfo(cn, 0);
3480fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    }
3490fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    final Intent intent = new Intent(Intent.ACTION_MAIN, null)
3500fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        .addCategory(Intent.CATEGORY_LAUNCHER)
3510fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        .setComponent(cn)
3520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
3530fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
3540fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3550fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    return addShortcut(info.loadLabel(mPackageManager).toString(),
3560fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                            intent, Favorites.ITEM_TYPE_APPLICATION);
3570fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                } catch (PackageManager.NameNotFoundException e) {
358cf0c746ec080ee528d4994c382562fda1e647752Adam Cohen                    Log.e(TAG, "Unable to add favorite: " + packageName + "/" + className, e);
3590fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
3600fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
3610fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            } else {
3623a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                return invalidPackageOrClass(parser);
3630fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
3640fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
3653a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
3663a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        /**
3673a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal         * Helper method to allow extending the parser capabilities
3683a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal         */
3693a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        protected long invalidPackageOrClass(XmlResourceParser parser) {
370cf0c746ec080ee528d4994c382562fda1e647752Adam Cohen            Log.w(TAG, "Skipping invalid <favorite> with no component");
3713a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return -1;
3723a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
3730fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
3740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3753a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
3763a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * AutoInstall: required attributes packageName and className
3773a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
3783a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected class AutoInstallParser implements TagParser {
3790fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
3800fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        @Override
3813a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public long parseAndAdd(XmlResourceParser parser) {
3820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
3830fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
3840fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
3850fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component");
3860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
3870fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
3880fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
389349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal            mValues.put(Favorites.RESTORED, ShortcutInfo.FLAG_AUTOINTALL_ICON);
3900fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final Intent intent = new Intent(Intent.ACTION_MAIN, null)
3910fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                .addCategory(Intent.CATEGORY_LAUNCHER)
3920fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                .setComponent(new ComponentName(packageName, className))
3930fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
3940fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
3950fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return addShortcut(mContext.getString(R.string.package_state_unknown), intent,
3960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    Favorites.ITEM_TYPE_APPLICATION);
3970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
3980fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
3990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4003a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
4013a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Parses a web shortcut. Required attributes url, icon, title
4023a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
4033a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected class ShortcutParser implements TagParser {
4043a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
4053a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        private final Resources mIconRes;
4063a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
4073a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public ShortcutParser(Resources iconRes) {
4083a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            mIconRes = iconRes;
4093a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
4100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        @Override
4123a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public long parseAndAdd(XmlResourceParser parser) {
4130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
4140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
4150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (titleResId == 0 || iconId == 0) {
4170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.d(TAG, "Ignoring shortcut");
4180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
4190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
4200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4213a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            final Intent intent = parseIntent(parser);
4223a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            if (intent == null) {
4230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
4240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
4253a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
4263a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            Drawable icon = mIconRes.getDrawable(iconId);
4270fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (icon == null) {
4280fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.d(TAG, "Ignoring shortcut, can't load icon");
4290fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
4300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
4310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4320fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            ItemInfo.writeBitmap(mValues, Utilities.createIconBitmap(icon, mContext));
4333a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            mValues.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
4343a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
4353a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
4363a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
4373a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
4380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
4393a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return addShortcut(mSourceRes.getString(titleResId),
4403a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                    intent, Favorites.ITEM_TYPE_SHORTCUT);
4413a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
4423a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
4433a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        protected Intent parseIntent(XmlResourceParser parser) {
4443a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            final String url = getAttributeValue(parser, ATTR_URL);
4453a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) {
4463a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url);
4473a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                return null;
4483a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            }
4493a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            return new Intent(Intent.ACTION_VIEW, null).setData(Uri.parse(url));
4500fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
4510fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
4520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4533a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    /**
4543a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * AppWidget parser: Required attributes packageName, className, spanX and spanY.
4553a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     * Options child nodes: <extra key=... value=... />
4563a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal     */
4573a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected class AppWidgetParser implements TagParser {
4580fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4590fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        @Override
4603a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public long parseAndAdd(XmlResourceParser parser)
4610fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                throws XmlPullParserException, IOException {
4620fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
4630fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
4640fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
4650fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component");
4660fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
4670fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
4680fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4690fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            ComponentName cn = new ComponentName(packageName, className);
4700fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            try {
4710fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mPackageManager.getReceiverInfo(cn, 0);
4720fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            } catch (Exception e) {
4730fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                String[] packages = mPackageManager.currentToCanonicalPackageNames(
4740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        new String[] { packageName });
4750fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                cn = new ComponentName(packages[0], className);
4760fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                try {
4770fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    mPackageManager.getReceiverInfo(cn, 0);
4780fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                } catch (Exception e1) {
4790fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    if (LOGD) Log.d(TAG, "Can't find widget provider: " + className);
4800fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    return -1;
4810fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
4820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
4830fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4840fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X));
4850fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y));
4860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4870fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            // Read the extras
4880fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            Bundle extras = new Bundle();
4890fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            int widgetDepth = parser.getDepth();
4900fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            int type;
4910fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            while ((type = parser.next()) != XmlPullParser.END_TAG ||
4920fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    parser.getDepth() > widgetDepth) {
4930fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (type != XmlPullParser.START_TAG) {
4940fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    continue;
4950fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
4960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (TAG_EXTRA.equals(parser.getName())) {
4980fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    String key = getAttributeValue(parser, ATTR_KEY);
4990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    String value = getAttributeValue(parser, ATTR_VALUE);
5000fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    if (key != null && value != null) {
5010fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        extras.putString(key, value);
5020fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    } else {
5030fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        throw new RuntimeException("Widget extras must have a key and value");
5040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    }
5050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                } else {
5060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    throw new RuntimeException("Widgets can contain only extras");
5070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
5090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
5110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            long insertedId = -1;
5120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            try {
5130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
5140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) {
5160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn);
5170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    return -1;
5180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
5210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.put(Favorites.APPWIDGET_ID, appWidgetId);
5220fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
5230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.put(Favorites._ID, mCallback.generateNewItemId());
5240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                insertedId = mCallback.insertAndCheck(mDb, mValues);
5250fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (insertedId < 0) {
5260fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
5270fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    return insertedId;
5280fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5290fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                // Send a broadcast to configure the widget
5310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (!extras.isEmpty()) {
5320fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
5330fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    intent.setComponent(cn);
5340fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    intent.putExtras(extras);
5350fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
5360fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    mContext.sendBroadcast(intent);
5370fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            } catch (RuntimeException ex) {
5390fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.e(TAG, "Problem allocating appWidgetId", ex);
5400fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
5410fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return insertedId;
5420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
5430fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
5440fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5453a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected class FolderParser implements TagParser {
5463a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        private final HashMap<String, TagParser> mFolderElements;
5473a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
5483a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public FolderParser() {
5493a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            this(getFolderElementsMap());
5503a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
5513a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal
5523a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public FolderParser(HashMap<String, TagParser> elements) {
5533a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal            mFolderElements = elements;
5543a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        }
5550fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5560fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        @Override
5573a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal        public long parseAndAdd(XmlResourceParser parser)
5580fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                throws XmlPullParserException, IOException {
5590fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final String title;
5600fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
5610fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (titleResId != 0) {
5623a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                title = mSourceRes.getString(titleResId);
5630fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            } else {
5640fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                title = mContext.getResources().getString(R.string.folder_name);
5650fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
5660fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5670fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.TITLE, title);
5680fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER);
5690fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.SPANX, 1);
5700fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites.SPANY, 1);
5710fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            mValues.put(Favorites._ID, mCallback.generateNewItemId());
5720fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            long folderId = mCallback.insertAndCheck(mDb, mValues);
5730fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (folderId < 0) {
5740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (LOGD) Log.e(TAG, "Unable to add folder");
5750fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                return -1;
5760fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
5770fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5780fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            final ContentValues myValues = new ContentValues(mValues);
5790fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            ArrayList<Long> folderItems = new ArrayList<Long>();
5800fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5810fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            int type;
5820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            int folderDepth = parser.getDepth();
58356a57bb6bbcdfd3f309727fcfcbbc896f583ded9Sunny Goyal            int rank = 0;
5840fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            while ((type = parser.next()) != XmlPullParser.END_TAG ||
5850fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    parser.getDepth() > folderDepth) {
5860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (type != XmlPullParser.START_TAG) {
5870fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    continue;
5880fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5890fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.clear();
5900fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mValues.put(Favorites.CONTAINER, folderId);
59156a57bb6bbcdfd3f309727fcfcbbc896f583ded9Sunny Goyal                mValues.put(Favorites.RANK, rank);
5920fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
5930fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                TagParser tagParser = mFolderElements.get(parser.getName());
5940fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (tagParser != null) {
5953a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal                    final long id = tagParser.parseAndAdd(parser);
5960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    if (id >= 0) {
5970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                        folderItems.add(id);
59856a57bb6bbcdfd3f309727fcfcbbc896f583ded9Sunny Goyal                        rank++;
5990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    }
6000fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                } else {
6010fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    throw new RuntimeException("Invalid folder item " + parser.getName());
6020fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
6030fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
6040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            long addedId = folderId;
6060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            // We can only have folders with >= 2 items, so we need to remove the
6080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            // folder and clean up if less than 2 items were included, or some
6090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            // failed to add, and less than 2 were actually added
6100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (folderItems.size() < 2) {
6110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                // Delete the folder
6121d4a2df091e2b5928406ea503321563a0ec8a01eSunny Goyal                Uri uri = Favorites.getContentUri(folderId);
6130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                SqlArguments args = new SqlArguments(uri, null, null);
6140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                mDb.delete(args.table, args.where, args.args);
6150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                addedId = -1;
6160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                // If we have a single item, promote it to where the folder
6180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                // would have been.
6190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                if (folderItems.size() == 1) {
6200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    final ContentValues childValues = new ContentValues();
6210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    copyInteger(myValues, childValues, Favorites.CONTAINER);
6220fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    copyInteger(myValues, childValues, Favorites.SCREEN);
6230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    copyInteger(myValues, childValues, Favorites.CELLX);
6240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    copyInteger(myValues, childValues, Favorites.CELLY);
6250fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6260fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    addedId = folderItems.get(0);
6270fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    mDb.update(LauncherProvider.TABLE_FAVORITES, childValues,
6280fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                            Favorites._ID + "=" + addedId, null);
6290fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
6300fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
6310fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            return addedId;
6320fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
6330fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6340fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6353a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected static final void beginDocument(XmlPullParser parser, String firstElementName)
6360fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            throws XmlPullParserException, IOException {
6370fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        int type;
6380fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        while ((type = parser.next()) != XmlPullParser.START_TAG
6390fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                && type != XmlPullParser.END_DOCUMENT);
6400fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6410fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (type != XmlPullParser.START_TAG) {
6420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            throw new XmlPullParserException("No start tag found");
6430fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
6440fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6450fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (!parser.getName().equals(firstElementName)) {
6460fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
6470fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    ", expected " + firstElementName);
6480fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
6490fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6500fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6510fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    /**
6520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * Return attribute value, attempting launcher-specific namespace first
6530fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * before falling back to anonymous attribute.
6540fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     */
6553a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected static String getAttributeValue(XmlResourceParser parser, String attribute) {
6560fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        String value = parser.getAttributeValue(
6570fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute);
6580fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (value == null) {
6590fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            value = parser.getAttributeValue(null, attribute);
6600fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
6610fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        return value;
6620fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6630fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6640fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    /**
6650fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * Return attribute resource value, attempting launcher-specific namespace
6660fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * first before falling back to anonymous attribute.
6670fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     */
6683a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal    protected static int getAttributeResourceValue(XmlResourceParser parser, String attribute,
6690fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            int defaultValue) {
6700fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        int value = parser.getAttributeResourceValue(
6710fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute,
6720fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                defaultValue);
6730fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        if (value == defaultValue) {
6740fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            value = parser.getAttributeResourceValue(null, attribute, defaultValue);
6750fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
6760fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        return value;
6770fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6780fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6790fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    public static interface LayoutParserCallback {
6800fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        long generateNewItemId();
6810fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
6820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        long insertAndCheck(SQLiteDatabase db, ContentValues values);
6830fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6840fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
685091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk static void copyInteger(ContentValues from, ContentValues to, String key) {
6860fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        to.put(key, from.getAsInteger(key));
6870fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
6880fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal}
689