summaryrefslogtreecommitdiffstats
path: root/core/java/android/appwidget
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/appwidget')
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java131
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java27
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java413
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java140
4 files changed, 493 insertions, 218 deletions
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 84d3835..e7b68f5 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -19,7 +19,11 @@ package android.appwidget;
import java.util.ArrayList;
import java.util.HashMap;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -61,32 +65,30 @@ public class AppWidgetHost {
private OnClickHandler mOnClickHandler;
class Callbacks extends IAppWidgetHost.Stub {
- public void updateAppWidget(int appWidgetId, RemoteViews views, int userId) {
+ public void updateAppWidget(int appWidgetId, RemoteViews views) {
if (isLocalBinder() && views != null) {
views = views.clone();
- views.setUser(new UserHandle(userId));
}
- Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, userId, views);
+ Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, 0, views);
msg.sendToTarget();
}
- public void providerChanged(int appWidgetId, AppWidgetProviderInfo info, int userId) {
+ public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
if (isLocalBinder() && info != null) {
info = info.clone();
}
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED,
- appWidgetId, userId, info);
+ appWidgetId, 0, info);
msg.sendToTarget();
}
- public void providersChanged(int userId) {
- Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED, userId, 0);
- msg.sendToTarget();
+ public void providersChanged() {
+ mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED).sendToTarget();
}
- public void viewDataChanged(int appWidgetId, int viewId, int userId) {
+ public void viewDataChanged(int appWidgetId, int viewId) {
Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
- appWidgetId, viewId, userId);
+ appWidgetId, viewId);
msg.sendToTarget();
}
}
@@ -99,7 +101,7 @@ public class AppWidgetHost {
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_UPDATE: {
- updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj, msg.arg2);
+ updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
break;
}
case HANDLE_PROVIDER_CHANGED: {
@@ -111,7 +113,7 @@ public class AppWidgetHost {
break;
}
case HANDLE_VIEW_DATA_CHANGED: {
- viewDataChanged(msg.arg1, msg.arg2, (Integer) msg.obj);
+ viewDataChanged(msg.arg1, msg.arg2);
break;
}
}
@@ -151,25 +153,20 @@ public class AppWidgetHost {
public void startListening() {
int[] updatedIds;
ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
-
- final int userId = mContext.getUserId();
try {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
- updatedIds = sService.startListening(
- mCallbacks, mPackageName, mHostId, updatedViews, userId);
+ updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId,
+ updatedViews);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
final int N = updatedIds.length;
- for (int i=0; i<N; i++) {
- if (updatedViews.get(i) != null) {
- updatedViews.get(i).setUser(new UserHandle(userId));
- }
- updateAppWidgetView(updatedIds[i], updatedViews.get(i), userId);
+ for (int i = 0; i < N; i++) {
+ updateAppWidgetView(updatedIds[i], updatedViews.get(i));
}
}
@@ -179,7 +176,7 @@ public class AppWidgetHost {
*/
public void stopListening() {
try {
- sService.stopListening(mHostId, mContext.getUserId());
+ sService.stopListening(mPackageName, mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -200,7 +197,7 @@ public class AppWidgetHost {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
- return sService.allocateAppWidgetId(mPackageName, mHostId, mContext.getUserId());
+ return sService.allocateAppWidgetId(mPackageName, mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -208,18 +205,39 @@ public class AppWidgetHost {
}
/**
- * Get a appWidgetId for a host in the given package.
+ * Starts an app widget provider configure activity for result on behalf of the caller.
+ * Use this method if the provider is in another profile as you are not allowed to start
+ * an activity in another profile. The provided intent must have action {@link
+ * AppWidgetManager#ACTION_APPWIDGET_CONFIGURE}. The widget id must be specified by
+ * the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} extra. The provider configure
+ * activity must be specified as the component name of the intent via {@link
+ * Intent#setComponent(android.content.ComponentName)}. The user profile under which
+ * the provider operates is specified via the {@link
+ * AppWidgetManager#EXTRA_APPWIDGET_PROVIDER_PROFILE} extra. If a user profile is
+ * not provided, the current user is used. Finally, you can optionally provide a
+ * request code that is returned in {@link Activity#onActivityResult(int, int,
+ * android.content.Intent)}.
*
- * @return a appWidgetId
- * @hide
+ * @param activity The activity from which to start the configure one.
+ * @param intent Properly populated intent for launching the configuration activity.
+ * @param requestCode Optional request code retuned with the result.
+ *
+ * @throws android.content.ActivityNotFoundException If the activity is not found.
+ *
+ * @see AppWidgetProviderInfo#getProfile()
*/
- public static int allocateAppWidgetIdForPackage(int hostId, int userId, String packageName) {
- checkCallerIsSystem();
+ public final void startAppWidgetConfigureActivityForResult(Activity activity, Intent intent,
+ int requestCode) {
try {
- if (sService == null) {
- bindService();
+ IntentSender intentSender = sService.createAppWidgetConfigIntentSender(
+ mContext.getPackageName(), intent);
+ if (intentSender != null) {
+ activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0);
+ } else {
+ throw new ActivityNotFoundException();
}
- return sService.allocateAppWidgetId(packageName, hostId, userId);
+ } catch (IntentSender.SendIntentException e) {
+ throw new ActivityNotFoundException();
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -235,20 +253,12 @@ public class AppWidgetHost {
if (sService == null) {
bindService();
}
- return sService.getAppWidgetIdsForHost(mHostId, mContext.getUserId());
+ return sService.getAppWidgetIdsForHost(mContext.getPackageName(), mHostId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
- private static void checkCallerIsSystem() {
- int uid = Process.myUid();
- if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
- return;
- }
- throw new SecurityException("Disallowed call for uid " + uid);
- }
-
private boolean isLocalBinder() {
return Process.myPid() == Binder.getCallingPid();
}
@@ -260,7 +270,7 @@ public class AppWidgetHost {
synchronized (mViews) {
mViews.remove(appWidgetId);
try {
- sService.deleteAppWidgetId(appWidgetId, mContext.getUserId());
+ sService.deleteAppWidgetId(mContext.getPackageName(), appWidgetId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -269,22 +279,6 @@ public class AppWidgetHost {
}
/**
- * Stop listening to changes for this AppWidget.
- * @hide
- */
- public static void deleteAppWidgetIdForSystem(int appWidgetId, int userId) {
- checkCallerIsSystem();
- try {
- if (sService == null) {
- bindService();
- }
- sService.deleteAppWidgetId(appWidgetId, userId);
- } catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-
- /**
* Remove all records about this host from the AppWidget manager.
* <ul>
* <li>Call this when initializing your database, as it might be because of a data wipe.</li>
@@ -294,7 +288,7 @@ public class AppWidgetHost {
*/
public void deleteHost() {
try {
- sService.deleteHost(mHostId, mContext.getUserId());
+ sService.deleteHost(mContext.getPackageName(), mHostId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -310,16 +304,8 @@ public class AppWidgetHost {
* </ul>
*/
public static void deleteAllHosts() {
- deleteAllHosts(UserHandle.myUserId());
- }
-
- /**
- * Private method containing a userId
- * @hide
- */
- public static void deleteAllHosts(int userId) {
try {
- sService.deleteAllHosts(userId);
+ sService.deleteAllHosts();
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -332,9 +318,7 @@ public class AppWidgetHost {
*/
public final AppWidgetHostView createView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- final int userId = mContext.getUserId();
AppWidgetHostView view = onCreateView(mContext, appWidgetId, appWidget);
- view.setUserId(userId);
view.setOnClickHandler(mOnClickHandler);
view.setAppWidget(appWidgetId, appWidget);
synchronized (mViews) {
@@ -342,10 +326,7 @@ public class AppWidgetHost {
}
RemoteViews views;
try {
- views = sService.getAppWidgetViews(appWidgetId, userId);
- if (views != null) {
- views.setUser(new UserHandle(mContext.getUserId()));
- }
+ views = sService.getAppWidgetViews(mPackageName, appWidgetId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -397,7 +378,7 @@ public class AppWidgetHost {
// Does nothing
}
- void updateAppWidgetView(int appWidgetId, RemoteViews views, int userId) {
+ void updateAppWidgetView(int appWidgetId, RemoteViews views) {
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
@@ -407,7 +388,7 @@ public class AppWidgetHost {
}
}
- void viewDataChanged(int appWidgetId, int viewId, int userId) {
+ void viewDataChanged(int appWidgetId, int viewId) {
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 700bba8..1ff476e 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -87,7 +87,6 @@ public class AppWidgetHostView extends FrameLayout {
Bitmap mOld;
Paint mOldPaint = new Paint();
private OnClickHandler mOnClickHandler;
- private UserHandle mUser;
/**
* Create a host view. Uses default fade animations.
@@ -115,17 +114,11 @@ public class AppWidgetHostView extends FrameLayout {
public AppWidgetHostView(Context context, int animationIn, int animationOut) {
super(context);
mContext = context;
- mUser = Process.myUserHandle();
// We want to segregate the view ids within AppWidgets to prevent
// problems when those ids collide with view ids in the AppWidgetHost.
setIsRootNamespace(true);
}
- /** @hide */
- public void setUserId(int userId) {
- mUser = new UserHandle(userId);
- }
-
/**
* Pass the given handler to RemoteViews when updating this widget. Unless this
* is done immediatly after construction, a call to {@link #updateAppWidget(RemoteViews)}
@@ -380,7 +373,7 @@ public class AppWidgetHostView extends FrameLayout {
} else {
// Prepare a local reference to the remote Context so we're ready to
// inflate any requested LayoutParams.
- mRemoteContext = getRemoteContext(remoteViews);
+ mRemoteContext = getRemoteContext();
int layoutId = remoteViews.getLayoutId();
// If our stale view has been prepared to match active, and the new
@@ -466,17 +459,14 @@ public class AppWidgetHostView extends FrameLayout {
* Build a {@link Context} cloned into another package name, usually for the
* purposes of reading remote resources.
*/
- private Context getRemoteContext(RemoteViews views) {
- // Bail if missing package name
- final String packageName = views.getPackage();
- if (packageName == null) return mContext;
-
+ private Context getRemoteContext() {
try {
// Return if cloned successfully, otherwise default
- return mContext.createPackageContextAsUser(packageName, Context.CONTEXT_RESTRICTED,
- mUser);
+ return mContext.createApplicationContext(
+ mInfo.providerInfo.applicationInfo,
+ Context.CONTEXT_RESTRICTED);
} catch (NameNotFoundException e) {
- Log.e(TAG, "Package name " + packageName + " not found");
+ Log.e(TAG, "Package name " + mInfo.providerInfo.packageName + " not found");
return mContext;
}
}
@@ -548,8 +538,7 @@ public class AppWidgetHostView extends FrameLayout {
try {
if (mInfo != null) {
- Context theirContext = mContext.createPackageContextAsUser(
- mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED, mUser);
+ Context theirContext = getRemoteContext();
mRemoteContext = theirContext;
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -572,8 +561,6 @@ public class AppWidgetHostView extends FrameLayout {
} else {
Log.w(TAG, "can't inflate defaultView because mInfo is missing");
}
- } catch (PackageManager.NameNotFoundException e) {
- exception = e;
} catch (RuntimeException e) {
exception = e;
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index e5bf7d0..e5d1d95 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -21,8 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -30,9 +30,8 @@ import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetService;
-import java.lang.ref.WeakReference;
+import java.util.Collections;
import java.util.List;
-import java.util.WeakHashMap;
/**
* Updates AppWidget state; gets information about installed AppWidget providers and other
@@ -45,7 +44,6 @@ import java.util.WeakHashMap;
* </div>
*/
public class AppWidgetManager {
- static final String TAG = "AppWidgetManager";
/**
* Activity action to launch from your {@link AppWidgetHost} activity when you want to
@@ -72,9 +70,9 @@ public class AppWidgetManager {
* <p>
* When you receive the result from the AppWidget pick activity, if the resultCode is
* {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected. You should then
- * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
- * activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
- * the appWidgetId.
+ * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
+ * configuration activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you
+ * should delete the appWidgetId.
*
* @see #ACTION_APPWIDGET_CONFIGURE
*/
@@ -103,6 +101,12 @@ public class AppWidgetManager {
* <td>The BroadcastReceiver that will be the AppWidget provider for this AppWidget.
* </td>
* </tr>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_PROVIDER_PROFILE}</td>
+ * <td>An optional handle to a user profile under which runs the provider
+ * for this AppWidget.
+ * </td>
+ * </tr>
* </table>
*
* <p>
@@ -119,8 +123,7 @@ public class AppWidgetManager {
* {@link android.app.Activity#RESULT_OK}, the AppWidget has been bound. You should then
* check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
* configuration activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you
- * should delete
- * the appWidgetId.
+ * should delete the appWidgetId.
*
* @see #ACTION_APPWIDGET_CONFIGURE
*
@@ -130,7 +133,8 @@ public class AppWidgetManager {
/**
* Sent when it is time to configure your AppWidget while it is being added to a host.
* This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
- * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
+ * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo
+ * meta-data}.
*
* <p>
* The intent will contain the following extras:
@@ -145,7 +149,8 @@ public class AppWidgetManager {
* {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
* and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
* If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
- * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
+ * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
+ * broadcast.
*/
public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
@@ -188,7 +193,9 @@ public class AppWidgetManager {
/**
* An intent extra which points to a bundle of extra information for a particular widget id.
- * In particular this bundle can contain EXTRA_APPWIDGET_WIDTH and EXTRA_APPWIDGET_HEIGHT.
+ * In particular this bundle can contain {@link #OPTION_APPWIDGET_MIN_WIDTH},
+ * {@link #OPTION_APPWIDGET_MIN_HEIGHT}, {@link #OPTION_APPWIDGET_MAX_WIDTH},
+ * {@link #OPTION_APPWIDGET_MAX_HEIGHT}.
*/
public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
@@ -203,11 +210,19 @@ public class AppWidgetManager {
/**
* An intent extra that contains the component name of a AppWidget provider.
* <p>
- * The value will be an ComponentName.
+ * The value will be an {@link android.content.ComponentName}.
*/
public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
/**
+ * An intent extra that contains the user handle of the profile under
+ * which an AppWidget provider is registered.
+ * <p>
+ * The value will be a {@link android.os.UserHandle}.
+ */
+ public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
+
+ /**
* An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
* {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
* installed. (This is how the launcher shows the search widget).
@@ -295,12 +310,12 @@ public class AppWidgetManager {
public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
/**
- * Sent when an instance of an AppWidget is removed from the last host.
+ * Sent when the last AppWidget of this provider is removed from the last host.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
*
- * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
+ * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
*/
public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
@@ -403,46 +418,36 @@ public class AppWidgetManager {
*/
public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
- static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache =
- new WeakHashMap<Context, WeakReference<AppWidgetManager>>();
- static IAppWidgetService sService;
+ private final String mPackageName;
- Context mContext;
+ private final IAppWidgetService mService;
- private DisplayMetrics mDisplayMetrics;
+ private final DisplayMetrics mDisplayMetrics;
/**
* Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
* Context} object.
*/
public static AppWidgetManager getInstance(Context context) {
- synchronized (sManagerCache) {
- if (sService == null) {
- IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
- sService = IAppWidgetService.Stub.asInterface(b);
- }
-
- WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
- AppWidgetManager result = null;
- if (ref != null) {
- result = ref.get();
- }
- if (result == null) {
- result = new AppWidgetManager(context);
- sManagerCache.put(context, new WeakReference<AppWidgetManager>(result));
- }
- return result;
- }
+ return (AppWidgetManager) context.getSystemService(Context.APPWIDGET_SERVICE);
}
- private AppWidgetManager(Context context) {
- mContext = context;
+ /**
+ * Creates a new instance.
+ *
+ * @param context The current context in which to operate.
+ * @param service The backing system service.
+ * @hide
+ */
+ public AppWidgetManager(Context context, IAppWidgetService service) {
+ mPackageName = context.getPackageName();
+ mService = service;
mDisplayMetrics = context.getResources().getDisplayMetrics();
}
/**
* Set the RemoteViews to use for the specified appWidgetIds.
- *
+ * <p>
* Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
* contain a complete representation of the widget. For performing partial widget updates, see
* {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
@@ -456,12 +461,15 @@ public class AppWidgetManager {
* The total Bitmap memory used by the RemoteViews object cannot exceed that required to
* fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
*
- * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
- * @param views The RemoteViews object to show.
+ * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
+ * @param views The RemoteViews object to show.
*/
public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.updateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
+ mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -470,18 +478,21 @@ public class AppWidgetManager {
/**
* Update the extras for a given widget instance.
- *
+ * <p>
* The extras can be used to embed additional information about this widget to be accessed
* by the associated widget's AppWidgetProvider.
*
* @see #getAppWidgetOptions(int)
*
- * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
- * @param options The options to associate with this widget
+ * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
+ * @param options The options to associate with this widget
*/
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.updateAppWidgetOptions(appWidgetId, options, mContext.getUserId());
+ mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -490,18 +501,21 @@ public class AppWidgetManager {
/**
* Get the extras associated with a given widget instance.
- *
+ * <p>
* The extras can be used to embed additional information about this widget to be accessed
* by the associated widget's AppWidgetProvider.
*
* @see #updateAppWidgetOptions(int, Bundle)
*
- * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
- * @return The options associated with the given widget instance.
+ * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
+ * @return The options associated with the given widget instance.
*/
public Bundle getAppWidgetOptions(int appWidgetId) {
+ if (mService == null) {
+ return Bundle.EMPTY;
+ }
try {
- return sService.getAppWidgetOptions(appWidgetId, mContext.getUserId());
+ return mService.getAppWidgetOptions(mPackageName, appWidgetId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -510,7 +524,7 @@ public class AppWidgetManager {
/**
* Set the RemoteViews to use for the specified appWidgetId.
- *
+ * <p>
* Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
* contain a complete representation of the widget. For performing partial widget updates, see
* {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
@@ -528,12 +542,15 @@ public class AppWidgetManager {
* @param views The RemoteViews object to show.
*/
public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ if (mService == null) {
+ return;
+ }
updateAppWidget(new int[] { appWidgetId }, views);
}
/**
* Perform an incremental update or command on the widget(s) specified by appWidgetIds.
- *
+ * <p>
* This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
* RemoteViews object which is passed is understood to be an incomplete representation of the
* widget, and hence does not replace the cached representation of the widget. As of API
@@ -556,8 +573,11 @@ public class AppWidgetManager {
* @param views The RemoteViews object containing the incremental update / command.
*/
public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.partiallyUpdateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
+ mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -565,7 +585,7 @@ public class AppWidgetManager {
/**
* Perform an incremental update or command on the widget specified by appWidgetId.
- *
+ * <p>
* This update differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
* object which is passed is understood to be an incomplete representation of the widget, and
* hence is not cached by the AppWidgetService. Note that because these updates are not cached,
@@ -588,6 +608,9 @@ public class AppWidgetManager {
* @param views The RemoteViews object containing the incremental update / command.
*/
public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
+ if (mService == null) {
+ return;
+ }
partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
}
@@ -605,8 +628,11 @@ public class AppWidgetManager {
* @param views The RemoteViews object to show.
*/
public void updateAppWidget(ComponentName provider, RemoteViews views) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.updateAppWidgetProvider(provider, views, mContext.getUserId());
+ mService.updateAppWidgetProvider(provider, views);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -621,8 +647,11 @@ public class AppWidgetManager {
* @param viewId The collection view id.
*/
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId, mContext.getUserId());
+ mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -637,37 +666,106 @@ public class AppWidgetManager {
* @param viewId The collection view id.
*/
public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
+ if (mService == null) {
+ return;
+ }
notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
}
/**
+ * Gets the AppWidget providers for the given user profiles. User profiles can only
+ * be the current user or a profile of the current user. For example, the current
+ * user may have a corporate profile. In this case the parent user profile has a
+ * child profile, the corporate one.
+ *
+ * @param profiles The profiles for which to get providers. Passing null is equivaled
+ * to passing only the current user handle.
+ * @return The intalled providers.
+ *
+ * @see android.os.Process#myUserHandle()
+ * @see android.os.UserManager#getUserProfiles()
+ */
+ public List<AppWidgetProviderInfo> getInstalledProvidersForProfiles(UserHandle[] profiles) {
+ if (mService == null) {
+ return Collections.emptyList();
+ }
+ return getInstalledProvidersForProfiles(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
+ profiles);
+ }
+
+ /**
* Return a list of the AppWidget providers that are currently installed.
*/
public List<AppWidgetProviderInfo> getInstalledProviders() {
- return getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
+ if (mService == null) {
+ return Collections.emptyList();
+ }
+ return getInstalledProvidersForProfiles(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
+ null);
}
/**
- * Return a list of the AppWidget providers that are currently installed.
+ * Gets the AppWidget providers for the current user.
*
* @param categoryFilter Will only return providers which register as any of the specified
* specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
+ * @return The intalled providers.
+ *
+ * @see android.os.Process#myUserHandle()
+ * @see android.os.UserManager#getUserProfiles()
+ *
* @hide
*/
public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
+ if (mService == null) {
+ return Collections.emptyList();
+ }
+ return getInstalledProvidersForProfiles(categoryFilter, null);
+ }
+
+ /**
+ * Gets the AppWidget providers for the given user profiles. User profiles can only
+ * be the current user or a profile of the current user. For example, the current
+ * user may have a corporate profile. In this case the parent user profile has a
+ * child profile, the corporate one.
+ *
+ * @param categoryFilter Will only return providers which register as any of the specified
+ * specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
+ * @param profiles Child profiles of the current user which to be queried. The user
+ * is itself also a profile. If null, the providers only for the current user
+ * are returned.
+ * @return The intalled providers.
+ *
+ * @see android.os.Process#myUserHandle()
+ * @see android.os.UserManager#getUserProfiles()
+ *
+ * @hide
+ */
+ public List<AppWidgetProviderInfo> getInstalledProvidersForProfiles(int categoryFilter,
+ UserHandle[] profiles) {
+ if (mService == null) {
+ return Collections.emptyList();
+ }
+
+ int[] profileIds = null;
+
+ if (profiles != null) {
+ final int profileCount = profiles.length;
+ profileIds = new int[profileCount];
+ for (int i = 0; i < profileCount; i++) {
+ profileIds[i] = profiles[i].getIdentifier();
+ }
+ }
+
try {
- List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter,
- mContext.getUserId());
+ List<AppWidgetProviderInfo> providers = mService.getInstalledProviders(categoryFilter,
+ profileIds);
+ if (providers == null) {
+ return Collections.emptyList();
+ }
for (AppWidgetProviderInfo info : providers) {
// Converting complex to dp.
- info.minWidth =
- TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
- info.minHeight =
- TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
- info.minResizeWidth =
- TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
- info.minResizeHeight =
- TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
+ convertSizesToPixels(info);
}
return providers;
}
@@ -683,19 +781,14 @@ public class AppWidgetManager {
* you don't have access to that appWidgetId, null is returned.
*/
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ if (mService == null) {
+ return null;
+ }
try {
- AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId,
- mContext.getUserId());
+ AppWidgetProviderInfo info = mService.getAppWidgetInfo(mPackageName, appWidgetId);
if (info != null) {
// Converting complex to dp.
- info.minWidth =
- TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
- info.minHeight =
- TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
- info.minResizeWidth =
- TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
- info.minResizeHeight =
- TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
+ convertSizesToPixels(info);
}
return info;
}
@@ -717,12 +810,10 @@ public class AppWidgetManager {
* @hide
*/
public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
- try {
- sService.bindAppWidgetId(appWidgetId, provider, null, mContext.getUserId());
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ if (mService == null) {
+ return;
}
+ bindAppWidgetId(appWidgetId, provider, null);
}
/**
@@ -741,12 +832,10 @@ public class AppWidgetManager {
* @hide
*/
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
- try {
- sService.bindAppWidgetId(appWidgetId, provider, options, mContext.getUserId());
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ if (mService == null) {
+ return;
}
+ bindAppWidgetIdIfAllowed(appWidgetId, Process.myUserHandle(), provider, options);
}
/**
@@ -757,22 +846,16 @@ public class AppWidgetManager {
* method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
* bind
*
- * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param appWidgetId The AppWidget id under which to bind the provider.
* @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
* provider for this AppWidget.
* @return true if this component has permission to bind the AppWidget
*/
public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) {
- if (mContext == null) {
+ if (mService == null) {
return false;
}
- try {
- return sService.bindAppWidgetIdIfAllowed(
- mContext.getPackageName(), appWidgetId, provider, null, mContext.getUserId());
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
+ return bindAppWidgetIdIfAllowed(appWidgetId, UserHandle.myUserId(), provider, null);
}
/**
@@ -783,7 +866,7 @@ public class AppWidgetManager {
* method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
* bind
*
- * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param appWidgetId The AppWidget id under which to bind the provider.
* @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
* provider for this AppWidget.
* @param options Bundle containing options for the AppWidget. See also
@@ -793,12 +876,52 @@ public class AppWidgetManager {
*/
public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider,
Bundle options) {
- if (mContext == null) {
+ if (mService == null) {
+ return false;
+ }
+ return bindAppWidgetIdIfAllowed(appWidgetId, UserHandle.myUserId(), provider, options);
+ }
+
+ /**
+ * Set the provider for a given appWidgetId if the caller has a permission.
+ * <p>
+ * <strong>Note:</strong> You need the {@link android.Manifest.permission#BIND_APPWIDGET}
+ * permission or the user must have enabled binding widgets always for your component.
+ * Should be used by apps that host widgets. If this method returns false, call {@link
+ * #ACTION_APPWIDGET_BIND} to request permission to bind.
+ * </p>
+ *
+ * @param appWidgetId The AppWidget id under which to bind the provider.
+ * @param user The user id in which the provider resides.
+ * @param provider The component name of the provider.
+ * @param options An optional Bundle containing options for the AppWidget.
+ *
+ * @return true if this component has permission to bind the AppWidget
+ */
+ public boolean bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user,
+ ComponentName provider, Bundle options) {
+ if (mService == null) {
+ return false;
+ }
+ return bindAppWidgetIdIfAllowed(appWidgetId, user.getIdentifier(), provider, options);
+ }
+
+ /**
+ * Query if a given package was granted permission by the user to bind app widgets
+ *
+ * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
+ *
+ * @param packageName The package for which the permission is being queried
+ * @param userId The user id of the user under which the package runs.
+ * @return true if the package was granted permission by the user to bind app widgets
+ * @hide
+ */
+ public boolean hasBindAppWidgetPermission(String packageName, int userId) {
+ if (mService == null) {
return false;
}
try {
- return sService.bindAppWidgetIdIfAllowed(mContext.getPackageName(), appWidgetId,
- provider, options, mContext.getUserId());
+ return mService.hasBindAppWidgetPermission(packageName, userId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -815,8 +938,11 @@ public class AppWidgetManager {
* @hide
*/
public boolean hasBindAppWidgetPermission(String packageName) {
+ if (mService == null) {
+ return false;
+ }
try {
- return sService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
+ return mService.hasBindAppWidgetPermission(packageName, UserHandle.myUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -828,13 +954,35 @@ public class AppWidgetManager {
*
* <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
*
- * @param provider The package whose permission is being changed
- * @param permission Whether to give the package permission to bind widgets
+ * @param packageName The package whose permission is being changed
+ * @param permission Whether to give the package permission to bind widgets
+ *
* @hide
*/
public void setBindAppWidgetPermission(String packageName, boolean permission) {
+ if (mService == null) {
+ return;
+ }
+ setBindAppWidgetPermission(packageName, UserHandle.myUserId(), permission);
+ }
+
+ /**
+ * Changes any user-granted permission for the given package to bind app widgets
+ *
+ * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
+ *
+ * @param packageName The package whose permission is being changed
+ * @param userId The user under which the package is running.
+ * @param permission Whether to give the package permission to bind widgets
+ *
+ * @hide
+ */
+ public void setBindAppWidgetPermission(String packageName, int userId, boolean permission) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.setBindAppWidgetPermission(packageName, permission, mContext.getUserId());
+ mService.setBindAppWidgetPermission(packageName, userId, permission);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -847,18 +995,20 @@ public class AppWidgetManager {
* The appWidgetId specified must already be bound to the calling AppWidgetHost via
* {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
*
+ * @param packageName The package from which the binding is requested.
* @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
* @param intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter.
* @param connection The callback interface to be notified when a connection is made or lost.
- * @param userHandle The user to bind to.
* @hide
*/
- public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
- UserHandle userHandle) {
+ public void bindRemoteViewsService(String packageName, int appWidgetId, Intent intent,
+ IBinder connection) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.bindRemoteViewsService(appWidgetId, intent, connection,
- userHandle.getIdentifier());
+ mService.bindRemoteViewsService(packageName, appWidgetId, intent, connection);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -871,15 +1021,18 @@ public class AppWidgetManager {
* The appWidgetId specified muse already be bound to the calling AppWidgetHost via
* {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
*
+ * @param packageName The package from which the binding is requested.
* @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
* @param intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter.
- * @param userHandle The user to unbind from.
* @hide
*/
- public void unbindRemoteViewsService(int appWidgetId, Intent intent, UserHandle userHandle) {
+ public void unbindRemoteViewsService(String packageName, int appWidgetId, Intent intent) {
+ if (mService == null) {
+ return;
+ }
try {
- sService.unbindRemoteViewsService(appWidgetId, intent, userHandle.getIdentifier());
+ mService.unbindRemoteViewsService(packageName, appWidgetId, intent);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -894,12 +1047,40 @@ public class AppWidgetManager {
* AppWidget provider to find appWidgetIds for.
*/
public int[] getAppWidgetIds(ComponentName provider) {
+ if (mService == null) {
+ return new int[0];
+ }
try {
- return sService.getAppWidgetIds(provider, mContext.getUserId());
+ return mService.getAppWidgetIds(provider);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
}
-}
+ private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
+ ComponentName provider, Bundle options) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.bindAppWidgetId(mPackageName, appWidgetId,
+ profileId, provider, options);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ private void convertSizesToPixels(AppWidgetProviderInfo info) {
+ // Converting complex to dp.
+ info.minWidth = TypedValue.complexToDimensionPixelSize(info.minWidth,
+ mDisplayMetrics);
+ info.minHeight = TypedValue.complexToDimensionPixelSize(info.minHeight,
+ mDisplayMetrics);
+ info.minResizeWidth = TypedValue.complexToDimensionPixelSize(info.minResizeWidth,
+ mDisplayMetrics);
+ info.minResizeHeight = TypedValue.complexToDimensionPixelSize(info.minResizeHeight,
+ mDisplayMetrics);
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 8b9c7f0..e4dad5a 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -16,9 +16,17 @@
package android.appwidget;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.content.ComponentName;
+import android.os.UserHandle;
+import android.os.UserManager;
/**
* Describes the meta data for an installed AppWidget provider. The fields in this class
@@ -145,21 +153,23 @@ public class AppWidgetProviderInfo implements Parcelable {
public ComponentName configure;
/**
- * The label to display to the user in the AppWidget picker. If not supplied in the
- * xml, the application label will be used.
+ * The label to display to the user in the AppWidget picker.
*
- * <p>This field corresponds to the <code>android:label</code> attribute in
- * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ * @deprecated Use {@link #loadLabel(android.content.pm.PackageManager)}.
*/
+ @Deprecated
public String label;
/**
- * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
+ * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
* xml, the application icon will be used.
*
* <p>This field corresponds to the <code>android:icon</code> attribute in
* the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ *
+ * @deprecated Use {@link #loadIcon(android.content.Context, int)}.
*/
+ @Deprecated
public int icon;
/**
@@ -176,7 +186,10 @@ public class AppWidgetProviderInfo implements Parcelable {
*
* <p>This field corresponds to the <code>android:previewImage</code> attribute in
* the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ *
+ * @deprecated User {@link #loadPreviewImage(android.content.Context, int)}.
*/
+ @Deprecated
public int previewImage;
/**
@@ -200,12 +213,17 @@ public class AppWidgetProviderInfo implements Parcelable {
*/
public int widgetCategory;
+ /** @hide */
+ public ActivityInfo providerInfo;
+
public AppWidgetProviderInfo() {
+
}
/**
* Unflatten the AppWidgetProviderInfo from a parcel.
*/
+ @SuppressWarnings("deprecation")
public AppWidgetProviderInfo(Parcel in) {
if (0 != in.readInt()) {
this.provider = new ComponentName(in);
@@ -226,8 +244,86 @@ public class AppWidgetProviderInfo implements Parcelable {
this.autoAdvanceViewId = in.readInt();
this.resizeMode = in.readInt();
this.widgetCategory = in.readInt();
+ this.providerInfo = in.readParcelable(null);
+ }
+
+ /**
+ * Loads the localized label to display to the user in the AppWidget picker.
+ *
+ * @param packageManager Package manager instance for loading resources.
+ * @return The label for the current locale.
+ */
+ public final String loadLabel(PackageManager packageManager) {
+ CharSequence label = providerInfo.loadLabel(packageManager);
+ if (label != null) {
+ return label.toString().trim();
+ }
+ return null;
+ }
+
+ /**
+ * Loads the icon to display for this AppWidget in the AppWidget picker. If not
+ * supplied in the xml, the application icon will be used. A client can optionally
+ * provide a desired density such as {@link android.util.DisplayMetrics#DENSITY_LOW}
+ * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
+ * provided, the density of the current display will be used.
+ * <p>
+ * The loaded icon corresponds to the <code>android:icon</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> If you care about widgets from different profiles, you
+ * should use this method to load the icon as the system will apply the correct
+ * badging when applicable, so the user knows which profile a widget comes from.
+ * </p>
+ *
+ * @param context Context for accessing resources.
+ * @param density The optional desired density as per
+ * {@link android.util.DisplayMetrics#densityDpi}.
+ * @return The potentially badged provider icon.
+ */
+ public final Drawable loadIcon(Context context, int density) {
+ return loadDrawable(context, density, providerInfo.getIconResource());
}
+ /**
+ * Loads a preview of what the AppWidget will look like after it's configured.
+ * If not supplied, the AppWidget's icon will be used. A client can optionally
+ * provide a desired deinsity such as {@link android.util.DisplayMetrics#DENSITY_LOW}
+ * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
+ * provided, the density of the current display will be used.
+ * <p>
+ * The loaded image corresponds to the <code>android:previewImage</code> attribute
+ * in the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> If you care about widgets from different profiles, you
+ * should use this method to load the preview image as the system will apply the
+ * correct badging when applicable, so the user knows which profile a previewed
+ * widget comes from.
+ * </p>
+ *
+ * @param context Context for accessing resources.
+ * @param density The optional desired density as per
+ * {@link android.util.DisplayMetrics#densityDpi}.
+ * @return The potentially badged widget preview image.
+ */
+ @SuppressWarnings("deprecation")
+ public final Drawable loadPreviewImage(Context context, int density) {
+ return loadDrawable(context, density, previewImage);
+ }
+
+ /**
+ * Gets the user profile in which the provider resides.
+ *
+ * @return The hosting user profile.
+ */
+ public final UserHandle getProfile() {
+ return new UserHandle(UserHandle.getUserId(providerInfo.applicationInfo.uid));
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
public void writeToParcel(android.os.Parcel out, int flags) {
if (this.provider != null) {
out.writeInt(1);
@@ -254,9 +350,11 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeInt(this.autoAdvanceViewId);
out.writeInt(this.resizeMode);
out.writeInt(this.widgetCategory);
+ out.writeParcelable(this.providerInfo, flags);
}
@Override
+ @SuppressWarnings("deprecation")
public AppWidgetProviderInfo clone() {
AppWidgetProviderInfo that = new AppWidgetProviderInfo();
that.provider = this.provider == null ? null : this.provider.clone();
@@ -273,7 +371,8 @@ public class AppWidgetProviderInfo implements Parcelable {
that.previewImage = this.previewImage;
that.autoAdvanceViewId = this.autoAdvanceViewId;
that.resizeMode = this.resizeMode;
- that.widgetCategory = this.widgetCategory;
+ that.widgetCategory = this.widgetCategory;
+ that.providerInfo = this.providerInfo;
return that;
}
@@ -281,6 +380,33 @@ public class AppWidgetProviderInfo implements Parcelable {
return 0;
}
+ private Drawable loadDrawable(Context context, int density, int resourceId) {
+ try {
+ Resources resources = context.getPackageManager().getResourcesForApplication(
+ providerInfo.applicationInfo);
+
+ final Drawable drawable;
+ if (resourceId > 0) {
+ if (density <= 0) {
+ density = context.getResources().getDisplayMetrics().densityDpi;
+ }
+ drawable = resources.getDrawableForDensity(resourceId, density);
+ } else {
+ drawable = providerInfo.loadIcon(context.getPackageManager());
+ }
+
+ if (drawable instanceof BitmapDrawable) {
+ UserManager userManager = (UserManager) context.getSystemService(
+ Context.USER_SERVICE);
+ return userManager.getBadgedDrawableForUser(drawable, getProfile());
+ }
+ } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
+ /* ignore */
+ }
+
+ return null;
+ }
+
/**
* Parcelable.Creator that instantiates AppWidgetProviderInfo objects
*/
@@ -299,6 +425,6 @@ public class AppWidgetProviderInfo implements Parcelable {
};
public String toString() {
- return "AppWidgetProviderInfo(provider=" + this.provider + ")";
+ return "AppWidgetProviderInfo(" + getProfile() + '/' + provider + ')';
}
}