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