AppWidgetService.java revision 15d161f61bd97e937e95fe8a8e520a947113c7b1
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 java.io.File; 20import java.io.FileDescriptor; 21import java.io.FileInputStream; 22import java.io.FileOutputStream; 23import java.io.IOException; 24import java.io.PrintWriter; 25import java.util.ArrayList; 26import java.util.HashMap; 27import java.util.HashSet; 28import java.util.Iterator; 29import java.util.List; 30import java.util.Locale; 31 32import org.apache.commons.logging.impl.SimpleLog; 33import org.xmlpull.v1.XmlPullParser; 34import org.xmlpull.v1.XmlPullParserException; 35import org.xmlpull.v1.XmlSerializer; 36 37import android.app.AlarmManager; 38import android.app.PendingIntent; 39import android.appwidget.AppWidgetManager; 40import android.appwidget.AppWidgetProviderInfo; 41import android.content.BroadcastReceiver; 42import android.content.ComponentName; 43import android.content.Context; 44import android.content.Intent; 45import android.content.Intent.FilterComparison; 46import android.content.IntentFilter; 47import android.content.ServiceConnection; 48import android.content.pm.ActivityInfo; 49import android.content.pm.ApplicationInfo; 50import android.content.pm.PackageInfo; 51import android.content.pm.PackageManager; 52import android.content.pm.ResolveInfo; 53import android.content.pm.ServiceInfo; 54import android.content.res.Resources; 55import android.content.res.TypedArray; 56import android.content.res.XmlResourceParser; 57import android.net.Uri; 58import android.os.Binder; 59import android.os.Bundle; 60import android.os.IBinder; 61import android.os.Process; 62import android.os.RemoteException; 63import android.os.SystemClock; 64import android.util.AttributeSet; 65import android.util.Log; 66import android.util.Pair; 67import android.util.Slog; 68import android.util.TypedValue; 69import android.util.Xml; 70import android.widget.RemoteViews; 71import android.widget.RemoteViewsService; 72 73import com.android.internal.appwidget.IAppWidgetHost; 74import com.android.internal.appwidget.IAppWidgetService; 75import com.android.internal.util.FastXmlSerializer; 76import com.android.internal.widget.IRemoteViewsAdapterConnection; 77import com.android.internal.widget.IRemoteViewsFactory; 78 79class AppWidgetService extends IAppWidgetService.Stub 80{ 81 private static final String TAG = "AppWidgetService"; 82 83 private static final String SETTINGS_FILENAME = "appwidgets.xml"; 84 private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp"; 85 private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes 86 87 /* 88 * When identifying a Host or Provider based on the calling process, use the uid field. 89 * When identifying a Host or Provider based on a package manager broadcast, use the 90 * package given. 91 */ 92 93 static class Provider { 94 int uid; 95 AppWidgetProviderInfo info; 96 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 97 PendingIntent broadcast; 98 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 99 100 int tag; // for use while saving state (the index) 101 } 102 103 static class Host { 104 int uid; 105 int hostId; 106 String packageName; 107 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 108 IAppWidgetHost callbacks; 109 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 110 111 int tag; // for use while saving state (the index) 112 } 113 114 static class AppWidgetId { 115 int appWidgetId; 116 Provider provider; 117 RemoteViews views; 118 Host host; 119 } 120 121 /** 122 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. 123 * This needs to be a static inner class since a reference to the ServiceConnection is held 124 * globally and may lead us to leak AppWidgetService instances (if there were more than one). 125 */ 126 static class ServiceConnectionProxy implements ServiceConnection { 127 private final Pair<Integer, Intent.FilterComparison> mKey; 128 private final IBinder mConnectionCb; 129 130 ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) { 131 mKey = key; 132 mConnectionCb = connectionCb; 133 } 134 public void onServiceConnected(ComponentName name, IBinder service) { 135 final IRemoteViewsAdapterConnection cb = 136 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb); 137 try { 138 cb.onServiceConnected(service); 139 } catch (Exception e) { 140 e.printStackTrace(); 141 } 142 } 143 public void onServiceDisconnected(ComponentName name) { 144 disconnect(); 145 } 146 public void disconnect() { 147 final IRemoteViewsAdapterConnection cb = 148 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb); 149 try { 150 cb.onServiceDisconnected(); 151 } catch (Exception e) { 152 e.printStackTrace(); 153 } 154 } 155 } 156 157 // Manages active connections to RemoteViewsServices 158 private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> 159 mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>(); 160 // Manages persistent references to RemoteViewsServices from different App Widgets 161 private final HashMap<FilterComparison, HashSet<Integer>> 162 mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>(); 163 164 Context mContext; 165 Locale mLocale; 166 PackageManager mPackageManager; 167 AlarmManager mAlarmManager; 168 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>(); 169 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; 170 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>(); 171 ArrayList<Host> mHosts = new ArrayList<Host>(); 172 boolean mSafeMode; 173 boolean mStateLoaded; 174 175 AppWidgetService(Context context) { 176 mContext = context; 177 mPackageManager = context.getPackageManager(); 178 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 179 } 180 181 public void systemReady(boolean safeMode) { 182 mSafeMode = safeMode; 183 184 synchronized (mAppWidgetIds) { 185 ensureStateLoadedLocked(); 186 } 187 188 // Register for the boot completed broadcast, so we can send the 189 // ENABLE broacasts. If we try to send them now, they time out, 190 // because the system isn't ready to handle them yet. 191 mContext.registerReceiver(mBroadcastReceiver, 192 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 193 194 // Register for configuration changes so we can update the names 195 // of the widgets when the locale changes. 196 mContext.registerReceiver(mBroadcastReceiver, 197 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); 198 199 // Register for broadcasts about package install, etc., so we can 200 // update the provider list. 201 IntentFilter filter = new IntentFilter(); 202 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 203 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 204 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 205 filter.addDataScheme("package"); 206 mContext.registerReceiver(mBroadcastReceiver, filter); 207 // Register for events related to sdcard installation. 208 IntentFilter sdFilter = new IntentFilter(); 209 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 210 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 211 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 212 } 213 214 private void ensureStateLoadedLocked() { 215 if (!mStateLoaded) { 216 loadAppWidgetList(); 217 loadStateLocked(); 218 mStateLoaded = true; 219 } 220 } 221 222 @Override 223 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 224 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 225 != PackageManager.PERMISSION_GRANTED) { 226 pw.println("Permission Denial: can't dump from from pid=" 227 + Binder.getCallingPid() 228 + ", uid=" + Binder.getCallingUid()); 229 return; 230 } 231 232 synchronized (mAppWidgetIds) { 233 int N = mInstalledProviders.size(); 234 pw.println("Providers:"); 235 for (int i=0; i<N; i++) { 236 Provider p = mInstalledProviders.get(i); 237 AppWidgetProviderInfo info = p.info; 238 pw.print(" ["); pw.print(i); pw.print("] provider "); 239 pw.print(info.provider.flattenToShortString()); 240 pw.println(':'); 241 pw.print(" min=("); pw.print(info.minWidth); 242 pw.print("x"); pw.print(info.minHeight); 243 pw.print(") minResize=("); pw.print(info.minResizeWidth); 244 pw.print("x"); pw.print(info.minResizeHeight); 245 pw.print(") updatePeriodMillis="); 246 pw.print(info.updatePeriodMillis); 247 pw.print(" resizeMode="); 248 pw.print(info.resizeMode); 249 pw.print(" autoAdvanceViewId="); 250 pw.print(info.autoAdvanceViewId); 251 pw.print(" initialLayout=#"); 252 pw.print(Integer.toHexString(info.initialLayout)); 253 pw.print(" zombie="); pw.println(p.zombie); 254 } 255 256 N = mAppWidgetIds.size(); 257 pw.println(" "); 258 pw.println("AppWidgetIds:"); 259 for (int i=0; i<N; i++) { 260 AppWidgetId id = mAppWidgetIds.get(i); 261 pw.print(" ["); pw.print(i); pw.print("] id="); 262 pw.println(id.appWidgetId); 263 pw.print(" hostId="); 264 pw.print(id.host.hostId); pw.print(' '); 265 pw.print(id.host.packageName); pw.print('/'); 266 pw.println(id.host.uid); 267 if (id.provider != null) { 268 pw.print(" provider="); 269 pw.println(id.provider.info.provider.flattenToShortString()); 270 } 271 if (id.host != null) { 272 pw.print(" host.callbacks="); pw.println(id.host.callbacks); 273 } 274 if (id.views != null) { 275 pw.print(" views="); pw.println(id.views); 276 } 277 } 278 279 N = mHosts.size(); 280 pw.println(" "); 281 pw.println("Hosts:"); 282 for (int i=0; i<N; i++) { 283 Host host = mHosts.get(i); 284 pw.print(" ["); pw.print(i); pw.print("] hostId="); 285 pw.print(host.hostId); pw.print(' '); 286 pw.print(host.packageName); pw.print('/'); 287 pw.print(host.uid); pw.println(':'); 288 pw.print(" callbacks="); pw.println(host.callbacks); 289 pw.print(" instances.size="); pw.print(host.instances.size()); 290 pw.print(" zombie="); pw.println(host.zombie); 291 } 292 } 293 } 294 295 public int allocateAppWidgetId(String packageName, int hostId) { 296 int callingUid = enforceCallingUid(packageName); 297 synchronized (mAppWidgetIds) { 298 ensureStateLoadedLocked(); 299 int appWidgetId = mNextAppWidgetId++; 300 301 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 302 303 AppWidgetId id = new AppWidgetId(); 304 id.appWidgetId = appWidgetId; 305 id.host = host; 306 307 host.instances.add(id); 308 mAppWidgetIds.add(id); 309 310 saveStateLocked(); 311 312 return appWidgetId; 313 } 314 } 315 316 public void deleteAppWidgetId(int appWidgetId) { 317 synchronized (mAppWidgetIds) { 318 ensureStateLoadedLocked(); 319 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 320 if (id != null) { 321 deleteAppWidgetLocked(id); 322 saveStateLocked(); 323 } 324 } 325 } 326 327 public void deleteHost(int hostId) { 328 synchronized (mAppWidgetIds) { 329 ensureStateLoadedLocked(); 330 int callingUid = getCallingUid(); 331 Host host = lookupHostLocked(callingUid, hostId); 332 if (host != null) { 333 deleteHostLocked(host); 334 saveStateLocked(); 335 } 336 } 337 } 338 339 public void deleteAllHosts() { 340 synchronized (mAppWidgetIds) { 341 ensureStateLoadedLocked(); 342 int callingUid = getCallingUid(); 343 final int N = mHosts.size(); 344 boolean changed = false; 345 for (int i=N-1; i>=0; i--) { 346 Host host = mHosts.get(i); 347 if (host.uid == callingUid) { 348 deleteHostLocked(host); 349 changed = true; 350 } 351 } 352 if (changed) { 353 saveStateLocked(); 354 } 355 } 356 } 357 358 void deleteHostLocked(Host host) { 359 final int N = host.instances.size(); 360 for (int i=N-1; i>=0; i--) { 361 AppWidgetId id = host.instances.get(i); 362 deleteAppWidgetLocked(id); 363 } 364 host.instances.clear(); 365 mHosts.remove(host); 366 // it's gone or going away, abruptly drop the callback connection 367 host.callbacks = null; 368 } 369 370 void deleteAppWidgetLocked(AppWidgetId id) { 371 // We first unbind all services that are bound to this id 372 unbindAppWidgetRemoteViewsServicesLocked(id); 373 374 Host host = id.host; 375 host.instances.remove(id); 376 pruneHostLocked(host); 377 378 mAppWidgetIds.remove(id); 379 380 Provider p = id.provider; 381 if (p != null) { 382 p.instances.remove(id); 383 if (!p.zombie) { 384 // send the broacast saying that this appWidgetId has been deleted 385 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 386 intent.setComponent(p.info.provider); 387 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); 388 mContext.sendBroadcast(intent); 389 if (p.instances.size() == 0) { 390 // cancel the future updates 391 cancelBroadcasts(p); 392 393 // send the broacast saying that the provider is not in use any more 394 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 395 intent.setComponent(p.info.provider); 396 mContext.sendBroadcast(intent); 397 } 398 } 399 } 400 } 401 402 void cancelBroadcasts(Provider p) { 403 if (p.broadcast != null) { 404 mAlarmManager.cancel(p.broadcast); 405 long token = Binder.clearCallingIdentity(); 406 try { 407 p.broadcast.cancel(); 408 } finally { 409 Binder.restoreCallingIdentity(token); 410 } 411 p.broadcast = null; 412 } 413 } 414 415 public void bindAppWidgetId(int appWidgetId, ComponentName provider) { 416 mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, 417 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider); 418 419 final long ident = Binder.clearCallingIdentity(); 420 try { 421 synchronized (mAppWidgetIds) { 422 ensureStateLoadedLocked(); 423 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 424 if (id == null) { 425 throw new IllegalArgumentException("bad appWidgetId"); 426 } 427 if (id.provider != null) { 428 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to " 429 + id.provider.info.provider); 430 } 431 Provider p = lookupProviderLocked(provider); 432 if (p == null) { 433 throw new IllegalArgumentException("not a appwidget provider: " + provider); 434 } 435 if (p.zombie) { 436 throw new IllegalArgumentException("can't bind to a 3rd party provider in" 437 + " safe mode: " + provider); 438 } 439 440 id.provider = p; 441 p.instances.add(id); 442 int instancesSize = p.instances.size(); 443 if (instancesSize == 1) { 444 // tell the provider that it's ready 445 sendEnableIntentLocked(p); 446 } 447 448 // send an update now -- We need this update now, and just for this appWidgetId. 449 // It's less critical when the next one happens, so when we schdule the next one, 450 // we add updatePeriodMillis to its start time. That time will have some slop, 451 // but that's okay. 452 sendUpdateIntentLocked(p, new int[] { appWidgetId }); 453 454 // schedule the future updates 455 registerForBroadcastsLocked(p, getAppWidgetIds(p)); 456 saveStateLocked(); 457 } 458 } finally { 459 Binder.restoreCallingIdentity(ident); 460 } 461 } 462 463 // Binds to a specific RemoteViewsService 464 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { 465 synchronized (mAppWidgetIds) { 466 ensureStateLoadedLocked(); 467 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 468 if (id == null) { 469 throw new IllegalArgumentException("bad appWidgetId"); 470 } 471 final ComponentName componentName = intent.getComponent(); 472 try { 473 final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName, 474 PackageManager.GET_PERMISSIONS); 475 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) { 476 throw new SecurityException("Selected service does not require " 477 + android.Manifest.permission.BIND_REMOTEVIEWS 478 + ": " + componentName); 479 } 480 } catch (PackageManager.NameNotFoundException e) { 481 throw new IllegalArgumentException("Unknown component " + componentName); 482 } 483 484 // If there is already a connection made for this service intent, then disconnect from 485 // that first. (This does not allow multiple connections to the same service under 486 // the same key) 487 ServiceConnectionProxy conn = null; 488 FilterComparison fc = new FilterComparison(intent); 489 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc); 490 if (mBoundRemoteViewsServices.containsKey(key)) { 491 conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 492 conn.disconnect(); 493 mContext.unbindService(conn); 494 mBoundRemoteViewsServices.remove(key); 495 } 496 497 // Bind to the RemoteViewsService (which will trigger a callback to the 498 // RemoteViewsAdapter.onServiceConnected()) 499 final long token = Binder.clearCallingIdentity(); 500 try { 501 conn = new ServiceConnectionProxy(key, connection); 502 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); 503 mBoundRemoteViewsServices.put(key, conn); 504 } finally { 505 Binder.restoreCallingIdentity(token); 506 } 507 508 // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine 509 // when we can call back to the RemoteViewsService later to destroy associated 510 // factories. 511 incrementAppWidgetServiceRefCount(appWidgetId, fc); 512 } 513 } 514 515 // Unbinds from a specific RemoteViewsService 516 public void unbindRemoteViewsService(int appWidgetId, Intent intent) { 517 synchronized (mAppWidgetIds) { 518 ensureStateLoadedLocked(); 519 // Unbind from the RemoteViewsService (which will trigger a callback to the bound 520 // RemoteViewsAdapter) 521 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, 522 new FilterComparison(intent)); 523 if (mBoundRemoteViewsServices.containsKey(key)) { 524 // We don't need to use the appWidgetId until after we are sure there is something 525 // to unbind. Note that this may mask certain issues with apps calling unbind() 526 // more than necessary. 527 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 528 if (id == null) { 529 throw new IllegalArgumentException("bad appWidgetId"); 530 } 531 532 ServiceConnectionProxy conn = 533 (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 534 conn.disconnect(); 535 mContext.unbindService(conn); 536 mBoundRemoteViewsServices.remove(key); 537 } else { 538 Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound"); 539 } 540 } 541 } 542 543 // Unbinds from a RemoteViewsService when we delete an app widget 544 private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) { 545 int appWidgetId = id.appWidgetId; 546 // Unbind all connections to Services bound to this AppWidgetId 547 Iterator<Pair<Integer, Intent.FilterComparison>> it = 548 mBoundRemoteViewsServices.keySet().iterator(); 549 while (it.hasNext()) { 550 final Pair<Integer, Intent.FilterComparison> key = it.next(); 551 if (key.first.intValue() == appWidgetId) { 552 final ServiceConnectionProxy conn = (ServiceConnectionProxy) 553 mBoundRemoteViewsServices.get(key); 554 conn.disconnect(); 555 mContext.unbindService(conn); 556 it.remove(); 557 } 558 } 559 560 // Check if we need to destroy any services (if no other app widgets are 561 // referencing the same service) 562 decrementAppWidgetServiceRefCount(appWidgetId); 563 } 564 565 // Destroys the cached factory on the RemoteViewsService's side related to the specified intent 566 private void destroyRemoteViewsService(final Intent intent) { 567 final ServiceConnection conn = new ServiceConnection() { 568 @Override 569 public void onServiceConnected(ComponentName name, IBinder service) { 570 final IRemoteViewsFactory cb = 571 IRemoteViewsFactory.Stub.asInterface(service); 572 try { 573 cb.onDestroy(intent); 574 } catch (RemoteException e) { 575 e.printStackTrace(); 576 } catch (RuntimeException e) { 577 e.printStackTrace(); 578 } 579 mContext.unbindService(this); 580 } 581 @Override 582 public void onServiceDisconnected(android.content.ComponentName name) { 583 // Do nothing 584 } 585 }; 586 587 // Bind to the service and remove the static intent->factory mapping in the 588 // RemoteViewsService. 589 final long token = Binder.clearCallingIdentity(); 590 try { 591 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); 592 } finally { 593 Binder.restoreCallingIdentity(token); 594 } 595 } 596 597 // Adds to the ref-count for a given RemoteViewsService intent 598 private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) { 599 HashSet<Integer> appWidgetIds = null; 600 if (mRemoteViewsServicesAppWidgets.containsKey(fc)) { 601 appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc); 602 } else { 603 appWidgetIds = new HashSet<Integer>(); 604 mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds); 605 } 606 appWidgetIds.add(appWidgetId); 607 } 608 609 // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if 610 // the ref-count reaches zero. 611 private void decrementAppWidgetServiceRefCount(int appWidgetId) { 612 Iterator<FilterComparison> it = 613 mRemoteViewsServicesAppWidgets.keySet().iterator(); 614 while (it.hasNext()) { 615 final FilterComparison key = it.next(); 616 final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key); 617 if (ids.remove(appWidgetId)) { 618 // If we have removed the last app widget referencing this service, then we 619 // should destroy it and remove it from this set 620 if (ids.isEmpty()) { 621 destroyRemoteViewsService(key.getIntent()); 622 it.remove(); 623 } 624 } 625 } 626 } 627 628 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { 629 synchronized (mAppWidgetIds) { 630 ensureStateLoadedLocked(); 631 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 632 if (id != null && id.provider != null && !id.provider.zombie) { 633 return id.provider.info; 634 } 635 return null; 636 } 637 } 638 639 public RemoteViews getAppWidgetViews(int appWidgetId) { 640 synchronized (mAppWidgetIds) { 641 ensureStateLoadedLocked(); 642 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 643 if (id != null) { 644 return id.views; 645 } 646 return null; 647 } 648 } 649 650 public List<AppWidgetProviderInfo> getInstalledProviders() { 651 synchronized (mAppWidgetIds) { 652 ensureStateLoadedLocked(); 653 final int N = mInstalledProviders.size(); 654 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N); 655 for (int i=0; i<N; i++) { 656 Provider p = mInstalledProviders.get(i); 657 if (!p.zombie) { 658 result.add(p.info); 659 } 660 } 661 return result; 662 } 663 } 664 665 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 666 if (appWidgetIds == null) { 667 return; 668 } 669 if (appWidgetIds.length == 0) { 670 return; 671 } 672 final int N = appWidgetIds.length; 673 674 synchronized (mAppWidgetIds) { 675 ensureStateLoadedLocked(); 676 for (int i=0; i<N; i++) { 677 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 678 updateAppWidgetInstanceLocked(id, views); 679 } 680 } 681 } 682 683 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 684 if (appWidgetIds == null) { 685 return; 686 } 687 if (appWidgetIds.length == 0) { 688 return; 689 } 690 final int N = appWidgetIds.length; 691 692 synchronized (mAppWidgetIds) { 693 ensureStateLoadedLocked(); 694 for (int i=0; i<N; i++) { 695 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 696 updateAppWidgetInstanceLocked(id, views, true); 697 } 698 } 699 } 700 701 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) { 702 if (appWidgetIds == null) { 703 return; 704 } 705 if (appWidgetIds.length == 0) { 706 return; 707 } 708 final int N = appWidgetIds.length; 709 710 synchronized (mAppWidgetIds) { 711 ensureStateLoadedLocked(); 712 for (int i=0; i<N; i++) { 713 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 714 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId); 715 } 716 } 717 } 718 719 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) { 720 synchronized (mAppWidgetIds) { 721 ensureStateLoadedLocked(); 722 Provider p = lookupProviderLocked(provider); 723 if (p == null) { 724 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider); 725 return; 726 } 727 ArrayList<AppWidgetId> instances = p.instances; 728 final int N = instances.size(); 729 for (int i=0; i<N; i++) { 730 AppWidgetId id = instances.get(i); 731 updateAppWidgetInstanceLocked(id, views); 732 } 733 } 734 } 735 736 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) { 737 updateAppWidgetInstanceLocked(id, views, false); 738 } 739 740 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) { 741 // allow for stale appWidgetIds and other badness 742 // lookup also checks that the calling process can access the appWidgetId 743 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 744 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 745 746 // We do not want to save this RemoteViews 747 if (!isPartialUpdate) id.views = views; 748 749 // is anyone listening? 750 if (id.host.callbacks != null) { 751 try { 752 // the lock is held, but this is a oneway call 753 id.host.callbacks.updateAppWidget(id.appWidgetId, views); 754 } catch (RemoteException e) { 755 // It failed; remove the callback. No need to prune because 756 // we know that this host is still referenced by this instance. 757 id.host.callbacks = null; 758 } 759 } 760 } 761 } 762 763 void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) { 764 // allow for stale appWidgetIds and other badness 765 // lookup also checks that the calling process can access the appWidgetId 766 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 767 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 768 // is anyone listening? 769 if (id.host.callbacks != null) { 770 try { 771 // the lock is held, but this is a oneway call 772 id.host.callbacks.viewDataChanged(id.appWidgetId, viewId); 773 } catch (RemoteException e) { 774 // It failed; remove the callback. No need to prune because 775 // we know that this host is still referenced by this instance. 776 id.host.callbacks = null; 777 } 778 } 779 } 780 } 781 782 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, 783 List<RemoteViews> updatedViews) { 784 int callingUid = enforceCallingUid(packageName); 785 synchronized (mAppWidgetIds) { 786 ensureStateLoadedLocked(); 787 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 788 host.callbacks = callbacks; 789 790 updatedViews.clear(); 791 792 ArrayList<AppWidgetId> instances = host.instances; 793 int N = instances.size(); 794 int[] updatedIds = new int[N]; 795 for (int i=0; i<N; i++) { 796 AppWidgetId id = instances.get(i); 797 updatedIds[i] = id.appWidgetId; 798 updatedViews.add(id.views); 799 } 800 return updatedIds; 801 } 802 } 803 804 public void stopListening(int hostId) { 805 synchronized (mAppWidgetIds) { 806 ensureStateLoadedLocked(); 807 Host host = lookupHostLocked(getCallingUid(), hostId); 808 if (host != null) { 809 host.callbacks = null; 810 pruneHostLocked(host); 811 } 812 } 813 } 814 815 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { 816 if (id.host.uid == callingUid) { 817 // Apps hosting the AppWidget have access to it. 818 return true; 819 } 820 if (id.provider != null && id.provider.uid == callingUid) { 821 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound) 822 return true; 823 } 824 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) 825 == PackageManager.PERMISSION_GRANTED) { 826 // Apps that can bind have access to all appWidgetIds. 827 return true; 828 } 829 // Nobody else can access it. 830 return false; 831 } 832 833 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) { 834 int callingUid = getCallingUid(); 835 final int N = mAppWidgetIds.size(); 836 for (int i=0; i<N; i++) { 837 AppWidgetId id = mAppWidgetIds.get(i); 838 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) { 839 return id; 840 } 841 } 842 return null; 843 } 844 845 Provider lookupProviderLocked(ComponentName provider) { 846 final int N = mInstalledProviders.size(); 847 for (int i=0; i<N; i++) { 848 Provider p = mInstalledProviders.get(i); 849 if (p.info.provider.equals(provider)) { 850 return p; 851 } 852 } 853 return null; 854 } 855 856 Host lookupHostLocked(int uid, int hostId) { 857 final int N = mHosts.size(); 858 for (int i=0; i<N; i++) { 859 Host h = mHosts.get(i); 860 if (h.uid == uid && h.hostId == hostId) { 861 return h; 862 } 863 } 864 return null; 865 } 866 867 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) { 868 final int N = mHosts.size(); 869 for (int i=0; i<N; i++) { 870 Host h = mHosts.get(i); 871 if (h.hostId == hostId && h.packageName.equals(packageName)) { 872 return h; 873 } 874 } 875 Host host = new Host(); 876 host.packageName = packageName; 877 host.uid = uid; 878 host.hostId = hostId; 879 mHosts.add(host); 880 return host; 881 } 882 883 void pruneHostLocked(Host host) { 884 if (host.instances.size() == 0 && host.callbacks == null) { 885 mHosts.remove(host); 886 } 887 } 888 889 void loadAppWidgetList() { 890 PackageManager pm = mPackageManager; 891 892 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 893 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent, 894 PackageManager.GET_META_DATA); 895 896 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 897 for (int i=0; i<N; i++) { 898 ResolveInfo ri = broadcastReceivers.get(i); 899 addProviderLocked(ri); 900 } 901 } 902 903 boolean addProviderLocked(ResolveInfo ri) { 904 if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 905 return false; 906 } 907 if (!ri.activityInfo.isEnabled()) { 908 return false; 909 } 910 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, 911 ri.activityInfo.name), ri); 912 if (p != null) { 913 mInstalledProviders.add(p); 914 return true; 915 } else { 916 return false; 917 } 918 } 919 920 void removeProviderLocked(int index, Provider p) { 921 int N = p.instances.size(); 922 for (int i=0; i<N; i++) { 923 AppWidgetId id = p.instances.get(i); 924 // Call back with empty RemoteViews 925 updateAppWidgetInstanceLocked(id, null); 926 // Stop telling the host about updates for this from now on 927 cancelBroadcasts(p); 928 // clear out references to this appWidgetId 929 id.host.instances.remove(id); 930 mAppWidgetIds.remove(id); 931 id.provider = null; 932 pruneHostLocked(id.host); 933 id.host = null; 934 } 935 p.instances.clear(); 936 mInstalledProviders.remove(index); 937 // no need to send the DISABLE broadcast, since the receiver is gone anyway 938 cancelBroadcasts(p); 939 } 940 941 void sendEnableIntentLocked(Provider p) { 942 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 943 intent.setComponent(p.info.provider); 944 mContext.sendBroadcast(intent); 945 } 946 947 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { 948 if (appWidgetIds != null && appWidgetIds.length > 0) { 949 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 950 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 951 intent.setComponent(p.info.provider); 952 mContext.sendBroadcast(intent); 953 } 954 } 955 956 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) { 957 if (p.info.updatePeriodMillis > 0) { 958 // if this is the first instance, set the alarm. otherwise, 959 // rely on the fact that we've already set it and that 960 // PendingIntent.getBroadcast will update the extras. 961 boolean alreadyRegistered = p.broadcast != null; 962 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 963 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 964 intent.setComponent(p.info.provider); 965 long token = Binder.clearCallingIdentity(); 966 try { 967 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent, 968 PendingIntent.FLAG_UPDATE_CURRENT); 969 } finally { 970 Binder.restoreCallingIdentity(token); 971 } 972 if (!alreadyRegistered) { 973 long period = p.info.updatePeriodMillis; 974 if (period < MIN_UPDATE_PERIOD) { 975 period = MIN_UPDATE_PERIOD; 976 } 977 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 978 SystemClock.elapsedRealtime() + period, period, p.broadcast); 979 } 980 } 981 } 982 983 static int[] getAppWidgetIds(Provider p) { 984 int instancesSize = p.instances.size(); 985 int appWidgetIds[] = new int[instancesSize]; 986 for (int i=0; i<instancesSize; i++) { 987 appWidgetIds[i] = p.instances.get(i).appWidgetId; 988 } 989 return appWidgetIds; 990 } 991 992 public int[] getAppWidgetIds(ComponentName provider) { 993 synchronized (mAppWidgetIds) { 994 ensureStateLoadedLocked(); 995 Provider p = lookupProviderLocked(provider); 996 if (p != null && getCallingUid() == p.uid) { 997 return getAppWidgetIds(p); 998 } else { 999 return new int[0]; 1000 } 1001 } 1002 } 1003 1004 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { 1005 Provider p = null; 1006 1007 ActivityInfo activityInfo = ri.activityInfo; 1008 XmlResourceParser parser = null; 1009 try { 1010 parser = activityInfo.loadXmlMetaData(mPackageManager, 1011 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 1012 if (parser == null) { 1013 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for " 1014 + "AppWidget provider '" + component + '\''); 1015 return null; 1016 } 1017 1018 AttributeSet attrs = Xml.asAttributeSet(parser); 1019 1020 int type; 1021 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1022 && type != XmlPullParser.START_TAG) { 1023 // drain whitespace, comments, etc. 1024 } 1025 1026 String nodeName = parser.getName(); 1027 if (!"appwidget-provider".equals(nodeName)) { 1028 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 1029 + " AppWidget provider '" + component + '\''); 1030 return null; 1031 } 1032 1033 p = new Provider(); 1034 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo(); 1035 info.provider = component; 1036 p.uid = activityInfo.applicationInfo.uid; 1037 1038 Resources res = mPackageManager.getResourcesForApplication( 1039 activityInfo.applicationInfo); 1040 1041 TypedArray sa = res.obtainAttributes(attrs, 1042 com.android.internal.R.styleable.AppWidgetProviderInfo); 1043 1044 // These dimensions has to be resolved in the application's context. 1045 // We simply send back the raw complex data, which will be 1046 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 1047 TypedValue value = sa.peekValue( 1048 com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 1049 info.minWidth = value != null ? value.data : 0; 1050 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 1051 info.minHeight = value != null ? value.data : 0; 1052 value = sa.peekValue( 1053 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); 1054 info.minResizeWidth = value != null ? value.data : info.minWidth; 1055 value = sa.peekValue( 1056 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); 1057 info.minResizeHeight = value != null ? value.data : info.minHeight; 1058 1059 info.updatePeriodMillis = sa.getInt( 1060 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 1061 info.initialLayout = sa.getResourceId( 1062 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 1063 String className = sa.getString( 1064 com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 1065 if (className != null) { 1066 info.configure = new ComponentName(component.getPackageName(), className); 1067 } 1068 info.label = activityInfo.loadLabel(mPackageManager).toString(); 1069 info.icon = ri.getIconResource(); 1070 info.previewImage = sa.getResourceId( 1071 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); 1072 info.autoAdvanceViewId = sa.getResourceId( 1073 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); 1074 info.resizeMode = sa.getInt( 1075 com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, 1076 AppWidgetProviderInfo.RESIZE_NONE); 1077 1078 sa.recycle(); 1079 } catch (Exception e) { 1080 // Ok to catch Exception here, because anything going wrong because 1081 // of what a client process passes to us should not be fatal for the 1082 // system process. 1083 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e); 1084 return null; 1085 } finally { 1086 if (parser != null) parser.close(); 1087 } 1088 return p; 1089 } 1090 1091 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { 1092 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0); 1093 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 1094 throw new PackageManager.NameNotFoundException(); 1095 } 1096 return pkgInfo.applicationInfo.uid; 1097 } 1098 1099 int enforceCallingUid(String packageName) throws IllegalArgumentException { 1100 int callingUid = getCallingUid(); 1101 int packageUid; 1102 try { 1103 packageUid = getUidForPackage(packageName); 1104 } catch (PackageManager.NameNotFoundException ex) { 1105 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1106 + packageName); 1107 } 1108 if (callingUid != packageUid) { 1109 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1110 + packageName); 1111 } 1112 return callingUid; 1113 } 1114 1115 void sendInitialBroadcasts() { 1116 synchronized (mAppWidgetIds) { 1117 ensureStateLoadedLocked(); 1118 final int N = mInstalledProviders.size(); 1119 for (int i=0; i<N; i++) { 1120 Provider p = mInstalledProviders.get(i); 1121 if (p.instances.size() > 0) { 1122 sendEnableIntentLocked(p); 1123 int[] appWidgetIds = getAppWidgetIds(p); 1124 sendUpdateIntentLocked(p, appWidgetIds); 1125 registerForBroadcastsLocked(p, appWidgetIds); 1126 } 1127 } 1128 } 1129 } 1130 1131 // only call from initialization -- it assumes that the data structures are all empty 1132 void loadStateLocked() { 1133 File temp = savedStateTempFile(); 1134 File real = savedStateRealFile(); 1135 1136 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the 1137 // real one. if there is both a real file and a temp one, assume that the temp one isn't 1138 // fully written and delete it. 1139 if (real.exists()) { 1140 readStateFromFileLocked(real); 1141 if (temp.exists()) { 1142 //noinspection ResultOfMethodCallIgnored 1143 temp.delete(); 1144 } 1145 } else if (temp.exists()) { 1146 readStateFromFileLocked(temp); 1147 //noinspection ResultOfMethodCallIgnored 1148 temp.renameTo(real); 1149 } 1150 } 1151 1152 void saveStateLocked() { 1153 File temp = savedStateTempFile(); 1154 File real = savedStateRealFile(); 1155 1156 if (!real.exists()) { 1157 // If the real one doesn't exist, it's either because this is the first time 1158 // or because something went wrong while copying them. In this case, we can't 1159 // trust anything that's in temp. In order to have the loadState code not 1160 // use the temporary one until it's fully written, create an empty file 1161 // for real, which will we'll shortly delete. 1162 try { 1163 //noinspection ResultOfMethodCallIgnored 1164 real.createNewFile(); 1165 } catch (IOException e) { 1166 // Ignore 1167 } 1168 } 1169 1170 if (temp.exists()) { 1171 //noinspection ResultOfMethodCallIgnored 1172 temp.delete(); 1173 } 1174 1175 if (!writeStateToFileLocked(temp)) { 1176 Slog.w(TAG, "Failed to persist new settings"); 1177 return; 1178 } 1179 1180 //noinspection ResultOfMethodCallIgnored 1181 real.delete(); 1182 //noinspection ResultOfMethodCallIgnored 1183 temp.renameTo(real); 1184 } 1185 1186 boolean writeStateToFileLocked(File file) { 1187 FileOutputStream stream = null; 1188 int N; 1189 1190 try { 1191 stream = new FileOutputStream(file, false); 1192 XmlSerializer out = new FastXmlSerializer(); 1193 out.setOutput(stream, "utf-8"); 1194 out.startDocument(null, true); 1195 1196 1197 out.startTag(null, "gs"); 1198 1199 int providerIndex = 0; 1200 N = mInstalledProviders.size(); 1201 for (int i=0; i<N; i++) { 1202 Provider p = mInstalledProviders.get(i); 1203 if (p.instances.size() > 0) { 1204 out.startTag(null, "p"); 1205 out.attribute(null, "pkg", p.info.provider.getPackageName()); 1206 out.attribute(null, "cl", p.info.provider.getClassName()); 1207 out.endTag(null, "p"); 1208 p.tag = providerIndex; 1209 providerIndex++; 1210 } 1211 } 1212 1213 N = mHosts.size(); 1214 for (int i=0; i<N; i++) { 1215 Host host = mHosts.get(i); 1216 out.startTag(null, "h"); 1217 out.attribute(null, "pkg", host.packageName); 1218 out.attribute(null, "id", Integer.toHexString(host.hostId)); 1219 out.endTag(null, "h"); 1220 host.tag = i; 1221 } 1222 1223 N = mAppWidgetIds.size(); 1224 for (int i=0; i<N; i++) { 1225 AppWidgetId id = mAppWidgetIds.get(i); 1226 out.startTag(null, "g"); 1227 out.attribute(null, "id", Integer.toHexString(id.appWidgetId)); 1228 out.attribute(null, "h", Integer.toHexString(id.host.tag)); 1229 if (id.provider != null) { 1230 out.attribute(null, "p", Integer.toHexString(id.provider.tag)); 1231 } 1232 out.endTag(null, "g"); 1233 } 1234 1235 out.endTag(null, "gs"); 1236 1237 out.endDocument(); 1238 stream.close(); 1239 return true; 1240 } catch (IOException e) { 1241 try { 1242 if (stream != null) { 1243 stream.close(); 1244 } 1245 } catch (IOException ex) { 1246 // Ignore 1247 } 1248 if (file.exists()) { 1249 //noinspection ResultOfMethodCallIgnored 1250 file.delete(); 1251 } 1252 return false; 1253 } 1254 } 1255 1256 void readStateFromFileLocked(File file) { 1257 FileInputStream stream = null; 1258 1259 boolean success = false; 1260 1261 try { 1262 stream = new FileInputStream(file); 1263 XmlPullParser parser = Xml.newPullParser(); 1264 parser.setInput(stream, null); 1265 1266 int type; 1267 int providerIndex = 0; 1268 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>(); 1269 do { 1270 type = parser.next(); 1271 if (type == XmlPullParser.START_TAG) { 1272 String tag = parser.getName(); 1273 if ("p".equals(tag)) { 1274 // TODO: do we need to check that this package has the same signature 1275 // as before? 1276 String pkg = parser.getAttributeValue(null, "pkg"); 1277 String cl = parser.getAttributeValue(null, "cl"); 1278 1279 final PackageManager packageManager = mContext.getPackageManager(); 1280 try { 1281 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0); 1282 } catch (PackageManager.NameNotFoundException e) { 1283 String[] pkgs = packageManager.currentToCanonicalPackageNames( 1284 new String[] { pkg }); 1285 pkg = pkgs[0]; 1286 } 1287 1288 Provider p = lookupProviderLocked(new ComponentName(pkg, cl)); 1289 if (p == null && mSafeMode) { 1290 // if we're in safe mode, make a temporary one 1291 p = new Provider(); 1292 p.info = new AppWidgetProviderInfo(); 1293 p.info.provider = new ComponentName(pkg, cl); 1294 p.zombie = true; 1295 mInstalledProviders.add(p); 1296 } 1297 if (p != null) { 1298 // if it wasn't uninstalled or something 1299 loadedProviders.put(providerIndex, p); 1300 } 1301 providerIndex++; 1302 } 1303 else if ("h".equals(tag)) { 1304 Host host = new Host(); 1305 1306 // TODO: do we need to check that this package has the same signature 1307 // as before? 1308 host.packageName = parser.getAttributeValue(null, "pkg"); 1309 try { 1310 host.uid = getUidForPackage(host.packageName); 1311 } catch (PackageManager.NameNotFoundException ex) { 1312 host.zombie = true; 1313 } 1314 if (!host.zombie || mSafeMode) { 1315 // In safe mode, we don't discard the hosts we don't recognize 1316 // so that they're not pruned from our list. Otherwise, we do. 1317 host.hostId = Integer.parseInt( 1318 parser.getAttributeValue(null, "id"), 16); 1319 mHosts.add(host); 1320 } 1321 } 1322 else if ("g".equals(tag)) { 1323 AppWidgetId id = new AppWidgetId(); 1324 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16); 1325 if (id.appWidgetId >= mNextAppWidgetId) { 1326 mNextAppWidgetId = id.appWidgetId + 1; 1327 } 1328 1329 String providerString = parser.getAttributeValue(null, "p"); 1330 if (providerString != null) { 1331 // there's no provider if it hasn't been bound yet. 1332 // maybe we don't have to save this, but it brings the system 1333 // to the state it was in. 1334 int pIndex = Integer.parseInt(providerString, 16); 1335 id.provider = loadedProviders.get(pIndex); 1336 if (false) { 1337 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider " 1338 + pIndex + " which is " + id.provider); 1339 } 1340 if (id.provider == null) { 1341 // This provider is gone. We just let the host figure out 1342 // that this happened when it fails to load it. 1343 continue; 1344 } 1345 } 1346 1347 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16); 1348 id.host = mHosts.get(hIndex); 1349 if (id.host == null) { 1350 // This host is gone. 1351 continue; 1352 } 1353 1354 if (id.provider != null) { 1355 id.provider.instances.add(id); 1356 } 1357 id.host.instances.add(id); 1358 mAppWidgetIds.add(id); 1359 } 1360 } 1361 } while (type != XmlPullParser.END_DOCUMENT); 1362 success = true; 1363 } catch (NullPointerException e) { 1364 Slog.w(TAG, "failed parsing " + file, e); 1365 } catch (NumberFormatException e) { 1366 Slog.w(TAG, "failed parsing " + file, e); 1367 } catch (XmlPullParserException e) { 1368 Slog.w(TAG, "failed parsing " + file, e); 1369 } catch (IOException e) { 1370 Slog.w(TAG, "failed parsing " + file, e); 1371 } catch (IndexOutOfBoundsException e) { 1372 Slog.w(TAG, "failed parsing " + file, e); 1373 } 1374 try { 1375 if (stream != null) { 1376 stream.close(); 1377 } 1378 } catch (IOException e) { 1379 // Ignore 1380 } 1381 1382 if (success) { 1383 // delete any hosts that didn't manage to get connected (should happen) 1384 // if it matters, they'll be reconnected. 1385 for (int i=mHosts.size()-1; i>=0; i--) { 1386 pruneHostLocked(mHosts.get(i)); 1387 } 1388 } else { 1389 // failed reading, clean up 1390 mAppWidgetIds.clear(); 1391 mHosts.clear(); 1392 final int N = mInstalledProviders.size(); 1393 for (int i=0; i<N; i++) { 1394 mInstalledProviders.get(i).instances.clear(); 1395 } 1396 } 1397 } 1398 1399 File savedStateTempFile() { 1400 return new File("/data/system/" + SETTINGS_TMP_FILENAME); 1401 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME); 1402 } 1403 1404 File savedStateRealFile() { 1405 return new File("/data/system/" + SETTINGS_FILENAME); 1406 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME); 1407 } 1408 1409 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1410 public void onReceive(Context context, Intent intent) { 1411 String action = intent.getAction(); 1412 //Slog.d(TAG, "received " + action); 1413 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 1414 sendInitialBroadcasts(); 1415 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 1416 Locale revised = Locale.getDefault(); 1417 if (revised == null || mLocale == null || 1418 !(revised.equals(mLocale))) { 1419 mLocale = revised; 1420 1421 synchronized (mAppWidgetIds) { 1422 ensureStateLoadedLocked(); 1423 int N = mInstalledProviders.size(); 1424 for (int i=N-1; i>=0; i--) { 1425 Provider p = mInstalledProviders.get(i); 1426 String pkgName = p.info.provider.getPackageName(); 1427 updateProvidersForPackageLocked(pkgName); 1428 } 1429 saveStateLocked(); 1430 } 1431 } 1432 } else { 1433 boolean added = false; 1434 boolean changed = false; 1435 String pkgList[] = null; 1436 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 1437 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1438 added = true; 1439 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1440 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1441 added = false; 1442 } else { 1443 Uri uri = intent.getData(); 1444 if (uri == null) { 1445 return; 1446 } 1447 String pkgName = uri.getSchemeSpecificPart(); 1448 if (pkgName == null) { 1449 return; 1450 } 1451 pkgList = new String[] { pkgName }; 1452 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 1453 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 1454 } 1455 if (pkgList == null || pkgList.length == 0) { 1456 return; 1457 } 1458 if (added || changed) { 1459 synchronized (mAppWidgetIds) { 1460 ensureStateLoadedLocked(); 1461 Bundle extras = intent.getExtras(); 1462 if (changed || (extras != null && 1463 extras.getBoolean(Intent.EXTRA_REPLACING, false))) { 1464 for (String pkgName : pkgList) { 1465 // The package was just upgraded 1466 updateProvidersForPackageLocked(pkgName); 1467 } 1468 } else { 1469 // The package was just added 1470 for (String pkgName : pkgList) { 1471 addProvidersForPackageLocked(pkgName); 1472 } 1473 } 1474 saveStateLocked(); 1475 } 1476 } else { 1477 Bundle extras = intent.getExtras(); 1478 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { 1479 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 1480 } else { 1481 synchronized (mAppWidgetIds) { 1482 ensureStateLoadedLocked(); 1483 for (String pkgName : pkgList) { 1484 removeProvidersForPackageLocked(pkgName); 1485 saveStateLocked(); 1486 } 1487 } 1488 } 1489 } 1490 } 1491 } 1492 }; 1493 1494 void addProvidersForPackageLocked(String pkgName) { 1495 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1496 intent.setPackage(pkgName); 1497 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1498 PackageManager.GET_META_DATA); 1499 1500 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1501 for (int i=0; i<N; i++) { 1502 ResolveInfo ri = broadcastReceivers.get(i); 1503 ActivityInfo ai = ri.activityInfo; 1504 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1505 continue; 1506 } 1507 if (pkgName.equals(ai.packageName)) { 1508 addProviderLocked(ri); 1509 } 1510 } 1511 } 1512 1513 void updateProvidersForPackageLocked(String pkgName) { 1514 HashSet<String> keep = new HashSet<String>(); 1515 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1516 intent.setPackage(pkgName); 1517 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1518 PackageManager.GET_META_DATA); 1519 1520 // add the missing ones and collect which ones to keep 1521 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1522 for (int i=0; i<N; i++) { 1523 ResolveInfo ri = broadcastReceivers.get(i); 1524 ActivityInfo ai = ri.activityInfo; 1525 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1526 continue; 1527 } 1528 if (pkgName.equals(ai.packageName)) { 1529 ComponentName component = new ComponentName(ai.packageName, ai.name); 1530 Provider p = lookupProviderLocked(component); 1531 if (p == null) { 1532 if (addProviderLocked(ri)) { 1533 keep.add(ai.name); 1534 } 1535 } else { 1536 Provider parsed = parseProviderInfoXml(component, ri); 1537 if (parsed != null) { 1538 keep.add(ai.name); 1539 // Use the new AppWidgetProviderInfo. 1540 p.info = parsed.info; 1541 // If it's enabled 1542 final int M = p.instances.size(); 1543 if (M > 0) { 1544 int[] appWidgetIds = getAppWidgetIds(p); 1545 // Reschedule for the new updatePeriodMillis (don't worry about handling 1546 // it specially if updatePeriodMillis didn't change because we just sent 1547 // an update, and the next one will be updatePeriodMillis from now). 1548 cancelBroadcasts(p); 1549 registerForBroadcastsLocked(p, appWidgetIds); 1550 // If it's currently showing, call back with the new AppWidgetProviderInfo. 1551 for (int j=0; j<M; j++) { 1552 AppWidgetId id = p.instances.get(j); 1553 id.views = null; 1554 if (id.host != null && id.host.callbacks != null) { 1555 try { 1556 id.host.callbacks.providerChanged(id.appWidgetId, p.info); 1557 } catch (RemoteException ex) { 1558 // It failed; remove the callback. No need to prune because 1559 // we know that this host is still referenced by this 1560 // instance. 1561 id.host.callbacks = null; 1562 } 1563 } 1564 } 1565 // Now that we've told the host, push out an update. 1566 sendUpdateIntentLocked(p, appWidgetIds); 1567 } 1568 } 1569 } 1570 } 1571 } 1572 1573 // prune the ones we don't want to keep 1574 N = mInstalledProviders.size(); 1575 for (int i=N-1; i>=0; i--) { 1576 Provider p = mInstalledProviders.get(i); 1577 if (pkgName.equals(p.info.provider.getPackageName()) 1578 && !keep.contains(p.info.provider.getClassName())) { 1579 removeProviderLocked(i, p); 1580 } 1581 } 1582 } 1583 1584 void removeProvidersForPackageLocked(String pkgName) { 1585 int N = mInstalledProviders.size(); 1586 for (int i=N-1; i>=0; i--) { 1587 Provider p = mInstalledProviders.get(i); 1588 if (pkgName.equals(p.info.provider.getPackageName())) { 1589 removeProviderLocked(i, p); 1590 } 1591 } 1592 1593 // Delete the hosts for this package too 1594 // 1595 // By now, we have removed any AppWidgets that were in any hosts here, 1596 // so we don't need to worry about sending DISABLE broadcasts to them. 1597 N = mHosts.size(); 1598 for (int i=N-1; i>=0; i--) { 1599 Host host = mHosts.get(i); 1600 if (pkgName.equals(host.packageName)) { 1601 deleteHostLocked(host); 1602 } 1603 } 1604 } 1605} 1606 1607