Home | History | Annotate | Download | only in appwidget
      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      */
    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