summaryrefslogtreecommitdiffstats
path: root/core/java/android/appwidget
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-11 12:11:56 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-11 12:11:56 -0700
commitc39a6e0c51e182338deb8b63d07933b585134929 (patch)
treee55fc5bd38b1eb8fb4851a0fe1cc264a7fe2f245 /core/java/android/appwidget
parentb2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54 (diff)
downloadframeworks_base-c39a6e0c51e182338deb8b63d07933b585134929.zip
frameworks_base-c39a6e0c51e182338deb8b63d07933b585134929.tar.gz
frameworks_base-c39a6e0c51e182338deb8b63d07933b585134929.tar.bz2
auto import from //branches/cupcake/...@137873
Diffstat (limited to 'core/java/android/appwidget')
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java248
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java312
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java320
-rwxr-xr-xcore/java/android/appwidget/AppWidgetProvider.java154
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.aidl19
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java168
-rw-r--r--core/java/android/appwidget/package.html136
7 files changed, 1357 insertions, 0 deletions
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
new file mode 100644
index 0000000..10c2b02
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -0,0 +1,248 @@
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
+
+/**
+ * AppWidgetHost provides the interaction with the AppWidget service for apps,
+ * like the home screen, that want to embed AppWidgets in their UI.
+ */
+public class AppWidgetHost {
+
+ static final int HANDLE_UPDATE = 1;
+ static final int HANDLE_PROVIDER_CHANGED = 2;
+
+ static Object sServiceLock = new Object();
+ static IAppWidgetService sService;
+
+ Context mContext;
+ String mPackageName;
+
+ class Callbacks extends IAppWidgetHost.Stub {
+ public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
+ msg.arg1 = appWidgetId;
+ msg.obj = views;
+ msg.sendToTarget();
+ }
+
+ public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+ Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
+ msg.arg1 = appWidgetId;
+ msg.obj = info;
+ msg.sendToTarget();
+ }
+ }
+
+ class UpdateHandler extends Handler {
+ public UpdateHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case HANDLE_UPDATE: {
+ updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
+ break;
+ }
+ case HANDLE_PROVIDER_CHANGED: {
+ onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
+ break;
+ }
+ }
+ }
+ }
+
+ Handler mHandler;
+
+ int mHostId;
+ Callbacks mCallbacks = new Callbacks();
+ HashMap<Integer,AppWidgetHostView> mViews = new HashMap();
+
+ public AppWidgetHost(Context context, int hostId) {
+ mContext = context;
+ mHostId = hostId;
+ mHandler = new UpdateHandler(context.getMainLooper());
+ synchronized (sServiceLock) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ sService = IAppWidgetService.Stub.asInterface(b);
+ }
+ }
+ }
+
+ /**
+ * Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
+ * becomes visible, i.e. from onStart() in your Activity.
+ */
+ public void startListening() {
+ int[] updatedIds = null;
+ ArrayList<RemoteViews> updatedViews = new ArrayList();
+
+ try {
+ if (mPackageName == null) {
+ mPackageName = mContext.getPackageName();
+ }
+ 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++) {
+ updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+ }
+ }
+
+ /**
+ * Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is
+ * no longer visible, i.e. from onStop() in your Activity.
+ */
+ public void stopListening() {
+ try {
+ sService.stopListening(mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get a appWidgetId for a host in the calling process.
+ *
+ * @return a appWidgetId
+ */
+ public int allocateAppWidgetId() {
+ try {
+ if (mPackageName == null) {
+ mPackageName = mContext.getPackageName();
+ }
+ return sService.allocateAppWidgetId(mPackageName, mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Stop listening to changes for this AppWidget.
+ */
+ public void deleteAppWidgetId(int appWidgetId) {
+ synchronized (mViews) {
+ mViews.remove(appWidgetId);
+ try {
+ sService.deleteAppWidgetId(appWidgetId);
+ }
+ 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>
+ * <li>Call this to have the AppWidget manager release all resources associated with your
+ * host. Any future calls about this host will cause the records to be re-allocated.</li>
+ * </ul>
+ */
+ public void deleteHost() {
+ try {
+ sService.deleteHost(mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Remove all records about all hosts for your package.
+ * <ul>
+ * <li>Call this when initializing your database, as it might be because of a data wipe.</li>
+ * <li>Call this to have the AppWidget manager release all resources associated with your
+ * host. Any future calls about this host will cause the records to be re-allocated.</li>
+ * </ul>
+ */
+ public static void deleteAllHosts() {
+ try {
+ sService.deleteAllHosts();
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ public final AppWidgetHostView createView(Context context, int appWidgetId,
+ AppWidgetProviderInfo appWidget) {
+ AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
+ view.setAppWidget(appWidgetId, appWidget);
+ synchronized (mViews) {
+ mViews.put(appWidgetId, view);
+ }
+ RemoteViews views = null;
+ try {
+ views = sService.getAppWidgetViews(appWidgetId);
+ } catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ view.updateAppWidget(views);
+ return view;
+ }
+
+ /**
+ * Called to create the AppWidgetHostView. Override to return a custom subclass if you
+ * need it. {@more}
+ */
+ protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+ AppWidgetProviderInfo appWidget) {
+ return new AppWidgetHostView(context);
+ }
+
+ /**
+ * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
+ */
+ protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+ }
+
+ void updateAppWidgetView(int appWidgetId, RemoteViews views) {
+ AppWidgetHostView v;
+ synchronized (mViews) {
+ v = mViews.get(appWidgetId);
+ }
+ if (v != null) {
+ v.updateAppWidget(views);
+ }
+ }
+}
+
+
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
new file mode 100644
index 0000000..be0f96e
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Config;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+/**
+ * Provides the glue to show AppWidget views. This class offers automatic animation
+ * between updates, and will try recycling old views for each incoming
+ * {@link RemoteViews}.
+ */
+public class AppWidgetHostView extends FrameLayout {
+ static final String TAG = "AppWidgetHostView";
+ static final boolean LOGD = false;
+ static final boolean CROSSFADE = false;
+
+ static final int VIEW_MODE_NOINIT = 0;
+ static final int VIEW_MODE_CONTENT = 1;
+ static final int VIEW_MODE_ERROR = 2;
+ static final int VIEW_MODE_DEFAULT = 3;
+
+ static final int FADE_DURATION = 1000;
+
+ // When we're inflating the initialLayout for a AppWidget, we only allow
+ // views that are allowed in RemoteViews.
+ static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
+ public boolean onLoadClass(Class clazz) {
+ return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
+ }
+ };
+
+ Context mContext;
+
+ int mAppWidgetId;
+ AppWidgetProviderInfo mInfo;
+ View mView;
+ int mViewMode = VIEW_MODE_NOINIT;
+ int mLayoutId = -1;
+ long mFadeStartTime = -1;
+ Bitmap mOld;
+ Paint mOldPaint = new Paint();
+
+ /**
+ * Create a host view. Uses default fade animations.
+ */
+ public AppWidgetHostView(Context context) {
+ this(context, android.R.anim.fade_in, android.R.anim.fade_out);
+ }
+
+ /**
+ * Create a host view. Uses specified animations when pushing
+ * {@link #updateAppWidget(RemoteViews)}.
+ *
+ * @param animationIn Resource ID of in animation to use
+ * @param animationOut Resource ID of out animation to use
+ */
+ public AppWidgetHostView(Context context, int animationIn, int animationOut) {
+ super(context);
+ mContext = context;
+ }
+
+ /**
+ * Set the AppWidget that will be displayed by this view.
+ */
+ public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+ mAppWidgetId = appWidgetId;
+ mInfo = info;
+ }
+
+ public int getAppWidgetId() {
+ return mAppWidgetId;
+ }
+
+ public AppWidgetProviderInfo getAppWidgetInfo() {
+ return mInfo;
+ }
+
+ /**
+ * Process a set of {@link RemoteViews} coming in as an update from the
+ * AppWidget provider. Will animate into these new views as needed.
+ */
+ public void updateAppWidget(RemoteViews remoteViews) {
+ if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
+
+ boolean recycled = false;
+ View content = null;
+ Exception exception = null;
+
+ // Capture the old view into a bitmap so we can do the crossfade.
+ if (CROSSFADE) {
+ if (mFadeStartTime < 0) {
+ if (mView != null) {
+ final int width = mView.getWidth();
+ final int height = mView.getHeight();
+ try {
+ mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ } catch (OutOfMemoryError e) {
+ // we just won't do the fade
+ mOld = null;
+ }
+ if (mOld != null) {
+ //mView.drawIntoBitmap(mOld);
+ }
+ }
+ }
+ }
+
+ if (remoteViews == null) {
+ if (mViewMode == VIEW_MODE_DEFAULT) {
+ // We've already done this -- nothing to do.
+ return;
+ }
+ content = getDefaultView();
+ mLayoutId = -1;
+ mViewMode = VIEW_MODE_DEFAULT;
+ } else {
+ int layoutId = remoteViews.getLayoutId();
+
+ // If our stale view has been prepared to match active, and the new
+ // layout matches, try recycling it
+ if (content == null && layoutId == mLayoutId) {
+ try {
+ remoteViews.reapply(mContext, mView);
+ content = mView;
+ recycled = true;
+ if (LOGD) Log.d(TAG, "was able to recycled existing layout");
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+ }
+
+ // Try normal RemoteView inflation
+ if (content == null) {
+ try {
+ content = remoteViews.apply(mContext, this);
+ if (LOGD) Log.d(TAG, "had to inflate new layout");
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+ }
+
+ mLayoutId = layoutId;
+ mViewMode = VIEW_MODE_CONTENT;
+ }
+
+ if (content == null) {
+ if (mViewMode == VIEW_MODE_ERROR) {
+ // We've already done this -- nothing to do.
+ return ;
+ }
+ Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception);
+ content = getErrorView();
+ mViewMode = VIEW_MODE_ERROR;
+ }
+
+ if (!recycled) {
+ prepareView(content);
+ addView(content);
+ }
+
+ if (mView != content) {
+ removeView(mView);
+ mView = content;
+ }
+
+ if (CROSSFADE) {
+ if (mFadeStartTime < 0) {
+ // if there is already an animation in progress, don't do anything --
+ // the new view will pop in on top of the old one during the cross fade,
+ // and that looks okay.
+ mFadeStartTime = SystemClock.uptimeMillis();
+ invalidate();
+ }
+ }
+ }
+
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (CROSSFADE) {
+ int alpha;
+ int l = child.getLeft();
+ int t = child.getTop();
+ if (mFadeStartTime > 0) {
+ alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION);
+ if (alpha > 255) {
+ alpha = 255;
+ }
+ Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t
+ + " w=" + child.getWidth());
+ if (alpha != 255 && mOld != null) {
+ mOldPaint.setAlpha(255-alpha);
+ //canvas.drawBitmap(mOld, l, t, mOldPaint);
+ }
+ } else {
+ alpha = 255;
+ }
+ int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ boolean rv = super.drawChild(canvas, child, drawingTime);
+ canvas.restoreToCount(restoreTo);
+ if (alpha < 255) {
+ invalidate();
+ } else {
+ mFadeStartTime = -1;
+ if (mOld != null) {
+ mOld.recycle();
+ mOld = null;
+ }
+ }
+ return rv;
+ } else {
+ return super.drawChild(canvas, child, drawingTime);
+ }
+ }
+
+ /**
+ * Prepare the given view to be shown. This might include adjusting
+ * {@link FrameLayout.LayoutParams} before inserting.
+ */
+ protected void prepareView(View view) {
+ // Take requested dimensions from parent, but apply default gravity.
+ ViewGroup.LayoutParams requested = view.getLayoutParams();
+ if (requested == null) {
+ requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.FILL_PARENT);
+ }
+
+ FrameLayout.LayoutParams params =
+ new FrameLayout.LayoutParams(requested.width, requested.height);
+ params.gravity = Gravity.CENTER;
+ view.setLayoutParams(params);
+ }
+
+ /**
+ * Inflate and return the default layout requested by AppWidget provider.
+ */
+ protected View getDefaultView() {
+ View defaultView = null;
+ Exception exception = null;
+
+ try {
+ if (mInfo != null) {
+ Context theirContext = mContext.createPackageContext(
+ mInfo.provider.getPackageName(), 0 /* no flags */);
+ LayoutInflater inflater = (LayoutInflater)
+ theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater = inflater.cloneInContext(theirContext);
+ inflater.setFilter(sInflaterFilter);
+ defaultView = inflater.inflate(mInfo.initialLayout, this, false);
+ } else {
+ Log.w(TAG, "can't inflate defaultView because mInfo is missing");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ exception = e;
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+
+ if (exception != null && LOGD) {
+ Log.w(TAG, "Error inflating AppWidget " + mInfo, exception);
+ }
+
+ if (defaultView == null) {
+ if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error");
+ defaultView = getErrorView();
+ }
+
+ return defaultView;
+ }
+
+ /**
+ * Inflate and return a view that represents an error state.
+ */
+ protected View getErrorView() {
+ TextView tv = new TextView(mContext);
+ tv.setText(com.android.internal.R.string.gadget_host_error_inflating);
+ // TODO: get this color from somewhere.
+ tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
+ return tv;
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
new file mode 100644
index 0000000..3b10ed2
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.android.internal.appwidget.IAppWidgetService;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.WeakHashMap;
+
+/**
+ * Updates AppWidget state; gets information about installed AppWidget providers and other
+ * AppWidget related state.
+ */
+public class AppWidgetManager {
+ static final String TAG = "AppWidgetManager";
+
+ /**
+ * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
+ * The AppWidget picker activity will be launched.
+ * <p>
+ * You must supply the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
+ * once the user has selected one.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>
+ * The system will respond with an onActivityResult call with the following extras in
+ * the intent:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>The appWidgetId that you supplied in the original intent.</td>
+ * </tr>
+ * </table>
+ * <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.
+ *
+ * @see #ACTION_APPWIDGET_CONFIGURE
+ */
+ public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
+
+ /**
+ * 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}.
+ *
+ * <p>
+ * The intent will contain the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>The appWidgetId to configure.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>If you return {@link android.app.Activity#RESULT_OK} using
+ * {@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.
+ */
+ public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
+
+ /**
+ * An intent extra that contains one appWidgetId.
+ * <p>
+ * The value will be an int that can be retrieved like this:
+ * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
+ */
+ public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
+
+ /**
+ * An intent extra that contains multiple appWidgetIds.
+ * <p>
+ * The value will be an int array that can be retrieved like this:
+ * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
+ */
+ public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
+
+ /**
+ * A sentiel value that the AppWidget manager will never return as a appWidgetId.
+ */
+ public static final int INVALID_APPWIDGET_ID = 0;
+
+ /**
+ * Sent when it is time to update your AppWidget.
+ *
+ * <p>This may be sent in response to a new instance for this AppWidget provider having
+ * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
+ * having lapsed, or the system booting.
+ *
+ * <p>
+ * The intent will contain the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_IDS}</td>
+ * <td>The appWidgetIds to update. This may be all of the AppWidgets created for this
+ * provider, or just a subset. The system tries to send updates for as few AppWidget
+ * instances as possible.</td>
+ * </tr>
+ * </table>
+ *
+ * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
+ */
+ public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
+
+ /**
+ * Sent when an instance of an AppWidget is deleted from its host.
+ *
+ * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
+ */
+ 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.
+ *
+ * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
+ */
+ public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
+
+ /**
+ * Sent when an instance of an AppWidget is added to a host for the first time.
+ * This broadcast is sent at boot time if there is a AppWidgetHost installed with
+ * an instance for this provider.
+ *
+ * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
+ */
+ public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
+
+ /**
+ * Field for the manifest meta-data tag.
+ *
+ * @see AppWidgetProviderInfo
+ */
+ public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
+
+ static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
+ static IAppWidgetService sService;
+
+ Context mContext;
+
+ /**
+ * 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(result));
+ }
+ return result;
+ }
+ }
+
+ private AppWidgetManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Set the RemoteViews to use for the specified appWidgetIds.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @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) {
+ try {
+ sService.updateAppWidgetIds(appWidgetIds, views);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Set the RemoteViews to use for the specified appWidgetId.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param views The RemoteViews object to show.
+ */
+ public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ updateAppWidget(new int[] { appWidgetId }, views);
+ }
+
+ /**
+ * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param provider The {@link ComponentName} for the {@link
+ * android.content.BroadcastReceiver BroadcastReceiver} provider
+ * for your AppWidget.
+ * @param views The RemoteViews object to show.
+ */
+ public void updateAppWidget(ComponentName provider, RemoteViews views) {
+ try {
+ sService.updateAppWidgetProvider(provider, views);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Return a list of the AppWidget providers that are currently installed.
+ */
+ public List<AppWidgetProviderInfo> getInstalledProviders() {
+ try {
+ return sService.getInstalledProviders();
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get the available info about the AppWidget.
+ *
+ * @return A appWidgetId. If the appWidgetId has not been bound to a provider yet, or
+ * you don't have access to that appWidgetId, null is returned.
+ */
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ try {
+ return sService.getAppWidgetInfo(appWidgetId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Set the component for a given appWidgetId.
+ *
+ * <p class="note">You need the APPWIDGET_LIST permission. This method is to be used by the
+ * AppWidget picker.
+ *
+ * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
+ * provider for this AppWidget.
+ */
+ public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
+ try {
+ sService.bindAppWidgetId(appWidgetId, provider);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get the list of appWidgetIds that have been bound to the given AppWidget
+ * provider.
+ *
+ * @param provider The {@link android.content.BroadcastReceiver} that is the
+ * AppWidget provider to find appWidgetIds for.
+ */
+ public int[] getAppWidgetIds(ComponentName provider) {
+ try {
+ return sService.getAppWidgetIds(provider);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+}
+
diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java
new file mode 100755
index 0000000..f70de9c
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetProvider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * A conveience class to aid in implementing an AppWidget provider.
+ * Everything you can do with AppWidgetProvider, you can do with a regular {@link BroadcastReceiver}.
+ * AppWidgetProvider merely parses the relevant fields out of the Intent that is received in
+ * {@link #onReceive(Context,Intent) onReceive(Context,Intent)}, and calls hook methods
+ * with the received extras.
+ *
+ * <p>Extend this class and override one or more of the {@link #onUpdate}, {@link #onDeleted},
+ * {@link #onEnabled} or {@link #onDisabled} methods to implement your own AppWidget functionality.
+ *
+ * <h3>Sample Code</h3>
+ * For an example of how to write a AppWidget provider, see the
+ * <a href="{@toroot}reference/android/appwidget/package-descr.html#providers">android.appwidget
+ * package overview</a>.
+ */
+public class AppWidgetProvider extends BroadcastReceiver {
+ /**
+ * Constructor to initialize AppWidgetProvider.
+ */
+ public AppWidgetProvider() {
+ }
+
+ /**
+ * Implements {@link BroadcastReceiver#onReceive} to dispatch calls to the various
+ * other methods on AppWidgetProvider.
+ *
+ * @param context The Context in which the receiver is running.
+ * @param intent The Intent being received.
+ */
+ // BEGIN_INCLUDE(onReceive)
+ public void onReceive(Context context, Intent intent) {
+ // Protect against rogue update broadcasts (not really a security issue,
+ // just filter bad broacasts out so subclasses are less likely to crash).
+ String action = intent.getAction();
+ if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (appWidgetIds != null && appWidgetIds.length > 0) {
+ this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
+ }
+ }
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (appWidgetIds != null && appWidgetIds.length > 0) {
+ this.onDeleted(context, appWidgetIds);
+ }
+ }
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
+ this.onEnabled(context);
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
+ this.onDisabled(context);
+ }
+ }
+ // END_INCLUDE(onReceive)
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcast when
+ * this AppWidget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews}
+ * for a set of AppWidgets. Override this method to implement your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ * @param appWidgetManager A {@link AppWidgetManager} object you can call {@link
+ * AppWidgetManager#updateAppWidget} on.
+ * @param appWidgetIds The appWidgetIds for which an update is needed. Note that this
+ * may be all of the AppWidget instances for this provider, or just
+ * a subset of them.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
+ */
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DELETED} broadcast when
+ * one or more AppWidget instances have been deleted. Override this method to implement
+ * your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ * @param appWidgetIds The appWidgetIds that have been deleted from their host.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_DELETED
+ */
+ public void onDeleted(Context context, int[] appWidgetIds) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_ENABLED} broadcast when
+ * the a AppWidget for this provider is instantiated. Override this method to implement your
+ * own AppWidget functionality.
+ *
+ * {@more}
+ * When the last AppWidget for this provider is deleted,
+ * {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} is sent by the AppWidget manager, and
+ * {@link #onDisabled} is called. If after that, an AppWidget for this provider is created
+ * again, onEnabled() will be called again.
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_ENABLED
+ */
+ public void onEnabled(Context context) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} broadcast, which
+ * is sent when the last AppWidget instance for this provider is deleted. Override this method
+ * to implement your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_DISABLED
+ */
+ public void onDisabled(Context context) {
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.aidl b/core/java/android/appwidget/AppWidgetProviderInfo.aidl
new file mode 100644
index 0000000..82b3ada
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+parcelable AppWidgetProviderInfo;
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
new file mode 100644
index 0000000..8530c35
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.content.ComponentName;
+
+/**
+ * Describes the meta data for an installed AppWidget provider. The fields in this class
+ * correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
+ */
+public class AppWidgetProviderInfo implements Parcelable {
+ /**
+ * Identity of this AppWidget component. This component should be a {@link
+ * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
+ * {@link android.appwidget as described in the AppWidget package documentation}.
+ *
+ * <p>This field corresponds to the <code>android:name</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ */
+ public ComponentName provider;
+
+ /**
+ * Minimum width of the AppWidget, in dp.
+ *
+ * <p>This field corresponds to the <code>android:minWidth</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int minWidth;
+
+ /**
+ * Minimum height of the AppWidget, in dp.
+ *
+ * <p>This field corresponds to the <code>android:minHeight</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int minHeight;
+
+ /**
+ * How often, in milliseconds, that this AppWidget wants to be updated.
+ * The AppWidget manager may place a limit on how often a AppWidget is updated.
+ *
+ * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int updatePeriodMillis;
+
+ /**
+ * The resource id of the initial layout for this AppWidget. This should be
+ * displayed until the RemoteViews for the AppWidget is available.
+ *
+ * <p>This field corresponds to the <code>android:initialLayout</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int initialLayout;
+
+ /**
+ * The activity to launch that will configure the AppWidget.
+ *
+ * <p>This class name of field corresponds to the <code>android:configure</code> attribute in
+ * the AppWidget meta-data file. The package name always corresponds to the package containing
+ * the AppWidget provider.
+ */
+ 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.
+ *
+ * <p>This field corresponds to the <code>android:label</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ */
+ public String label;
+
+ /**
+ * 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.
+ */
+ public int icon;
+
+ public AppWidgetProviderInfo() {
+ }
+
+ /**
+ * Unflatten the AppWidgetProviderInfo from a parcel.
+ */
+ public AppWidgetProviderInfo(Parcel in) {
+ if (0 != in.readInt()) {
+ this.provider = new ComponentName(in);
+ }
+ this.minWidth = in.readInt();
+ this.minHeight = in.readInt();
+ this.updatePeriodMillis = in.readInt();
+ this.initialLayout = in.readInt();
+ if (0 != in.readInt()) {
+ this.configure = new ComponentName(in);
+ }
+ this.label = in.readString();
+ this.icon = in.readInt();
+ }
+
+
+ public void writeToParcel(android.os.Parcel out, int flags) {
+ if (this.provider != null) {
+ out.writeInt(1);
+ this.provider.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeInt(this.minWidth);
+ out.writeInt(this.minHeight);
+ out.writeInt(this.updatePeriodMillis);
+ out.writeInt(this.initialLayout);
+ if (this.configure != null) {
+ out.writeInt(1);
+ this.configure.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeString(this.label);
+ out.writeInt(this.icon);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Parcelable.Creator that instantiates AppWidgetProviderInfo objects
+ */
+ public static final Parcelable.Creator<AppWidgetProviderInfo> CREATOR
+ = new Parcelable.Creator<AppWidgetProviderInfo>()
+ {
+ public AppWidgetProviderInfo createFromParcel(Parcel parcel)
+ {
+ return new AppWidgetProviderInfo(parcel);
+ }
+
+ public AppWidgetProviderInfo[] newArray(int size)
+ {
+ return new AppWidgetProviderInfo[size];
+ }
+ };
+
+ public String toString() {
+ return "AppWidgetProviderInfo(provider=" + this.provider + ")";
+ }
+}
+
+
diff --git a/core/java/android/appwidget/package.html b/core/java/android/appwidget/package.html
new file mode 100644
index 0000000..b6cd9c7
--- /dev/null
+++ b/core/java/android/appwidget/package.html
@@ -0,0 +1,136 @@
+<body>
+<p>Android allows applications to publish views to be embedded in other applications. These
+views are called widgets, and are published by "AppWidget providers." The component that can
+contain widgets is called a "AppWidget host."
+</p>
+<h3><a href="package-descr.html#providers">AppWidget Providers</a></h3>
+<ul>
+ <li><a href="package-descr.html#provider_manifest">Declaring a widget in the AndroidManifest</a></li>
+ <li><a href="package-descr.html#provider_meta_data">Adding the AppWidgetProviderInfo meta-data</a></li>
+ <li><a href="package-descr.html#provider_AppWidgetProvider">Using the AppWidgetProvider class</a></li>
+ <li><a href="package-descr.html#provider_configuration">AppWidget Configuration UI</a></li>
+ <li><a href="package-descr.html#provider_broadcasts">AppWidget Broadcast Intents</a></li>
+</ul>
+<h3><a href="package-descr.html#">AppWidget Hosts</a></h3>
+
+
+{@more}
+
+
+<h2><a name="providers"></a>AppWidget Providers</h2>
+<p>
+Any application can publish widgets. All an application needs to do to publish a widget is
+to have a {@link android.content.BroadcastReceiver} that receives the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} intent,
+and provide some meta-data about the widget. Android provides the
+{@link android.appwidget.AppWidgetProvider} class, which extends BroadcastReceiver, as a convenience
+class to aid in handling the broadcasts.
+
+<h3><a name="provider_manifest"></a>Declaring a widget in the AndroidManifest</h3>
+
+<p>
+First, declare the {@link android.content.BroadcastReceiver} in your application's
+<code>AndroidManifest.xml</code> file.
+
+{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml AppWidgetProvider}
+
+<p>
+The <b><code>&lt;receiver&gt;</b> element has the following attributes:
+<ul>
+ <li><b><code>android:name</code> -</b> which specifies the
+ {@link android.content.BroadcastReceiver} or {@link android.appwidget.AppWidgetProvider}
+ class.</li>
+ <li><b><code>android:label</code> -</b> which specifies the string resource that
+ will be shown by the widget picker as the label.</li>
+ <li><b><code>android:icon</code> -</b> which specifies the drawable resource that
+ will be shown by the widget picker as the icon.</li>
+</ul>
+
+<p>
+The <b><code>&lt;intent-filter&gt;</b> element tells the {@link android.content.pm.PackageManager}
+that this {@link android.content.BroadcastReceiver} receives the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
+The widget manager will send other broadcasts directly to your widget provider as required.
+It is only necessary to explicitly declare that you accept the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
+
+<p>
+The <b><code>&lt;meta-data&gt;</code></b> element tells the widget manager which xml resource to
+read to find the {@link android.appwidget.AppWidgetProviderInfo} for your widget provider. It has the following
+attributes:
+<ul>
+ <li><b><code>android:name="android.appwidget.provider"</code> -</b> identifies this meta-data
+ as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
+ <li><b><code>android:resource</code> -</b> is the xml resource to use as that descriptor.</li>
+</ul>
+
+
+<h3><a name="provider_meta_data"></a>Adding the {@link android.appwidget.AppWidgetProviderInfo AppWidgetProviderInfo} meta-data</h3>
+
+<p>
+For a widget, the values in the {@link android.appwidget.AppWidgetProviderInfo} structure are supplied
+in an XML resource. In the example above, the xml resource is referenced with
+<code>android:resource="@xml/appwidget_info"</code>. That XML file would go in your application's
+directory at <code>res/xml/appwidget_info.xml</code>. Here is a simple example.
+
+{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml AppWidgetProviderInfo}
+
+<p>
+The attributes are as documented in the {@link android.appwidget.AppWidgetProviderInfo GagetInfo} class. (86400000 milliseconds means once per day)
+
+
+<h3><a name="provider_AppWidgetProvider"></a>Using the {@link android.appwidget.AppWidgetProvider AppWidgetProvider} class</h3>
+
+<p>The AppWidgetProvider class is the easiest way to handle the widget provider intent broadcasts.
+See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java</code>
+sample class in ApiDemos for an example.
+
+<p class="note">Keep in mind that since the the AppWidgetProvider is a BroadcastReceiver,
+your process is not guaranteed to keep running after the callback methods return. See
+<a href="../../../guide/topics/fundamentals.html#broadlife">Application Fundamentals &gt;
+Broadcast Receiver Lifecycle</a> for more information.
+
+
+
+<h3><a name="provider_configuration"></a>AppWidget Configuration UI</h3>
+
+<p>
+Widget hosts have the ability to start a configuration activity when a widget is instantiated.
+The activity should be declared as normal in AndroidManifest.xml, and it should be listed in
+the AppWidgetProviderInfo XML file in the <code>android:configure</code> attribute.
+
+<p>The activity you specified will be launched with the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE} action. See the documentation for that
+action for more info.
+
+<p>See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java</code>
+sample class in ApiDemos for an example.
+
+
+
+<h3><a name="providers_broadcasts"></a>AppWidget Broadcast Intents</h3>
+
+<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like
+to receive the widget broadcasts directly, you can. The four intents you need to care about are:
+<ul>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li>
+</ul>
+
+<p>By way of example, the implementation of
+{@link android.appwidget.AppWidgetProvider#onReceive} is quite simple:</p>
+
+{@sample frameworks/base/core/java/android/appwidget/AppWidgetProvider.java onReceive}
+
+
+<h2>AppWidget Hosts</h3>
+<p>Widget hosts are the containers in which widgets can be placed. Most of the look and feel
+details are left up to the widget hosts. For example, the home screen has one way of viewing
+widgets, but the lock screen could also contain widgets, and it would have a different way of
+adding, removing and otherwise managing widgets.</p>
+<p>For more information on implementing your own widget host, see the
+{@link android.appwidget.AppWidgetHost AppWidgetHost} class.</p>
+</body>
+