Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2007 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 com.android.server;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.appwidget.AppWidgetManager;
     22 import android.appwidget.AppWidgetProviderInfo;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.ServiceConnection;
     29 import android.content.pm.PackageManager;
     30 import android.os.Binder;
     31 import android.os.Bundle;
     32 import android.os.IBinder;
     33 import android.os.RemoteException;
     34 import android.util.Pair;
     35 import android.util.Slog;
     36 import android.util.SparseArray;
     37 import android.widget.RemoteViews;
     38 
     39 import com.android.internal.appwidget.IAppWidgetHost;
     40 import com.android.internal.appwidget.IAppWidgetService;
     41 import com.android.internal.widget.IRemoteViewsAdapterConnection;
     42 
     43 import java.io.FileDescriptor;
     44 import java.io.PrintWriter;
     45 import java.util.ArrayList;
     46 import java.util.List;
     47 import java.util.Locale;
     48 
     49 
     50 /**
     51  * Redirects calls to this service to the instance of the service for the appropriate user.
     52  */
     53 class AppWidgetService extends IAppWidgetService.Stub
     54 {
     55     private static final String TAG = "AppWidgetService";
     56 
     57     /*
     58      * When identifying a Host or Provider based on the calling process, use the uid field.
     59      * When identifying a Host or Provider based on a package manager broadcast, use the
     60      * package given.
     61      */
     62 
     63     static class Provider {
     64         int uid;
     65         AppWidgetProviderInfo info;
     66         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
     67         PendingIntent broadcast;
     68         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
     69 
     70         int tag;    // for use while saving state (the index)
     71     }
     72 
     73     static class Host {
     74         int uid;
     75         int hostId;
     76         String packageName;
     77         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
     78         IAppWidgetHost callbacks;
     79         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
     80 
     81         int tag;    // for use while saving state (the index)
     82     }
     83 
     84     static class AppWidgetId {
     85         int appWidgetId;
     86         Provider provider;
     87         RemoteViews views;
     88         Host host;
     89     }
     90 
     91     /**
     92      * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
     93      * This needs to be a static inner class since a reference to the ServiceConnection is held
     94      * globally and may lead us to leak AppWidgetService instances (if there were more than one).
     95      */
     96     static class ServiceConnectionProxy implements ServiceConnection {
     97         private final IBinder mConnectionCb;
     98 
     99         ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
    100             mConnectionCb = connectionCb;
    101         }
    102         public void onServiceConnected(ComponentName name, IBinder service) {
    103             final IRemoteViewsAdapterConnection cb =
    104                 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
    105             try {
    106                 cb.onServiceConnected(service);
    107             } catch (Exception e) {
    108                 e.printStackTrace();
    109             }
    110         }
    111         public void onServiceDisconnected(ComponentName name) {
    112             disconnect();
    113         }
    114         public void disconnect() {
    115             final IRemoteViewsAdapterConnection cb =
    116                 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
    117             try {
    118                 cb.onServiceDisconnected();
    119             } catch (Exception e) {
    120                 e.printStackTrace();
    121             }
    122         }
    123     }
    124 
    125     Context mContext;
    126     Locale mLocale;
    127     PackageManager mPackageManager;
    128     AlarmManager mAlarmManager;
    129     ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
    130     int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
    131     final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
    132     ArrayList<Host> mHosts = new ArrayList<Host>();
    133     boolean mSafeMode;
    134 
    135 
    136     private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
    137 
    138     AppWidgetService(Context context) {
    139         mContext = context;
    140         mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
    141         AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
    142         mAppWidgetServices.append(0, primary);
    143     }
    144 
    145     public void systemReady(boolean safeMode) {
    146         mSafeMode = safeMode;
    147 
    148         mAppWidgetServices.get(0).systemReady(safeMode);
    149 
    150         // Register for the boot completed broadcast, so we can send the
    151         // ENABLE broacasts. If we try to send them now, they time out,
    152         // because the system isn't ready to handle them yet.
    153         mContext.registerReceiver(mBroadcastReceiver,
    154                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
    155 
    156         // Register for configuration changes so we can update the names
    157         // of the widgets when the locale changes.
    158         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
    159                 Intent.ACTION_CONFIGURATION_CHANGED), null, null);
    160 
    161         // Register for broadcasts about package install, etc., so we can
    162         // update the provider list.
    163         IntentFilter filter = new IntentFilter();
    164         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
    165         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    166         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    167         filter.addDataScheme("package");
    168         mContext.registerReceiver(mBroadcastReceiver, filter);
    169         // Register for events related to sdcard installation.
    170         IntentFilter sdFilter = new IntentFilter();
    171         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
    172         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    173         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
    174 
    175         IntentFilter userFilter = new IntentFilter();
    176         userFilter.addAction(Intent.ACTION_USER_REMOVED);
    177         mContext.registerReceiver(new BroadcastReceiver() {
    178             @Override
    179             public void onReceive(Context context, Intent intent) {
    180                 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
    181             }
    182         }, userFilter);
    183     }
    184 
    185     @Override
    186     public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
    187         return getImplForUser().allocateAppWidgetId(packageName, hostId);
    188     }
    189 
    190     @Override
    191     public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
    192         getImplForUser().deleteAppWidgetId(appWidgetId);
    193     }
    194 
    195     @Override
    196     public void deleteHost(int hostId) throws RemoteException {
    197         getImplForUser().deleteHost(hostId);
    198     }
    199 
    200     @Override
    201     public void deleteAllHosts() throws RemoteException {
    202         getImplForUser().deleteAllHosts();
    203     }
    204 
    205     @Override
    206     public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
    207         getImplForUser().bindAppWidgetId(appWidgetId, provider);
    208     }
    209 
    210     @Override
    211     public boolean bindAppWidgetIdIfAllowed(
    212             String packageName, int appWidgetId, ComponentName provider) throws RemoteException {
    213         return getImplForUser().bindAppWidgetIdIfAllowed(packageName, appWidgetId, provider);
    214     }
    215 
    216     @Override
    217     public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
    218         return getImplForUser().hasBindAppWidgetPermission(packageName);
    219     }
    220 
    221     @Override
    222     public void setBindAppWidgetPermission(String packageName, boolean permission)
    223             throws RemoteException {
    224         getImplForUser().setBindAppWidgetPermission(packageName, permission);
    225     }
    226 
    227     @Override
    228     public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
    229             throws RemoteException {
    230         getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
    231     }
    232 
    233     @Override
    234     public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
    235             List<RemoteViews> updatedViews) throws RemoteException {
    236         return getImplForUser().startListening(host, packageName, hostId, updatedViews);
    237     }
    238 
    239     public void onUserRemoved(int userId) {
    240         AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
    241         if (userId < 1) return;
    242 
    243         if (impl == null) {
    244             AppWidgetServiceImpl.getSettingsFile(userId).delete();
    245         } else {
    246             impl.onUserRemoved();
    247         }
    248     }
    249 
    250     private AppWidgetServiceImpl getImplForUser() {
    251         final int userId = Binder.getOrigCallingUser();
    252         AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
    253         if (service == null) {
    254             Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
    255             // TODO: Verify that it's a valid user
    256             service = new AppWidgetServiceImpl(mContext, userId);
    257             service.systemReady(mSafeMode);
    258             // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
    259             service.sendInitialBroadcasts();
    260             mAppWidgetServices.append(userId, service);
    261         }
    262 
    263         return service;
    264     }
    265 
    266     @Override
    267     public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
    268         return getImplForUser().getAppWidgetIds(provider);
    269     }
    270 
    271     @Override
    272     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
    273         return getImplForUser().getAppWidgetInfo(appWidgetId);
    274     }
    275 
    276     @Override
    277     public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
    278         return getImplForUser().getAppWidgetViews(appWidgetId);
    279     }
    280 
    281     @Override
    282     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
    283         getImplForUser().updateAppWidgetOptions(appWidgetId, options);
    284     }
    285 
    286     @Override
    287     public Bundle getAppWidgetOptions(int appWidgetId) {
    288         return getImplForUser().getAppWidgetOptions(appWidgetId);
    289     }
    290 
    291     static int[] getAppWidgetIds(Provider p) {
    292         int instancesSize = p.instances.size();
    293         int appWidgetIds[] = new int[instancesSize];
    294         for (int i=0; i<instancesSize; i++) {
    295             appWidgetIds[i] = p.instances.get(i).appWidgetId;
    296         }
    297         return appWidgetIds;
    298     }
    299 
    300     @Override
    301     public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
    302         return getImplForUser().getInstalledProviders();
    303     }
    304 
    305     @Override
    306     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
    307             throws RemoteException {
    308         getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
    309     }
    310 
    311     @Override
    312     public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
    313             throws RemoteException {
    314         getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
    315     }
    316 
    317     @Override
    318     public void stopListening(int hostId) throws RemoteException {
    319         getImplForUser().stopListening(hostId);
    320     }
    321 
    322     @Override
    323     public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
    324         getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
    325     }
    326 
    327     @Override
    328     public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
    329         getImplForUser().updateAppWidgetIds(appWidgetIds, views);
    330     }
    331 
    332     @Override
    333     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
    334             throws RemoteException {
    335         getImplForUser().updateAppWidgetProvider(provider, views);
    336     }
    337 
    338     @Override
    339     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    340         // Dump the state of all the app widget providers
    341         for (int i = 0; i < mAppWidgetServices.size(); i++) {
    342             AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
    343             service.dump(fd, pw, args);
    344         }
    345     }
    346 
    347     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    348         public void onReceive(Context context, Intent intent) {
    349             String action = intent.getAction();
    350             // Slog.d(TAG, "received " + action);
    351             if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
    352                 getImplForUser().sendInitialBroadcasts();
    353             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
    354                 for (int i = 0; i < mAppWidgetServices.size(); i++) {
    355                     AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
    356                     service.onConfigurationChanged();
    357                 }
    358             } else {
    359                 for (int i = 0; i < mAppWidgetServices.size(); i++) {
    360                     AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
    361                     service.onBroadcastReceived(intent);
    362                 }
    363             }
    364         }
    365     };
    366 }
    367