AppWidgetManager.java revision 8f25c426b118c35f558cbf27bd413e1eb6d59823
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 static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap(); 188 static IAppWidgetService sService; 189 190 Context mContext; 191 192 private DisplayMetrics mDisplayMetrics; 193 194 /** 195 * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context 196 * Context} object. 197 */ 198 public static AppWidgetManager getInstance(Context context) { 199 synchronized (sManagerCache) { 200 if (sService == null) { 201 IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE); 202 sService = IAppWidgetService.Stub.asInterface(b); 203 } 204 205 WeakReference<AppWidgetManager> ref = sManagerCache.get(context); 206 AppWidgetManager result = null; 207 if (ref != null) { 208 result = ref.get(); 209 } 210 if (result == null) { 211 result = new AppWidgetManager(context); 212 sManagerCache.put(context, new WeakReference(result)); 213 } 214 return result; 215 } 216 } 217 218 private AppWidgetManager(Context context) { 219 mContext = context; 220 mDisplayMetrics = context.getResources().getDisplayMetrics(); 221 } 222 223 /** 224 * Set the RemoteViews to use for the specified appWidgetIds. 225 * 226 * <p> 227 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast, 228 * and outside of the handler. 229 * This method will only work when called from the uid that owns the AppWidget provider. 230 * 231 * @param appWidgetIds The AppWidget instances for which to set the RemoteViews. 232 * @param views The RemoteViews object to show. 233 */ 234 public void updateAppWidget(int[] appWidgetIds, RemoteViews views) { 235 try { 236 sService.updateAppWidgetIds(appWidgetIds, views); 237 } 238 catch (RemoteException e) { 239 throw new RuntimeException("system server dead?", e); 240 } 241 } 242 243 /** 244 * Set the RemoteViews to use for the specified appWidgetId. 245 * 246 * <p> 247 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast, 248 * and outside of the handler. 249 * This method will only work when called from the uid that owns the AppWidget provider. 250 * 251 * @param appWidgetId The AppWidget instance for which to set the RemoteViews. 252 * @param views The RemoteViews object to show. 253 */ 254 public void updateAppWidget(int appWidgetId, RemoteViews views) { 255 updateAppWidget(new int[] { appWidgetId }, views); 256 } 257 258 /** 259 * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider. 260 * 261 * <p> 262 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast, 263 * and outside of the handler. 264 * This method will only work when called from the uid that owns the AppWidget provider. 265 * 266 * @param provider The {@link ComponentName} for the {@link 267 * android.content.BroadcastReceiver BroadcastReceiver} provider 268 * for your AppWidget. 269 * @param views The RemoteViews object to show. 270 */ 271 public void updateAppWidget(ComponentName provider, RemoteViews views) { 272 try { 273 sService.updateAppWidgetProvider(provider, views); 274 } 275 catch (RemoteException e) { 276 throw new RuntimeException("system server dead?", e); 277 } 278 } 279 280 /** 281 * Return a list of the AppWidget providers that are currently installed. 282 */ 283 public List<AppWidgetProviderInfo> getInstalledProviders() { 284 try { 285 return sService.getInstalledProviders(); 286 } 287 catch (RemoteException e) { 288 throw new RuntimeException("system server dead?", e); 289 } 290 } 291 292 /** 293 * Get the available info about the AppWidget. 294 * 295 * @return A appWidgetId. If the appWidgetId has not been bound to a provider yet, or 296 * you don't have access to that appWidgetId, null is returned. 297 */ 298 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { 299 try { 300 AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId); 301 if (info != null) { 302 // Converting complex to dp. 303 info.minWidth = 304 TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics); 305 info.minHeight = 306 TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics); 307 } 308 return info; 309 } 310 catch (RemoteException e) { 311 throw new RuntimeException("system server dead?", e); 312 } 313 } 314 315 /** 316 * Set the component for a given appWidgetId. 317 * 318 * <p class="note">You need the APPWIDGET_LIST permission. This method is to be used by the 319 * AppWidget picker. 320 * 321 * @param appWidgetId The AppWidget instance for which to set the RemoteViews. 322 * @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget 323 * provider for this AppWidget. 324 */ 325 public void bindAppWidgetId(int appWidgetId, ComponentName provider) { 326 try { 327 sService.bindAppWidgetId(appWidgetId, provider); 328 } 329 catch (RemoteException e) { 330 throw new RuntimeException("system server dead?", e); 331 } 332 } 333 334 /** 335 * Get the list of appWidgetIds that have been bound to the given AppWidget 336 * provider. 337 * 338 * @param provider The {@link android.content.BroadcastReceiver} that is the 339 * AppWidget provider to find appWidgetIds for. 340 */ 341 public int[] getAppWidgetIds(ComponentName provider) { 342 try { 343 return sService.getAppWidgetIds(provider); 344 } 345 catch (RemoteException e) { 346 throw new RuntimeException("system server dead?", e); 347 } 348 } 349} 350 351