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