AppWidgetService.java revision 0aa2d42e87e4a1ed5b83f356690e465d6a3587cc
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.Bundle; 31import android.os.IBinder; 32import android.os.RemoteException; 33import android.os.UserHandle; 34import android.util.Pair; 35import android.util.Slog; 36import android.util.SparseArray; 37import android.widget.RemoteViews; 38 39import com.android.internal.appwidget.IAppWidgetHost; 40import com.android.internal.appwidget.IAppWidgetService; 41import com.android.internal.widget.IRemoteViewsAdapterConnection; 42 43import java.io.FileDescriptor; 44import java.io.PrintWriter; 45import java.util.ArrayList; 46import java.util.List; 47import java.util.Locale; 48 49 50/** 51 * Redirects calls to this service to the instance of the service for the appropriate user. 52 */ 53class 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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 159 new IntentFilter(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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 169 filter, null, null); 170 // Register for events related to sdcard installation. 171 IntentFilter sdFilter = new IntentFilter(); 172 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 173 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 174 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 175 sdFilter, null, null); 176 177 IntentFilter userFilter = new IntentFilter(); 178 userFilter.addAction(Intent.ACTION_USER_REMOVED); 179 mContext.registerReceiver(new BroadcastReceiver() { 180 @Override 181 public void onReceive(Context context, Intent intent) { 182 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); 183 } 184 }, userFilter); 185 186 IntentFilter userStopFilter = new IntentFilter(); 187 userStopFilter.addAction(Intent.ACTION_USER_STOPPED); 188 mContext.registerReceiverAsUser(new BroadcastReceiver() { 189 @Override 190 public void onReceive(Context context, Intent intent) { 191 onUserStopped(getSendingUserId()); 192 } 193 }, UserHandle.ALL, userFilter, null, null); 194 } 195 196 @Override 197 public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException { 198 return getImplForUser(UserHandle.getCallingUserId()).allocateAppWidgetId( 199 packageName, hostId); 200 } 201 202 @Override 203 public void deleteAppWidgetId(int appWidgetId) throws RemoteException { 204 getImplForUser(UserHandle.getCallingUserId()).deleteAppWidgetId(appWidgetId); 205 } 206 207 @Override 208 public void deleteHost(int hostId) throws RemoteException { 209 getImplForUser(UserHandle.getCallingUserId()).deleteHost(hostId); 210 } 211 212 @Override 213 public void deleteAllHosts() throws RemoteException { 214 getImplForUser(UserHandle.getCallingUserId()).deleteAllHosts(); 215 } 216 217 @Override 218 public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) 219 throws RemoteException { 220 getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetId(appWidgetId, provider, 221 options); 222 } 223 224 @Override 225 public boolean bindAppWidgetIdIfAllowed( 226 String packageName, int appWidgetId, ComponentName provider, Bundle options) 227 throws RemoteException { 228 return getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetIdIfAllowed( 229 packageName, appWidgetId, provider, options); 230 } 231 232 @Override 233 public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException { 234 return getImplForUser(UserHandle.getCallingUserId()).hasBindAppWidgetPermission( 235 packageName); 236 } 237 238 @Override 239 public void setBindAppWidgetPermission(String packageName, boolean permission) 240 throws RemoteException { 241 getImplForUser(UserHandle.getCallingUserId()).setBindAppWidgetPermission( 242 packageName, permission); 243 } 244 245 @Override 246 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) 247 throws RemoteException { 248 getImplForUser(UserHandle.getCallingUserId()).bindRemoteViewsService( 249 appWidgetId, intent, connection); 250 } 251 252 @Override 253 public int[] startListening(IAppWidgetHost host, String packageName, int hostId, 254 List<RemoteViews> updatedViews) throws RemoteException { 255 return getImplForUser(UserHandle.getCallingUserId()).startListening(host, 256 packageName, hostId, updatedViews); 257 } 258 259 public void onUserRemoved(int userId) { 260 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); 261 if (userId < 1) return; 262 263 if (impl == null) { 264 AppWidgetServiceImpl.getSettingsFile(userId).delete(); 265 } else { 266 impl.onUserRemoved(); 267 } 268 } 269 270 public void onUserStopped(int userId) { 271 } 272 273 private AppWidgetServiceImpl getImplForUser(int userId) { 274 AppWidgetServiceImpl service = mAppWidgetServices.get(userId); 275 if (service == null) { 276 Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user"); 277 // TODO: Verify that it's a valid user 278 service = new AppWidgetServiceImpl(mContext, userId); 279 service.systemReady(mSafeMode); 280 // Assume that BOOT_COMPLETED was received, as this is a non-primary user. 281 service.sendInitialBroadcasts(); 282 mAppWidgetServices.append(userId, service); 283 } 284 285 return service; 286 } 287 288 @Override 289 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException { 290 return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetIds(provider); 291 } 292 293 @Override 294 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException { 295 return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetInfo(appWidgetId); 296 } 297 298 @Override 299 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException { 300 return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetViews(appWidgetId); 301 } 302 303 @Override 304 public void updateAppWidgetOptions(int appWidgetId, Bundle options) { 305 getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetOptions(appWidgetId, options); 306 } 307 308 @Override 309 public Bundle getAppWidgetOptions(int appWidgetId) { 310 return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetOptions(appWidgetId); 311 } 312 313 static int[] getAppWidgetIds(Provider p) { 314 int instancesSize = p.instances.size(); 315 int appWidgetIds[] = new int[instancesSize]; 316 for (int i=0; i<instancesSize; i++) { 317 appWidgetIds[i] = p.instances.get(i).appWidgetId; 318 } 319 return appWidgetIds; 320 } 321 322 @Override 323 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException { 324 return getImplForUser(UserHandle.getCallingUserId()).getInstalledProviders(); 325 } 326 327 @Override 328 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) 329 throws RemoteException { 330 getImplForUser(UserHandle.getCallingUserId()).notifyAppWidgetViewDataChanged( 331 appWidgetIds, viewId); 332 } 333 334 @Override 335 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) 336 throws RemoteException { 337 getImplForUser(UserHandle.getCallingUserId()).partiallyUpdateAppWidgetIds( 338 appWidgetIds, views); 339 } 340 341 @Override 342 public void stopListening(int hostId) throws RemoteException { 343 getImplForUser(UserHandle.getCallingUserId()).stopListening(hostId); 344 } 345 346 @Override 347 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException { 348 getImplForUser(UserHandle.getCallingUserId()).unbindRemoteViewsService( 349 appWidgetId, intent); 350 } 351 352 @Override 353 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException { 354 getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetIds(appWidgetIds, views); 355 } 356 357 @Override 358 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) 359 throws RemoteException { 360 getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetProvider(provider, views); 361 } 362 363 @Override 364 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 365 // Dump the state of all the app widget providers 366 for (int i = 0; i < mAppWidgetServices.size(); i++) { 367 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 368 service.dump(fd, pw, args); 369 } 370 } 371 372 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 373 public void onReceive(Context context, Intent intent) { 374 String action = intent.getAction(); 375 // Slog.d(TAG, "received " + action); 376 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 377 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 378 if (userId >= 0) { 379 getImplForUser(userId).sendInitialBroadcasts(); 380 } else { 381 Slog.w(TAG, "Not user handle supplied in " + intent); 382 } 383 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 384 for (int i = 0; i < mAppWidgetServices.size(); i++) { 385 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 386 service.onConfigurationChanged(); 387 } 388 } else { 389 int sendingUser = getSendingUserId(); 390 if (sendingUser == UserHandle.USER_ALL) { 391 for (int i = 0; i < mAppWidgetServices.size(); i++) { 392 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 393 service.onBroadcastReceived(intent); 394 } 395 } else { 396 AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser); 397 if (service != null) { 398 service.onBroadcastReceived(intent); 399 } 400 } 401 } 402 } 403 }; 404} 405