Loading src/com/android/launcher3/AutoInstallsLayout.java +25 −47 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ public class AutoInstallsLayout { parsers.put(TAG_APP_ICON, new AppShortcutParser()); parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser()); parsers.put(TAG_FOLDER, new FolderParser()); parsers.put(TAG_APPWIDGET, new AppWidgetParser()); parsers.put(TAG_APPWIDGET, new PendingWidgetParser()); parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes)); return parsers; } Loading Loading @@ -459,8 +459,12 @@ public class AutoInstallsLayout { /** * AppWidget parser: Required attributes packageName, className, spanX and spanY. * Options child nodes: <extra key=... value=... /> * It adds a pending widget which allows the widget to come later. If there are extras, those * are passed to widget options during bind. * The config activity for the widget (if present) is not shown, so any optional configurations * should be passed as extras and the widget should support reading these widget options. */ protected class AppWidgetParser implements TagParser { protected class PendingWidgetParser implements TagParser { @Override public long parseAndAdd(XmlResourceParser parser) Loading @@ -468,27 +472,13 @@ public class AutoInstallsLayout { final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); final String className = getAttributeValue(parser, ATTR_CLASS_NAME); if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) { if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component"); if (LOGD) Log.d(TAG, "Skipping invalid <appwidget> with no component"); return -1; } 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) { if (LOGD) Log.d(TAG, "Can't find widget provider: " + className); return -1; } } mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X)); mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y)); mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); // Read the extras Bundle extras = new Bundle(); Loading @@ -513,40 +503,28 @@ public class AutoInstallsLayout { } } final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); long insertedId = -1; try { int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn); return -1; return verifyAndInsert(new ComponentName(packageName, className), extras); } mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); mValues.put(Favorites.APPWIDGET_ID, appWidgetId); protected long verifyAndInsert(ComponentName cn, Bundle extras) { mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); mValues.put(Favorites.RESTORED, LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); mValues.put(Favorites._ID, mCallback.generateNewItemId()); insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { mAppWidgetHost.deleteAppWidgetId(appWidgetId); return insertedId; } // Send a broadcast to configure the widget if (!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) { if (LOGD) Log.e(TAG, "Problem allocating appWidgetId", ex); mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0)); } long insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { return -1; } else { return insertedId; } } } protected class FolderParser implements TagParser { private final HashMap<String, TagParser> mFolderElements; Loading src/com/android/launcher3/DefaultLayoutParser.java +64 −0 Original line number Diff line number Diff line package com.android.launcher3; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -9,6 +11,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; Loading Loading @@ -42,6 +45,10 @@ public class DefaultLayoutParser extends AutoInstallsLayout { private static final String ATTR_SCREEN = "screen"; private static final String ATTR_FOLDER_ITEMS = "folderItems"; // TODO: Remove support for this broadcast, instead use widget options to send bind time options private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE = "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE"; public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost, LayoutParserCallback callback, Resources sourceRes, int layoutId) { super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES); Loading Loading @@ -270,4 +277,61 @@ public class DefaultLayoutParser extends AutoInstallsLayout { return super.parseAndAdd(parser); } } /** * AppWidget parser which enforces that the app is already installed when the layout is parsed. */ protected class AppWidgetParser extends PendingWidgetParser { @Override protected long verifyAndInsert(ComponentName cn, Bundle extras) { try { mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e) { String[] packages = mPackageManager.currentToCanonicalPackageNames( new String[] { cn.getPackageName() }); cn = new ComponentName(packages[0], cn.getClassName()); try { mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e1) { Log.d(TAG, "Can't find widget provider: " + cn.getClassName()); return -1; } } final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); long insertedId = -1; try { int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { Log.e(TAG, "Unable to bind app widget id " + cn); mAppWidgetHost.deleteAppWidgetId(appWidgetId); return -1; } mValues.put(Favorites.APPWIDGET_ID, appWidgetId); mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); mValues.put(Favorites._ID, mCallback.generateNewItemId()); insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { mAppWidgetHost.deleteAppWidgetId(appWidgetId); return insertedId; } // Send a broadcast to configure the widget if (!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 insertedId; } } } src/com/android/launcher3/Launcher.java +17 −1 Original line number Diff line number Diff line Loading @@ -3952,14 +3952,30 @@ public class Launcher extends Activity pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); boolean isDirectConfig = item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); if (isDirectConfig && item.bindOptions != null) { Bundle newOptions = item.bindOptions.getExtras(); if (options != null) { newOptions.putAll(options); } options = newOptions; } boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( item.appWidgetId, appWidgetInfo, options); // We tried to bind once. If we were not able to bind, we would need to // go through the permission dialog, which means we cannot skip the config // activity. item.bindOptions = null; item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG; // Bind succeeded if (success) { // If the widget has a configure activity, it is still needs to set it up, // otherwise the widget is ready to go. item.restoreStatus = (appWidgetInfo.configure == null) item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig ? LauncherAppWidgetInfo.RESTORE_COMPLETED : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } Loading src/com/android/launcher3/LauncherAppWidgetInfo.java +14 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.appwidget.AppWidgetHostView; import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import com.android.launcher3.compat.UserHandleCompat; Loading Loading @@ -56,6 +57,12 @@ public class LauncherAppWidgetInfo extends ItemInfo { */ public static final int FLAG_ID_ALLOCATED = 16; /** * Indicates that the widget does not need to show config activity, even if it has a * configuration screen. It can also optionally have some extras which are sent during bind. */ public static final int FLAG_DIRECT_CONFIG = 32; /** * Indicates that the widget hasn't been instantiated yet. */ Loading Loading @@ -84,6 +91,11 @@ public class LauncherAppWidgetInfo extends ItemInfo { */ int installProgress = -1; /** * Optional extras sent during widget bind. See {@link #FLAG_DIRECT_CONFIG}. */ public Intent bindOptions; private boolean mHasNotifiedInitialWidgetSizeChanged; LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) { Loading Loading @@ -115,6 +127,8 @@ public class LauncherAppWidgetInfo extends ItemInfo { values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString()); values.put(LauncherSettings.Favorites.RESTORED, restoreStatus); values.put(LauncherSettings.Favorites.INTENT, bindOptions == null ? null : bindOptions.toUri(0)); } /** Loading src/com/android/launcher3/LauncherModel.java +9 −1 Original line number Diff line number Diff line Loading @@ -2144,7 +2144,7 @@ public class LauncherModel extends BroadcastReceiver // Id would be valid only if the widget restore broadcast was received. if (isIdValid) { status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } else { status &= ~LauncherAppWidgetInfo .FLAG_PROVIDER_NOT_READY; Loading Loading @@ -2175,6 +2175,14 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo.installProgress = installProgress == null ? 0 : installProgress; } if (appWidgetInfo.hasRestoreFlag( LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { intentDescription = c.getString(intentIndex); if (!TextUtils.isEmpty(intentDescription)) { appWidgetInfo.bindOptions = Intent.parseUri(intentDescription, 0); } } appWidgetInfo.id = id; appWidgetInfo.screenId = c.getInt(screenIndex); Loading Loading
src/com/android/launcher3/AutoInstallsLayout.java +25 −47 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ public class AutoInstallsLayout { parsers.put(TAG_APP_ICON, new AppShortcutParser()); parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser()); parsers.put(TAG_FOLDER, new FolderParser()); parsers.put(TAG_APPWIDGET, new AppWidgetParser()); parsers.put(TAG_APPWIDGET, new PendingWidgetParser()); parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes)); return parsers; } Loading Loading @@ -459,8 +459,12 @@ public class AutoInstallsLayout { /** * AppWidget parser: Required attributes packageName, className, spanX and spanY. * Options child nodes: <extra key=... value=... /> * It adds a pending widget which allows the widget to come later. If there are extras, those * are passed to widget options during bind. * The config activity for the widget (if present) is not shown, so any optional configurations * should be passed as extras and the widget should support reading these widget options. */ protected class AppWidgetParser implements TagParser { protected class PendingWidgetParser implements TagParser { @Override public long parseAndAdd(XmlResourceParser parser) Loading @@ -468,27 +472,13 @@ public class AutoInstallsLayout { final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); final String className = getAttributeValue(parser, ATTR_CLASS_NAME); if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) { if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component"); if (LOGD) Log.d(TAG, "Skipping invalid <appwidget> with no component"); return -1; } 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) { if (LOGD) Log.d(TAG, "Can't find widget provider: " + className); return -1; } } mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X)); mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y)); mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); // Read the extras Bundle extras = new Bundle(); Loading @@ -513,40 +503,28 @@ public class AutoInstallsLayout { } } final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); long insertedId = -1; try { int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn); return -1; return verifyAndInsert(new ComponentName(packageName, className), extras); } mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); mValues.put(Favorites.APPWIDGET_ID, appWidgetId); protected long verifyAndInsert(ComponentName cn, Bundle extras) { mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); mValues.put(Favorites.RESTORED, LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); mValues.put(Favorites._ID, mCallback.generateNewItemId()); insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { mAppWidgetHost.deleteAppWidgetId(appWidgetId); return insertedId; } // Send a broadcast to configure the widget if (!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) { if (LOGD) Log.e(TAG, "Problem allocating appWidgetId", ex); mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0)); } long insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { return -1; } else { return insertedId; } } } protected class FolderParser implements TagParser { private final HashMap<String, TagParser> mFolderElements; Loading
src/com/android/launcher3/DefaultLayoutParser.java +64 −0 Original line number Diff line number Diff line package com.android.launcher3; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -9,6 +11,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; Loading Loading @@ -42,6 +45,10 @@ public class DefaultLayoutParser extends AutoInstallsLayout { private static final String ATTR_SCREEN = "screen"; private static final String ATTR_FOLDER_ITEMS = "folderItems"; // TODO: Remove support for this broadcast, instead use widget options to send bind time options private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE = "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE"; public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost, LayoutParserCallback callback, Resources sourceRes, int layoutId) { super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES); Loading Loading @@ -270,4 +277,61 @@ public class DefaultLayoutParser extends AutoInstallsLayout { return super.parseAndAdd(parser); } } /** * AppWidget parser which enforces that the app is already installed when the layout is parsed. */ protected class AppWidgetParser extends PendingWidgetParser { @Override protected long verifyAndInsert(ComponentName cn, Bundle extras) { try { mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e) { String[] packages = mPackageManager.currentToCanonicalPackageNames( new String[] { cn.getPackageName() }); cn = new ComponentName(packages[0], cn.getClassName()); try { mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e1) { Log.d(TAG, "Can't find widget provider: " + cn.getClassName()); return -1; } } final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); long insertedId = -1; try { int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { Log.e(TAG, "Unable to bind app widget id " + cn); mAppWidgetHost.deleteAppWidgetId(appWidgetId); return -1; } mValues.put(Favorites.APPWIDGET_ID, appWidgetId); mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); mValues.put(Favorites._ID, mCallback.generateNewItemId()); insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { mAppWidgetHost.deleteAppWidgetId(appWidgetId); return insertedId; } // Send a broadcast to configure the widget if (!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 insertedId; } } }
src/com/android/launcher3/Launcher.java +17 −1 Original line number Diff line number Diff line Loading @@ -3952,14 +3952,30 @@ public class Launcher extends Activity pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); boolean isDirectConfig = item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); if (isDirectConfig && item.bindOptions != null) { Bundle newOptions = item.bindOptions.getExtras(); if (options != null) { newOptions.putAll(options); } options = newOptions; } boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( item.appWidgetId, appWidgetInfo, options); // We tried to bind once. If we were not able to bind, we would need to // go through the permission dialog, which means we cannot skip the config // activity. item.bindOptions = null; item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG; // Bind succeeded if (success) { // If the widget has a configure activity, it is still needs to set it up, // otherwise the widget is ready to go. item.restoreStatus = (appWidgetInfo.configure == null) item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig ? LauncherAppWidgetInfo.RESTORE_COMPLETED : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } Loading
src/com/android/launcher3/LauncherAppWidgetInfo.java +14 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.appwidget.AppWidgetHostView; import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import com.android.launcher3.compat.UserHandleCompat; Loading Loading @@ -56,6 +57,12 @@ public class LauncherAppWidgetInfo extends ItemInfo { */ public static final int FLAG_ID_ALLOCATED = 16; /** * Indicates that the widget does not need to show config activity, even if it has a * configuration screen. It can also optionally have some extras which are sent during bind. */ public static final int FLAG_DIRECT_CONFIG = 32; /** * Indicates that the widget hasn't been instantiated yet. */ Loading Loading @@ -84,6 +91,11 @@ public class LauncherAppWidgetInfo extends ItemInfo { */ int installProgress = -1; /** * Optional extras sent during widget bind. See {@link #FLAG_DIRECT_CONFIG}. */ public Intent bindOptions; private boolean mHasNotifiedInitialWidgetSizeChanged; LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) { Loading Loading @@ -115,6 +127,8 @@ public class LauncherAppWidgetInfo extends ItemInfo { values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString()); values.put(LauncherSettings.Favorites.RESTORED, restoreStatus); values.put(LauncherSettings.Favorites.INTENT, bindOptions == null ? null : bindOptions.toUri(0)); } /** Loading
src/com/android/launcher3/LauncherModel.java +9 −1 Original line number Diff line number Diff line Loading @@ -2144,7 +2144,7 @@ public class LauncherModel extends BroadcastReceiver // Id would be valid only if the widget restore broadcast was received. if (isIdValid) { status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } else { status &= ~LauncherAppWidgetInfo .FLAG_PROVIDER_NOT_READY; Loading Loading @@ -2175,6 +2175,14 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo.installProgress = installProgress == null ? 0 : installProgress; } if (appWidgetInfo.hasRestoreFlag( LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { intentDescription = c.getString(intentIndex); if (!TextUtils.isEmpty(intentDescription)) { appWidgetInfo.bindOptions = Intent.parseUri(intentDescription, 0); } } appWidgetInfo.id = id; appWidgetInfo.screenId = c.getInt(screenIndex); Loading