Home | History | Annotate | Download | only in appwidget
      1 /*
      2  * Copyright (C) 2009 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 java.util.ArrayList;
     20 import java.util.HashMap;
     21 
     22 import android.content.Context;
     23 import android.os.Handler;
     24 import android.os.IBinder;
     25 import android.os.Looper;
     26 import android.os.Message;
     27 import android.os.RemoteException;
     28 import android.os.ServiceManager;
     29 import android.util.DisplayMetrics;
     30 import android.util.TypedValue;
     31 import android.widget.RemoteViews;
     32 
     33 import com.android.internal.appwidget.IAppWidgetHost;
     34 import com.android.internal.appwidget.IAppWidgetService;
     35 
     36 /**
     37  * AppWidgetHost provides the interaction with the AppWidget service for apps,
     38  * like the home screen, that want to embed AppWidgets in their UI.
     39  */
     40 public class AppWidgetHost {
     41 
     42     static final int HANDLE_UPDATE = 1;
     43     static final int HANDLE_PROVIDER_CHANGED = 2;
     44     static final int HANDLE_VIEW_DATA_CHANGED = 3;
     45 
     46     final static Object sServiceLock = new Object();
     47     static IAppWidgetService sService;
     48     private DisplayMetrics mDisplayMetrics;
     49 
     50     Context mContext;
     51     String mPackageName;
     52 
     53     class Callbacks extends IAppWidgetHost.Stub {
     54         public void updateAppWidget(int appWidgetId, RemoteViews views) {
     55             Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
     56             msg.arg1 = appWidgetId;
     57             msg.obj = views;
     58             msg.sendToTarget();
     59         }
     60 
     61         public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
     62             Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
     63             msg.arg1 = appWidgetId;
     64             msg.obj = info;
     65             msg.sendToTarget();
     66         }
     67 
     68         public void viewDataChanged(int appWidgetId, int viewId) {
     69             Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED);
     70             msg.arg1 = appWidgetId;
     71             msg.arg2 = viewId;
     72             msg.sendToTarget();
     73         }
     74     }
     75 
     76     class UpdateHandler extends Handler {
     77         public UpdateHandler(Looper looper) {
     78             super(looper);
     79         }
     80 
     81         public void handleMessage(Message msg) {
     82             switch (msg.what) {
     83                 case HANDLE_UPDATE: {
     84                     updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
     85                     break;
     86                 }
     87                 case HANDLE_PROVIDER_CHANGED: {
     88                     onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
     89                     break;
     90                 }
     91                 case HANDLE_VIEW_DATA_CHANGED: {
     92                     viewDataChanged(msg.arg1, msg.arg2);
     93                     break;
     94                 }
     95             }
     96         }
     97     }
     98 
     99     Handler mHandler;
    100 
    101     int mHostId;
    102     Callbacks mCallbacks = new Callbacks();
    103     final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
    104 
    105     public AppWidgetHost(Context context, int hostId) {
    106         mContext = context;
    107         mHostId = hostId;
    108         mHandler = new UpdateHandler(context.getMainLooper());
    109         mDisplayMetrics = context.getResources().getDisplayMetrics();
    110         synchronized (sServiceLock) {
    111             if (sService == null) {
    112                 IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
    113                 sService = IAppWidgetService.Stub.asInterface(b);
    114             }
    115         }
    116     }
    117 
    118     /**
    119      * Start receiving onAppWidgetChanged calls for your AppWidgets.  Call this when your activity
    120      * becomes visible, i.e. from onStart() in your Activity.
    121      */
    122     public void startListening() {
    123         int[] updatedIds;
    124         ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
    125 
    126         try {
    127             if (mPackageName == null) {
    128                 mPackageName = mContext.getPackageName();
    129             }
    130             updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);
    131         }
    132         catch (RemoteException e) {
    133             throw new RuntimeException("system server dead?", e);
    134         }
    135 
    136         final int N = updatedIds.length;
    137         for (int i=0; i<N; i++) {
    138             updateAppWidgetView(updatedIds[i], updatedViews.get(i));
    139         }
    140     }
    141 
    142     /**
    143      * Stop receiving onAppWidgetChanged calls for your AppWidgets.  Call this when your activity is
    144      * no longer visible, i.e. from onStop() in your Activity.
    145      */
    146     public void stopListening() {
    147         try {
    148             sService.stopListening(mHostId);
    149         }
    150         catch (RemoteException e) {
    151             throw new RuntimeException("system server dead?", e);
    152         }
    153     }
    154 
    155     /**
    156      * Get a appWidgetId for a host in the calling process.
    157      *
    158      * @return a appWidgetId
    159      */
    160     public int allocateAppWidgetId() {
    161         try {
    162             if (mPackageName == null) {
    163                 mPackageName = mContext.getPackageName();
    164             }
    165             return sService.allocateAppWidgetId(mPackageName, mHostId);
    166         }
    167         catch (RemoteException e) {
    168             throw new RuntimeException("system server dead?", e);
    169         }
    170     }
    171 
    172     /**
    173      * Stop listening to changes for this AppWidget.
    174      */
    175     public void deleteAppWidgetId(int appWidgetId) {
    176         synchronized (mViews) {
    177             mViews.remove(appWidgetId);
    178             try {
    179                 sService.deleteAppWidgetId(appWidgetId);
    180             }
    181             catch (RemoteException e) {
    182                 throw new RuntimeException("system server dead?", e);
    183             }
    184         }
    185     }
    186 
    187     /**
    188      * Remove all records about this host from the AppWidget manager.
    189      * <ul>
    190      *   <li>Call this when initializing your database, as it might be because of a data wipe.</li>
    191      *   <li>Call this to have the AppWidget manager release all resources associated with your
    192      *   host.  Any future calls about this host will cause the records to be re-allocated.</li>
    193      * </ul>
    194      */
    195     public void deleteHost() {
    196         try {
    197             sService.deleteHost(mHostId);
    198         }
    199         catch (RemoteException e) {
    200             throw new RuntimeException("system server dead?", e);
    201         }
    202     }
    203 
    204     /**
    205      * Remove all records about all hosts for your package.
    206      * <ul>
    207      *   <li>Call this when initializing your database, as it might be because of a data wipe.</li>
    208      *   <li>Call this to have the AppWidget manager release all resources associated with your
    209      *   host.  Any future calls about this host will cause the records to be re-allocated.</li>
    210      * </ul>
    211      */
    212     public static void deleteAllHosts() {
    213         try {
    214             sService.deleteAllHosts();
    215         }
    216         catch (RemoteException e) {
    217             throw new RuntimeException("system server dead?", e);
    218         }
    219     }
    220 
    221     /**
    222      * Create the AppWidgetHostView for the given widget.
    223      * The AppWidgetHost retains a pointer to the newly-created View.
    224      */
    225     public final AppWidgetHostView createView(Context context, int appWidgetId,
    226             AppWidgetProviderInfo appWidget) {
    227         AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
    228         view.setAppWidget(appWidgetId, appWidget);
    229         synchronized (mViews) {
    230             mViews.put(appWidgetId, view);
    231         }
    232         RemoteViews views;
    233         try {
    234             views = sService.getAppWidgetViews(appWidgetId);
    235         } catch (RemoteException e) {
    236             throw new RuntimeException("system server dead?", e);
    237         }
    238         view.updateAppWidget(views);
    239         return view;
    240     }
    241 
    242     /**
    243      * Called to create the AppWidgetHostView.  Override to return a custom subclass if you
    244      * need it.  {@more}
    245      */
    246     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
    247             AppWidgetProviderInfo appWidget) {
    248         return new AppWidgetHostView(context);
    249     }
    250 
    251     /**
    252      * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
    253      */
    254     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
    255         AppWidgetHostView v;
    256 
    257         // Convert complex to dp -- we are getting the AppWidgetProviderInfo from the
    258         // AppWidgetService, which doesn't have our context, hence we need to do the
    259         // conversion here.
    260         appWidget.minWidth =
    261             TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics);
    262         appWidget.minHeight =
    263             TypedValue.complexToDimensionPixelSize(appWidget.minHeight, mDisplayMetrics);
    264         appWidget.minResizeWidth =
    265             TypedValue.complexToDimensionPixelSize(appWidget.minResizeWidth, mDisplayMetrics);
    266         appWidget.minResizeHeight =
    267             TypedValue.complexToDimensionPixelSize(appWidget.minResizeHeight, mDisplayMetrics);
    268 
    269         synchronized (mViews) {
    270             v = mViews.get(appWidgetId);
    271         }
    272         if (v != null) {
    273             v.resetAppWidget(appWidget);
    274         }
    275     }
    276 
    277     void updateAppWidgetView(int appWidgetId, RemoteViews views) {
    278         AppWidgetHostView v;
    279         synchronized (mViews) {
    280             v = mViews.get(appWidgetId);
    281         }
    282         if (v != null) {
    283             v.updateAppWidget(views);
    284         }
    285     }
    286 
    287     void viewDataChanged(int appWidgetId, int viewId) {
    288         AppWidgetHostView v;
    289         synchronized (mViews) {
    290             v = mViews.get(appWidgetId);
    291         }
    292         if (v != null) {
    293             v.viewDataChanged(viewId);
    294         }
    295     }
    296 
    297     /**
    298      * Clear the list of Views that have been created by this AppWidgetHost.
    299      */
    300     protected void clearViews() {
    301         mViews.clear();
    302     }
    303 }
    304 
    305 
    306