summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-08-10 15:03:22 -0700
committerSunny Goyal <sunnygoyal@google.com>2016-08-16 12:37:29 -0700
commit86df138d9f5b32d947f3497314694a2a7adac70c (patch)
treeb4440a3ef424b7f9c0b7d58d01e32b25b4cba155
parenteea721266f0a7c2c60097cba8363cfca12de9e46 (diff)
downloadandroid_packages_apps_Trebuchet-86df138d9f5b32d947f3497314694a2a7adac70c.tar.gz
android_packages_apps_Trebuchet-86df138d9f5b32d947f3497314694a2a7adac70c.tar.bz2
android_packages_apps_Trebuchet-86df138d9f5b32d947f3497314694a2a7adac70c.zip
Adding support for pending widgets in AutoInstall layout
> Pending widgets whill show a loading progress while the app is being installed. > Extra bind options can be defined using the tub tags <extra key="key-name" value="key-value" /> These are sent as widget options when the widget is bound. > If the widget has any config activity, it is not shown > Required attributes: className, packageName, x, y, spanY, spanY & screen Bug: 30279609 Change-Id: I1338618bfa5d86967339dffb68c12b1add6eb5d7
-rw-r--r--src/com/android/launcher3/AutoInstallsLayout.java72
-rw-r--r--src/com/android/launcher3/DefaultLayoutParser.java64
-rw-r--r--src/com/android/launcher3/Launcher.java18
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetInfo.java14
-rw-r--r--src/com/android/launcher3/LauncherModel.java10
5 files changed, 129 insertions, 49 deletions
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 0d5043bb2..d5309b4f0 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -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;
}
@@ -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)
@@ -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();
@@ -513,38 +503,26 @@ 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);
- 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;
- }
+ 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());
+ if (!extras.isEmpty()) {
+ mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0));
+ }
- // 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);
+ long insertedId = mCallback.insertAndCheck(mDb, mValues);
+ if (insertedId < 0) {
+ return -1;
+ } else {
+ return insertedId;
}
- return insertedId;
}
}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index e6f34d952..ef28d1e8c 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -1,6 +1,8 @@
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;
@@ -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;
@@ -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);
@@ -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;
+ }
+ }
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 886c5f0a2..c6fee8d56 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -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;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 99210fd34..f22c2a474 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -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;
@@ -57,6 +58,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.
*/
static final int NO_ID = -1;
@@ -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) {
@@ -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));
}
/**
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 6a63110b1..d4223e1ff 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -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;
@@ -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);