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 17 package android.appwidget; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.os.IBinder; 22 import android.os.RemoteException; 23 import android.os.ServiceManager; 24 import android.util.DisplayMetrics; 25 import android.util.Log; 26 import android.util.TypedValue; 27 import android.widget.RemoteViews; 28 29 import com.android.internal.appwidget.IAppWidgetService; 30 31 import java.lang.ref.WeakReference; 32 import java.util.List; 33 import java.util.WeakHashMap; 34 35 /** 36 * Updates AppWidget state; gets information about installed AppWidget providers and other 37 * AppWidget related state. 38 */ 39 public 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 */ getInstance(Context context)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 AppWidgetManager(Context context)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 */ updateAppWidget(int[] appWidgetIds, RemoteViews views)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 */ updateAppWidget(int appWidgetId, RemoteViews views)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 */ updateAppWidget(ComponentName provider, RemoteViews views)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 */ getInstalledProviders()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 */ getAppWidgetInfo(int appWidgetId)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 */ bindAppWidgetId(int appWidgetId, ComponentName provider)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 */ getAppWidgetIds(ComponentName provider)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