AppWidgetService.java revision a1a2f967e2a0de4c4190a775ac314ad32288727e
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.ActivityManagerNative; 20import android.appwidget.AppWidgetProviderInfo; 21import android.content.BroadcastReceiver; 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.PackageManager; 27import android.os.Binder; 28import android.os.Bundle; 29import android.os.Handler; 30import android.os.HandlerThread; 31import android.os.IBinder; 32import android.os.RemoteException; 33import android.os.UserHandle; 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.util.IndentingPrintWriter; 41 42import java.io.FileDescriptor; 43import java.io.PrintWriter; 44import java.util.List; 45import java.util.Locale; 46 47 48/** 49 * Redirects calls to this service to the instance of the service for the appropriate user. 50 */ 51class AppWidgetService extends IAppWidgetService.Stub 52{ 53 private static final String TAG = "AppWidgetService"; 54 55 Context mContext; 56 Locale mLocale; 57 PackageManager mPackageManager; 58 boolean mSafeMode; 59 private final Handler mSaveStateHandler; 60 61 private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices; 62 63 AppWidgetService(Context context) { 64 mContext = context; 65 66 HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state"); 67 handlerThread.start(); 68 mSaveStateHandler = new Handler(handlerThread.getLooper()); 69 70 mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5); 71 AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler); 72 mAppWidgetServices.append(0, primary); 73 } 74 75 public void systemReady(boolean safeMode) { 76 mSafeMode = safeMode; 77 78 mAppWidgetServices.get(0).systemReady(safeMode); 79 80 // Register for the boot completed broadcast, so we can send the 81 // ENABLE broacasts. If we try to send them now, they time out, 82 // because the system isn't ready to handle them yet. 83 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 84 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 85 86 // Register for configuration changes so we can update the names 87 // of the widgets when the locale changes. 88 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 89 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); 90 91 // Register for broadcasts about package install, etc., so we can 92 // update the provider list. 93 IntentFilter filter = new IntentFilter(); 94 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 95 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 96 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 97 filter.addDataScheme("package"); 98 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 99 filter, null, null); 100 // Register for events related to sdcard installation. 101 IntentFilter sdFilter = new IntentFilter(); 102 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 103 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 104 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 105 sdFilter, null, null); 106 107 IntentFilter userFilter = new IntentFilter(); 108 userFilter.addAction(Intent.ACTION_USER_REMOVED); 109 userFilter.addAction(Intent.ACTION_USER_STOPPING); 110 mContext.registerReceiver(new BroadcastReceiver() { 111 @Override 112 public void onReceive(Context context, Intent intent) { 113 if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 114 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 115 UserHandle.USER_NULL)); 116 } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) { 117 onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 118 UserHandle.USER_NULL)); 119 } 120 } 121 }, userFilter); 122 } 123 124 /** 125 * This returns the user id of the caller, if the caller is not the system process, 126 * otherwise it assumes that the calls are from the lockscreen and hence are meant for the 127 * current user. TODO: Instead, have lockscreen make explicit calls with userId 128 */ 129 private int getCallingOrCurrentUserId() { 130 int callingUid = Binder.getCallingUid(); 131 // Also check the PID because Settings (power control widget) also runs as System UID 132 if (callingUid == android.os.Process.myUid() 133 && Binder.getCallingPid() == android.os.Process.myPid()) { 134 try { 135 return ActivityManagerNative.getDefault().getCurrentUser().id; 136 } catch (RemoteException re) { 137 return UserHandle.getUserId(callingUid); 138 } 139 } else { 140 return UserHandle.getUserId(callingUid); 141 } 142 } 143 144 @Override 145 public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException { 146 return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId( 147 packageName, hostId); 148 } 149 150 @Override 151 public void deleteAppWidgetId(int appWidgetId) throws RemoteException { 152 getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId); 153 } 154 155 @Override 156 public void deleteHost(int hostId) throws RemoteException { 157 getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId); 158 } 159 160 @Override 161 public void deleteAllHosts() throws RemoteException { 162 getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts(); 163 } 164 165 @Override 166 public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) 167 throws RemoteException { 168 getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider, 169 options); 170 } 171 172 @Override 173 public boolean bindAppWidgetIdIfAllowed( 174 String packageName, int appWidgetId, ComponentName provider, Bundle options) 175 throws RemoteException { 176 return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed( 177 packageName, appWidgetId, provider, options); 178 } 179 180 @Override 181 public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException { 182 return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission( 183 packageName); 184 } 185 186 @Override 187 public void setBindAppWidgetPermission(String packageName, boolean permission) 188 throws RemoteException { 189 getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission( 190 packageName, permission); 191 } 192 193 @Override 194 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) 195 throws RemoteException { 196 getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService( 197 appWidgetId, intent, connection); 198 } 199 200 @Override 201 public int[] startListening(IAppWidgetHost host, String packageName, int hostId, 202 List<RemoteViews> updatedViews) throws RemoteException { 203 return getImplForUser(getCallingOrCurrentUserId()).startListening(host, 204 packageName, hostId, updatedViews); 205 } 206 207 public void onUserRemoved(int userId) { 208 if (userId < 1) return; 209 synchronized (mAppWidgetServices) { 210 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); 211 mAppWidgetServices.remove(userId); 212 213 if (impl == null) { 214 AppWidgetServiceImpl.getSettingsFile(userId).delete(); 215 } else { 216 impl.onUserRemoved(); 217 } 218 } 219 } 220 221 public void onUserStopping(int userId) { 222 if (userId < 1) return; 223 synchronized (mAppWidgetServices) { 224 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); 225 if (impl != null) { 226 mAppWidgetServices.remove(userId); 227 impl.onUserStopping(); 228 } 229 } 230 } 231 232 private AppWidgetServiceImpl getImplForUser(int userId) { 233 boolean sendInitial = false; 234 AppWidgetServiceImpl service; 235 synchronized (mAppWidgetServices) { 236 service = mAppWidgetServices.get(userId); 237 if (service == null) { 238 Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding"); 239 // TODO: Verify that it's a valid user 240 service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler); 241 service.systemReady(mSafeMode); 242 // Assume that BOOT_COMPLETED was received, as this is a non-primary user. 243 mAppWidgetServices.append(userId, service); 244 sendInitial = true; 245 } 246 } 247 if (sendInitial) { 248 service.sendInitialBroadcasts(); 249 } 250 return service; 251 } 252 253 @Override 254 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException { 255 return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider); 256 } 257 258 @Override 259 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException { 260 return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId); 261 } 262 263 @Override 264 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException { 265 return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId); 266 } 267 268 @Override 269 public void updateAppWidgetOptions(int appWidgetId, Bundle options) { 270 getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options); 271 } 272 273 @Override 274 public Bundle getAppWidgetOptions(int appWidgetId) { 275 return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId); 276 } 277 278 @Override 279 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException { 280 return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(); 281 } 282 283 @Override 284 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) 285 throws RemoteException { 286 getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged( 287 appWidgetIds, viewId); 288 } 289 290 @Override 291 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) 292 throws RemoteException { 293 getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds( 294 appWidgetIds, views); 295 } 296 297 @Override 298 public void stopListening(int hostId) throws RemoteException { 299 getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId); 300 } 301 302 @Override 303 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException { 304 getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService( 305 appWidgetId, intent); 306 } 307 308 @Override 309 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException { 310 getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views); 311 } 312 313 @Override 314 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) 315 throws RemoteException { 316 getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views); 317 } 318 319 @Override 320 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 321 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 322 323 // Dump the state of all the app widget providers 324 synchronized (mAppWidgetServices) { 325 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 326 for (int i = 0; i < mAppWidgetServices.size(); i++) { 327 pw.println("User: " + mAppWidgetServices.keyAt(i)); 328 ipw.increaseIndent(); 329 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 330 service.dump(fd, ipw, args); 331 ipw.decreaseIndent(); 332 } 333 } 334 } 335 336 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 337 public void onReceive(Context context, Intent intent) { 338 String action = intent.getAction(); 339 // Slog.d(TAG, "received " + action); 340 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 341 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 342 if (userId >= 0) { 343 getImplForUser(userId).sendInitialBroadcasts(); 344 } else { 345 Slog.w(TAG, "Incorrect user handle supplied in " + intent); 346 } 347 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 348 for (int i = 0; i < mAppWidgetServices.size(); i++) { 349 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 350 service.onConfigurationChanged(); 351 } 352 } else { 353 int sendingUser = getSendingUserId(); 354 if (sendingUser == UserHandle.USER_ALL) { 355 for (int i = 0; i < mAppWidgetServices.size(); i++) { 356 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); 357 service.onBroadcastReceived(intent); 358 } 359 } else { 360 AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser); 361 if (service != null) { 362 service.onBroadcastReceived(intent); 363 } 364 } 365 } 366 } 367 }; 368} 369