AppWidgetManager.java revision d2671e1fcf1d7f1b8e25a2615d514cf3c26b6a9c
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.appwidget;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.os.IBinder;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24import android.util.DisplayMetrics;
25import android.util.Log;
26import android.util.TypedValue;
27import android.widget.RemoteViews;
28
29import com.android.internal.appwidget.IAppWidgetService;
30
31import java.lang.ref.WeakReference;
32import java.util.List;
33import java.util.WeakHashMap;
34
35/**
36 * Updates AppWidget state; gets information about installed AppWidget providers and other
37 * AppWidget related state.
38 */
39public class AppWidgetManager {
40    static final String TAG = "AppWidgetManager";
41
42    /**
43     * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
44     * The AppWidget picker activity will be launched.
45     * <p>
46     * You must supply the following extras:
47     * <table>
48     *   <tr>
49     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
50     *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
51     *         once the user has selected one.</td>
52     *  </tr>
53     * </table>
54     *
55     * <p>
56     * The system will respond with an onActivityResult call with the following extras in
57     * the intent:
58     * <table>
59     *   <tr>
60     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
61     *     <td>The appWidgetId that you supplied in the original intent.</td>
62     *  </tr>
63     * </table>
64     * <p>
65     * When you receive the result from the AppWidget pick activity, if the resultCode is
66     * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected.  You should then
67     * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
68     * activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
69     * the appWidgetId.
70     *
71     * @see #ACTION_APPWIDGET_CONFIGURE
72     */
73    public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
74
75    /**
76     * Sent when it is time to configure your AppWidget while it is being added to a host.
77     * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
78     * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
79     *
80     * <p>
81     * The intent will contain the following extras:
82     * <table>
83     *   <tr>
84     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
85     *     <td>The appWidgetId to configure.</td>
86     *  </tr>
87     * </table>
88     *
89     * <p>If you return {@link android.app.Activity#RESULT_OK} using
90     * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
91     * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
92     * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
93     * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
94     */
95    public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
96
97    /**
98     * An intent extra that contains one appWidgetId.
99     * <p>
100     * The value will be an int that can be retrieved like this:
101     * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
102     */
103    public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
104
105    /**
106     * An intent extra that contains multiple appWidgetIds.
107     * <p>
108     * The value will be an int array that can be retrieved like this:
109     * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
110     */
111    public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
112
113    /**
114     * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
115     * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
116     * installed.  (This is how the launcher shows the search widget).
117     */
118    public static final String EXTRA_CUSTOM_INFO = "customInfo";
119
120    /**
121     * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
122     * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
123     * installed.  It will be added to the extras object on the {@link android.content.Intent}
124     * that is returned from the picker activity.
125     *
126     * {@more}
127     */
128    public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
129
130    /**
131     * A sentiel value that the AppWidget manager will never return as a appWidgetId.
132     */
133    public static final int INVALID_APPWIDGET_ID = 0;
134
135    /**
136     * Sent when it is time to update your AppWidget.
137     *
138     * <p>This may be sent in response to a new instance for this AppWidget provider having
139     * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
140     * having lapsed, or the system booting.
141     *
142     * <p>
143     * The intent will contain the following extras:
144     * <table>
145     *   <tr>
146     *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
147     *     <td>The appWidgetIds to update.  This may be all of the AppWidgets created for this
148     *     provider, or just a subset.  The system tries to send updates for as few AppWidget
149     *     instances as possible.</td>
150     *  </tr>
151     * </table>
152     *
153     * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
154     */
155    public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
156
157    /**
158     * Sent when an instance of an AppWidget is deleted from its host.
159     *
160     * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
161     */
162    public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
163
164    /**
165     * Sent when an instance of an AppWidget is removed from the last host.
166     *
167     * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
168     */
169    public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
170
171    /**
172     * Sent when an instance of an AppWidget is added to a host for the first time.
173     * This broadcast is sent at boot time if there is a AppWidgetHost installed with
174     * an instance for this provider.
175     *
176     * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
177     */
178    public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
179
180    /**
181     * Field for the manifest meta-data tag.
182     *
183     * @see AppWidgetProviderInfo
184     */
185    public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
186
187    /**
188     * Field for the manifest meta-data tag used to indicate any previous name for the
189     * app widget receiver.
190     *
191     * @see AppWidgetProviderInfo
192     *
193     * @hide Pending API approval
194     */
195    public static final String META_DATA_APPWIDGET_OLD_NAME = "android.appwidget.oldName";
196
197    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
198    static IAppWidgetService sService;
199
200    Context mContext;
201
202    private DisplayMetrics mDisplayMetrics;
203
204    /**
205     * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
206     * Context} object.
207     */
208    public static AppWidgetManager getInstance(Context context) {
209        synchronized (sManagerCache) {
210            if (sService == null) {
211                IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
212                sService = IAppWidgetService.Stub.asInterface(b);
213            }
214
215            WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
216            AppWidgetManager result = null;
217            if (ref != null) {
218                result = ref.get();
219            }
220            if (result == null) {
221                result = new AppWidgetManager(context);
222                sManagerCache.put(context, new WeakReference(result));
223            }
224            return result;
225        }
226    }
227
228    private AppWidgetManager(Context context) {
229        mContext = context;
230        mDisplayMetrics = context.getResources().getDisplayMetrics();
231    }
232
233    /**
234     * Set the RemoteViews to use for the specified appWidgetIds.
235     *
236     * <p>
237     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
238     * and outside of the handler.
239     * This method will only work when called from the uid that owns the AppWidget provider.
240     *
241     * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
242     * @param views         The RemoteViews object to show.
243     */
244    public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
245        try {
246            sService.updateAppWidgetIds(appWidgetIds, views);
247        }
248        catch (RemoteException e) {
249            throw new RuntimeException("system server dead?", e);
250        }
251    }
252
253    /**
254     * Set the RemoteViews to use for the specified appWidgetId.
255     *
256     * <p>
257     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
258     * and outside of the handler.
259     * This method will only work when called from the uid that owns the AppWidget provider.
260     *
261     * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
262     * @param views         The RemoteViews object to show.
263     */
264    public void updateAppWidget(int appWidgetId, RemoteViews views) {
265        updateAppWidget(new int[] { appWidgetId }, views);
266    }
267
268    /**
269     * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
270     *
271     * <p>
272     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
273     * and outside of the handler.
274     * This method will only work when called from the uid that owns the AppWidget provider.
275     *
276     * @param provider      The {@link ComponentName} for the {@link
277     * android.content.BroadcastReceiver BroadcastReceiver} provider
278     *                      for your AppWidget.
279     * @param views         The RemoteViews object to show.
280     */
281    public void updateAppWidget(ComponentName provider, RemoteViews views) {
282        try {
283            sService.updateAppWidgetProvider(provider, views);
284        }
285        catch (RemoteException e) {
286            throw new RuntimeException("system server dead?", e);
287        }
288    }
289
290    /**
291     * Return a list of the AppWidget providers that are currently installed.
292     */
293    public List<AppWidgetProviderInfo> getInstalledProviders() {
294        try {
295            return sService.getInstalledProviders();
296        }
297        catch (RemoteException e) {
298            throw new RuntimeException("system server dead?", e);
299        }
300    }
301
302    /**
303     * Get the available info about the AppWidget.
304     *
305     * @return A appWidgetId.  If the appWidgetId has not been bound to a provider yet, or
306     * you don't have access to that appWidgetId, null is returned.
307     */
308    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
309        try {
310            AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
311            if (info != null) {
312                // Converting complex to dp.
313                info.minWidth =
314                        TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
315                info.minHeight =
316                        TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
317            }
318            return info;
319        }
320        catch (RemoteException e) {
321            throw new RuntimeException("system server dead?", e);
322        }
323    }
324
325    /**
326     * Set the component for a given appWidgetId.
327     *
328     * <p class="note">You need the APPWIDGET_LIST permission.  This method is to be used by the
329     * AppWidget picker.
330     *
331     * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
332     * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
333     *                      provider for this AppWidget.
334     */
335    public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
336        try {
337            sService.bindAppWidgetId(appWidgetId, provider);
338        }
339        catch (RemoteException e) {
340            throw new RuntimeException("system server dead?", e);
341        }
342    }
343
344    /**
345     * Get the list of appWidgetIds that have been bound to the given AppWidget
346     * provider.
347     *
348     * @param provider The {@link android.content.BroadcastReceiver} that is the
349     *            AppWidget provider to find appWidgetIds for.
350     */
351    public int[] getAppWidgetIds(ComponentName provider) {
352        try {
353            return sService.getAppWidgetIds(provider);
354        }
355        catch (RemoteException e) {
356            throw new RuntimeException("system server dead?", e);
357        }
358    }
359}
360
361