Merge "Adding support for pending widgets in AutoInstall layout" into ub-launcher3-calgary-polish
This commit is contained in:
@@ -316,7 +316,7 @@ public class AutoInstallsLayout {
|
|||||||
parsers.put(TAG_APP_ICON, new AppShortcutParser());
|
parsers.put(TAG_APP_ICON, new AppShortcutParser());
|
||||||
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
|
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
|
||||||
parsers.put(TAG_FOLDER, new FolderParser());
|
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));
|
parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
|
||||||
return parsers;
|
return parsers;
|
||||||
}
|
}
|
||||||
@@ -459,8 +459,12 @@ public class AutoInstallsLayout {
|
|||||||
/**
|
/**
|
||||||
* AppWidget parser: Required attributes packageName, className, spanX and spanY.
|
* AppWidget parser: Required attributes packageName, className, spanX and spanY.
|
||||||
* Options child nodes: <extra key=... value=... />
|
* 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
|
@Override
|
||||||
public long parseAndAdd(XmlResourceParser parser)
|
public long parseAndAdd(XmlResourceParser parser)
|
||||||
@@ -468,27 +472,13 @@ public class AutoInstallsLayout {
|
|||||||
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
|
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
|
||||||
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
|
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
|
||||||
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
|
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;
|
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.SPANX, getAttributeValue(parser, ATTR_SPAN_X));
|
||||||
mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y));
|
mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y));
|
||||||
|
mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
|
||||||
|
|
||||||
// Read the extras
|
// Read the extras
|
||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
@@ -513,38 +503,26 @@ public class AutoInstallsLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
return verifyAndInsert(new ComponentName(packageName, className), extras);
|
||||||
long insertedId = -1;
|
}
|
||||||
try {
|
|
||||||
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
|
|
||||||
|
|
||||||
if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) {
|
protected long verifyAndInsert(ComponentName cn, Bundle extras) {
|
||||||
if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn);
|
mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
|
||||||
return -1;
|
mValues.put(Favorites.RESTORED,
|
||||||
}
|
LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
|
||||||
|
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
|
||||||
mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
|
LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
|
||||||
mValues.put(Favorites.APPWIDGET_ID, appWidgetId);
|
mValues.put(Favorites._ID, mCallback.generateNewItemId());
|
||||||
mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
|
if (!extras.isEmpty()) {
|
||||||
mValues.put(Favorites._ID, mCallback.generateNewItemId());
|
mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0));
|
||||||
insertedId = mCallback.insertAndCheck(mDb, mValues);
|
}
|
||||||
if (insertedId < 0) {
|
|
||||||
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
|
long insertedId = mCallback.insertAndCheck(mDb, mValues);
|
||||||
return insertedId;
|
if (insertedId < 0) {
|
||||||
}
|
return -1;
|
||||||
|
} else {
|
||||||
// Send a broadcast to configure the widget
|
return insertedId;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
return insertedId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.android.launcher3;
|
package com.android.launcher3;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetHost;
|
import android.appwidget.AppWidgetHost;
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
@@ -9,6 +11,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
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_SCREEN = "screen";
|
||||||
private static final String ATTR_FOLDER_ITEMS = "folderItems";
|
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,
|
public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
|
||||||
LayoutParserCallback callback, Resources sourceRes, int layoutId) {
|
LayoutParserCallback callback, Resources sourceRes, int layoutId) {
|
||||||
super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
|
super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
|
||||||
@@ -270,4 +277,61 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
|
|||||||
return super.parseAndAdd(parser);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3952,14 +3952,30 @@ public class Launcher extends Activity
|
|||||||
pendingInfo.minSpanX = item.minSpanX;
|
pendingInfo.minSpanX = item.minSpanX;
|
||||||
pendingInfo.minSpanY = item.minSpanY;
|
pendingInfo.minSpanY = item.minSpanY;
|
||||||
Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
|
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(
|
boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
|
||||||
item.appWidgetId, appWidgetInfo, options);
|
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
|
// Bind succeeded
|
||||||
if (success) {
|
if (success) {
|
||||||
// If the widget has a configure activity, it is still needs to set it up,
|
// If the widget has a configure activity, it is still needs to set it up,
|
||||||
// otherwise the widget is ready to go.
|
// otherwise the widget is ready to go.
|
||||||
item.restoreStatus = (appWidgetInfo.configure == null)
|
item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig
|
||||||
? LauncherAppWidgetInfo.RESTORE_COMPLETED
|
? LauncherAppWidgetInfo.RESTORE_COMPLETED
|
||||||
: LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
: LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.appwidget.AppWidgetHostView;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.android.launcher3.compat.UserHandleCompat;
|
import com.android.launcher3.compat.UserHandleCompat;
|
||||||
|
|
||||||
@@ -56,6 +57,12 @@ public class LauncherAppWidgetInfo extends ItemInfo {
|
|||||||
*/
|
*/
|
||||||
public static final int FLAG_ID_ALLOCATED = 16;
|
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.
|
* Indicates that the widget hasn't been instantiated yet.
|
||||||
*/
|
*/
|
||||||
@@ -84,6 +91,11 @@ public class LauncherAppWidgetInfo extends ItemInfo {
|
|||||||
*/
|
*/
|
||||||
int installProgress = -1;
|
int installProgress = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional extras sent during widget bind. See {@link #FLAG_DIRECT_CONFIG}.
|
||||||
|
*/
|
||||||
|
public Intent bindOptions;
|
||||||
|
|
||||||
private boolean mHasNotifiedInitialWidgetSizeChanged;
|
private boolean mHasNotifiedInitialWidgetSizeChanged;
|
||||||
|
|
||||||
LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
|
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_ID, appWidgetId);
|
||||||
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
|
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
|
||||||
values.put(LauncherSettings.Favorites.RESTORED, restoreStatus);
|
values.put(LauncherSettings.Favorites.RESTORED, restoreStatus);
|
||||||
|
values.put(LauncherSettings.Favorites.INTENT,
|
||||||
|
bindOptions == null ? null : bindOptions.toUri(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2144,7 +2144,7 @@ public class LauncherModel extends BroadcastReceiver
|
|||||||
|
|
||||||
// Id would be valid only if the widget restore broadcast was received.
|
// Id would be valid only if the widget restore broadcast was received.
|
||||||
if (isIdValid) {
|
if (isIdValid) {
|
||||||
status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
||||||
} else {
|
} else {
|
||||||
status &= ~LauncherAppWidgetInfo
|
status &= ~LauncherAppWidgetInfo
|
||||||
.FLAG_PROVIDER_NOT_READY;
|
.FLAG_PROVIDER_NOT_READY;
|
||||||
@@ -2175,6 +2175,14 @@ public class LauncherModel extends BroadcastReceiver
|
|||||||
appWidgetInfo.installProgress =
|
appWidgetInfo.installProgress =
|
||||||
installProgress == null ? 0 : 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.id = id;
|
||||||
appWidgetInfo.screenId = c.getInt(screenIndex);
|
appWidgetInfo.screenId = c.getInt(screenIndex);
|
||||||
|
|||||||
Reference in New Issue
Block a user