blob: 5ef3d35ceffbff3e21b9fbfe836c3162e877d98b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070021import android.appwidget.AppWidgetManager;
22import android.appwidget.AppWidgetProviderInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.ActivityInfo;
Joe Onorato331fbdc72010-08-24 17:02:09 -040029import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.pm.PackageManager;
31import android.content.pm.PackageInfo;
32import android.content.pm.ResolveInfo;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -080033import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.content.res.TypedArray;
35import android.content.res.XmlResourceParser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.net.Uri;
37import android.os.Binder;
38import android.os.Bundle;
Marco Nelissen54796e72009-04-30 15:16:30 -070039import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.RemoteException;
41import android.os.SystemClock;
42import android.util.AttributeSet;
Joe Onorato8a9b2202010-02-26 18:56:32 -080043import android.util.Slog;
Mitsuru Oshima8f25c422009-07-01 00:10:43 -070044import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.util.Xml;
46import android.widget.RemoteViews;
47
48import java.io.IOException;
49import java.io.File;
50import java.io.FileDescriptor;
51import java.io.FileInputStream;
52import java.io.FileOutputStream;
53import java.io.PrintWriter;
54import java.util.ArrayList;
55import java.util.List;
Eric Fischer63c2d9e2009-10-22 15:22:50 -070056import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import java.util.HashMap;
58import java.util.HashSet;
59
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070060import com.android.internal.appwidget.IAppWidgetService;
61import com.android.internal.appwidget.IAppWidgetHost;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080062import com.android.internal.util.FastXmlSerializer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64import org.xmlpull.v1.XmlPullParser;
65import org.xmlpull.v1.XmlPullParserException;
66import org.xmlpull.v1.XmlSerializer;
67
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070068class AppWidgetService extends IAppWidgetService.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069{
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070070 private static final String TAG = "AppWidgetService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070072 private static final String SETTINGS_FILENAME = "appwidgets.xml";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
Joe Onoratobe96b3a2009-07-14 19:49:27 -070074 private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075
76 /*
77 * When identifying a Host or Provider based on the calling process, use the uid field.
78 * When identifying a Host or Provider based on a package manager broadcast, use the
79 * package given.
80 */
81
82 static class Provider {
83 int uid;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070084 AppWidgetProviderInfo info;
Romain Guya5475592009-07-01 17:20:08 -070085 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 PendingIntent broadcast;
87 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
88
89 int tag; // for use while saving state (the index)
90 }
91
92 static class Host {
93 int uid;
94 int hostId;
95 String packageName;
Romain Guya5475592009-07-01 17:20:08 -070096 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070097 IAppWidgetHost callbacks;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 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
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700103 static class AppWidgetId {
104 int appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 Provider provider;
106 RemoteViews views;
107 Host host;
108 }
109
110 Context mContext;
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700111 Locale mLocale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 PackageManager mPackageManager;
113 AlarmManager mAlarmManager;
Romain Guya5475592009-07-01 17:20:08 -0700114 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700115 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
Romain Guya5475592009-07-01 17:20:08 -0700116 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
117 ArrayList<Host> mHosts = new ArrayList<Host>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 boolean mSafeMode;
119
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700120 AppWidgetService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 mContext = context;
122 mPackageManager = context.getPackageManager();
123 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
124 }
125
126 public void systemReady(boolean safeMode) {
127 mSafeMode = safeMode;
128
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700129 loadAppWidgetList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 loadStateLocked();
131
132 // Register for the boot completed broadcast, so we can send the
133 // ENABLE broacasts. If we try to send them now, they time out,
134 // because the system isn't ready to handle them yet.
135 mContext.registerReceiver(mBroadcastReceiver,
136 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
137
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700138 // Register for configuration changes so we can update the names
139 // of the widgets when the locale changes.
140 mContext.registerReceiver(mBroadcastReceiver,
141 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 // Register for broadcasts about package install, etc., so we can
144 // update the provider list.
145 IntentFilter filter = new IntentFilter();
146 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
147 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
148 filter.addDataScheme("package");
149 mContext.registerReceiver(mBroadcastReceiver, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800150 // Register for events related to sdcard installation.
151 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800152 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
153 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800154 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 }
156
157 @Override
158 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
159 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
160 != PackageManager.PERMISSION_GRANTED) {
161 pw.println("Permission Denial: can't dump from from pid="
162 + Binder.getCallingPid()
163 + ", uid=" + Binder.getCallingUid());
164 return;
165 }
166
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700167 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 int N = mInstalledProviders.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700169 pw.println("Providers:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 for (int i=0; i<N; i++) {
171 Provider p = mInstalledProviders.get(i);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700172 AppWidgetProviderInfo info = p.info;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700173 pw.print(" ["); pw.print(i); pw.print("] provider ");
174 pw.print(info.provider.flattenToShortString());
175 pw.println(':');
176 pw.print(" min=("); pw.print(info.minWidth);
177 pw.print("x"); pw.print(info.minHeight);
178 pw.print(") updatePeriodMillis=");
179 pw.print(info.updatePeriodMillis);
180 pw.print(" initialLayout=#");
181 pw.print(Integer.toHexString(info.initialLayout));
182 pw.print(" zombie="); pw.println(p.zombie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 }
184
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700185 N = mAppWidgetIds.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700186 pw.println(" ");
187 pw.println("AppWidgetIds:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700189 AppWidgetId id = mAppWidgetIds.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700190 pw.print(" ["); pw.print(i); pw.print("] id=");
Romain Guya5475592009-07-01 17:20:08 -0700191 pw.println(id.appWidgetId);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700192 pw.print(" hostId=");
193 pw.print(id.host.hostId); pw.print(' ');
194 pw.print(id.host.packageName); pw.print('/');
195 pw.println(id.host.uid);
196 if (id.provider != null) {
197 pw.print(" provider=");
198 pw.println(id.provider.info.provider.flattenToShortString());
199 }
200 if (id.host != null) {
201 pw.print(" host.callbacks="); pw.println(id.host.callbacks);
202 }
203 if (id.views != null) {
204 pw.print(" views="); pw.println(id.views);
205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 }
207
208 N = mHosts.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700209 pw.println(" ");
210 pw.println("Hosts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 for (int i=0; i<N; i++) {
212 Host host = mHosts.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700213 pw.print(" ["); pw.print(i); pw.print("] hostId=");
214 pw.print(host.hostId); pw.print(' ');
215 pw.print(host.packageName); pw.print('/');
216 pw.print(host.uid); pw.println(':');
217 pw.print(" callbacks="); pw.println(host.callbacks);
218 pw.print(" instances.size="); pw.print(host.instances.size());
219 pw.print(" zombie="); pw.println(host.zombie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221 }
222 }
223
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700224 public int allocateAppWidgetId(String packageName, int hostId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 int callingUid = enforceCallingUid(packageName);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700226 synchronized (mAppWidgetIds) {
227 int appWidgetId = mNextAppWidgetId++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
229 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
230
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700231 AppWidgetId id = new AppWidgetId();
232 id.appWidgetId = appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 id.host = host;
234
235 host.instances.add(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700236 mAppWidgetIds.add(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
238 saveStateLocked();
239
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700240 return appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 }
242 }
243
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700244 public void deleteAppWidgetId(int appWidgetId) {
245 synchronized (mAppWidgetIds) {
246 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 if (id != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700248 deleteAppWidgetLocked(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 saveStateLocked();
250 }
251 }
252 }
253
254 public void deleteHost(int hostId) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700255 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 int callingUid = getCallingUid();
257 Host host = lookupHostLocked(callingUid, hostId);
258 if (host != null) {
259 deleteHostLocked(host);
260 saveStateLocked();
261 }
262 }
263 }
264
265 public void deleteAllHosts() {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700266 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 int callingUid = getCallingUid();
268 final int N = mHosts.size();
269 boolean changed = false;
270 for (int i=N-1; i>=0; i--) {
271 Host host = mHosts.get(i);
272 if (host.uid == callingUid) {
273 deleteHostLocked(host);
274 changed = true;
275 }
276 }
277 if (changed) {
278 saveStateLocked();
279 }
280 }
281 }
282
283 void deleteHostLocked(Host host) {
284 final int N = host.instances.size();
285 for (int i=N-1; i>=0; i--) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700286 AppWidgetId id = host.instances.get(i);
287 deleteAppWidgetLocked(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 }
289 host.instances.clear();
290 mHosts.remove(host);
291 // it's gone or going away, abruptly drop the callback connection
292 host.callbacks = null;
293 }
294
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700295 void deleteAppWidgetLocked(AppWidgetId id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 Host host = id.host;
297 host.instances.remove(id);
298 pruneHostLocked(host);
299
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700300 mAppWidgetIds.remove(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
302 Provider p = id.provider;
303 if (p != null) {
304 p.instances.remove(id);
305 if (!p.zombie) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700306 // send the broacast saying that this appWidgetId has been deleted
307 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 intent.setComponent(p.info.provider);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700309 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 mContext.sendBroadcast(intent);
311 if (p.instances.size() == 0) {
312 // cancel the future updates
313 cancelBroadcasts(p);
314
315 // send the broacast saying that the provider is not in use any more
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700316 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 intent.setComponent(p.info.provider);
318 mContext.sendBroadcast(intent);
319 }
320 }
321 }
322 }
323
324 void cancelBroadcasts(Provider p) {
325 if (p.broadcast != null) {
326 mAlarmManager.cancel(p.broadcast);
327 long token = Binder.clearCallingIdentity();
328 try {
329 p.broadcast.cancel();
330 } finally {
331 Binder.restoreCallingIdentity(token);
332 }
333 p.broadcast = null;
334 }
335 }
336
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700337 public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
338 mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
339 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
340 synchronized (mAppWidgetIds) {
341 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 if (id == null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700343 throw new IllegalArgumentException("bad appWidgetId");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 }
345 if (id.provider != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700346 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 + id.provider.info.provider);
348 }
349 Provider p = lookupProviderLocked(provider);
350 if (p == null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700351 throw new IllegalArgumentException("not a appwidget provider: " + provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 }
353 if (p.zombie) {
354 throw new IllegalArgumentException("can't bind to a 3rd party provider in"
355 + " safe mode: " + provider);
356 }
357
358 id.provider = p;
359 p.instances.add(id);
360 int instancesSize = p.instances.size();
361 if (instancesSize == 1) {
362 // tell the provider that it's ready
363 sendEnableIntentLocked(p);
364 }
365
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700366 // send an update now -- We need this update now, and just for this appWidgetId.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 // It's less critical when the next one happens, so when we schdule the next one,
368 // we add updatePeriodMillis to its start time. That time will have some slop,
369 // but that's okay.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700370 sendUpdateIntentLocked(p, new int[] { appWidgetId });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371
372 // schedule the future updates
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700373 registerForBroadcastsLocked(p, getAppWidgetIds(p));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 saveStateLocked();
375 }
376 }
377
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700378 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
379 synchronized (mAppWidgetIds) {
380 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 if (id != null && id.provider != null && !id.provider.zombie) {
382 return id.provider.info;
383 }
384 return null;
385 }
386 }
387
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700388 public RemoteViews getAppWidgetViews(int appWidgetId) {
389 synchronized (mAppWidgetIds) {
390 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 if (id != null) {
392 return id.views;
393 }
394 return null;
395 }
396 }
397
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700398 public List<AppWidgetProviderInfo> getInstalledProviders() {
399 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 final int N = mInstalledProviders.size();
Romain Guya5475592009-07-01 17:20:08 -0700401 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 for (int i=0; i<N; i++) {
403 Provider p = mInstalledProviders.get(i);
404 if (!p.zombie) {
405 result.add(p.info);
406 }
407 }
408 return result;
409 }
410 }
411
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700412 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
413 if (appWidgetIds == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 return;
415 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700416 if (appWidgetIds.length == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 return;
418 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700419 final int N = appWidgetIds.length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700421 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700423 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
424 updateAppWidgetInstanceLocked(id, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 }
426 }
427 }
428
Adam Cohen2dd21972010-08-15 18:20:04 -0700429 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
430 if (appWidgetIds == null) {
431 return;
432 }
433 if (appWidgetIds.length == 0) {
434 return;
435 }
436 final int N = appWidgetIds.length;
437
438 synchronized (mAppWidgetIds) {
439 for (int i=0; i<N; i++) {
440 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
441 updateAppWidgetInstanceLocked(id, views, true);
442 }
443 }
444 }
445
Winson Chung6394c0e2010-08-16 10:14:56 -0700446 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700447 if (appWidgetIds == null) {
448 return;
449 }
450 if (appWidgetIds.length == 0) {
451 return;
452 }
453 final int N = appWidgetIds.length;
454
455 synchronized (mAppWidgetIds) {
456 for (int i=0; i<N; i++) {
457 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
Winson Chung6394c0e2010-08-16 10:14:56 -0700458 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700459 }
460 }
461 }
462
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700463 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
464 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 Provider p = lookupProviderLocked(provider);
466 if (p == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800467 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 return;
469 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700470 ArrayList<AppWidgetId> instances = p.instances;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 final int N = instances.size();
472 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700473 AppWidgetId id = instances.get(i);
474 updateAppWidgetInstanceLocked(id, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 }
476 }
477 }
478
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700479 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700480 updateAppWidgetInstanceLocked(id, views, false);
481 }
482
483 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700484 // allow for stale appWidgetIds and other badness
485 // lookup also checks that the calling process can access the appWidgetId
486 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700488
489 // We do not want to save this RemoteViews
490 if (!isPartialUpdate) id.views = views;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491
492 // is anyone listening?
493 if (id.host.callbacks != null) {
494 try {
495 // the lock is held, but this is a oneway call
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700496 id.host.callbacks.updateAppWidget(id.appWidgetId, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 } catch (RemoteException e) {
498 // It failed; remove the callback. No need to prune because
499 // we know that this host is still referenced by this instance.
500 id.host.callbacks = null;
501 }
502 }
503 }
504 }
505
Winson Chung6394c0e2010-08-16 10:14:56 -0700506 void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700507 // allow for stale appWidgetIds and other badness
508 // lookup also checks that the calling process can access the appWidgetId
509 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
510 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700511 // is anyone listening?
512 if (id.host.callbacks != null) {
513 try {
514 // the lock is held, but this is a oneway call
Winson Chung6394c0e2010-08-16 10:14:56 -0700515 id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700516 } catch (RemoteException e) {
517 // It failed; remove the callback. No need to prune because
518 // we know that this host is still referenced by this instance.
519 id.host.callbacks = null;
520 }
521 }
522 }
523 }
524
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700525 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 List<RemoteViews> updatedViews) {
527 int callingUid = enforceCallingUid(packageName);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700528 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
530 host.callbacks = callbacks;
531
532 updatedViews.clear();
533
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700534 ArrayList<AppWidgetId> instances = host.instances;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 int N = instances.size();
536 int[] updatedIds = new int[N];
537 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700538 AppWidgetId id = instances.get(i);
539 updatedIds[i] = id.appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 updatedViews.add(id.views);
541 }
542 return updatedIds;
543 }
544 }
545
546 public void stopListening(int hostId) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700547 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 Host host = lookupHostLocked(getCallingUid(), hostId);
Ken Shirriffe21167a2009-09-23 16:42:53 -0700549 if (host != null) {
550 host.callbacks = null;
551 pruneHostLocked(host);
552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554 }
555
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700556 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 if (id.host.uid == callingUid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700558 // Apps hosting the AppWidget have access to it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 return true;
560 }
561 if (id.provider != null && id.provider.uid == callingUid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700562 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 return true;
564 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700565 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 == PackageManager.PERMISSION_GRANTED) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700567 // Apps that can bind have access to all appWidgetIds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 return true;
569 }
570 // Nobody else can access it.
571 return false;
572 }
573
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700574 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 int callingUid = getCallingUid();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700576 final int N = mAppWidgetIds.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700578 AppWidgetId id = mAppWidgetIds.get(i);
579 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 return id;
581 }
582 }
583 return null;
584 }
585
586 Provider lookupProviderLocked(ComponentName provider) {
Romain Guyd2671e12010-03-11 18:06:42 -0800587 final String className = provider.getClassName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 final int N = mInstalledProviders.size();
589 for (int i=0; i<N; i++) {
590 Provider p = mInstalledProviders.get(i);
Romain Guyd2671e12010-03-11 18:06:42 -0800591 if (p.info.provider.equals(provider) || className.equals(p.info.oldName)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 return p;
593 }
594 }
595 return null;
596 }
597
598 Host lookupHostLocked(int uid, int hostId) {
599 final int N = mHosts.size();
600 for (int i=0; i<N; i++) {
601 Host h = mHosts.get(i);
602 if (h.uid == uid && h.hostId == hostId) {
603 return h;
604 }
605 }
606 return null;
607 }
608
609 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
610 final int N = mHosts.size();
611 for (int i=0; i<N; i++) {
612 Host h = mHosts.get(i);
613 if (h.hostId == hostId && h.packageName.equals(packageName)) {
614 return h;
615 }
616 }
617 Host host = new Host();
618 host.packageName = packageName;
619 host.uid = uid;
620 host.hostId = hostId;
621 mHosts.add(host);
622 return host;
623 }
624
625 void pruneHostLocked(Host host) {
626 if (host.instances.size() == 0 && host.callbacks == null) {
627 mHosts.remove(host);
628 }
629 }
630
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700631 void loadAppWidgetList() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 PackageManager pm = mPackageManager;
633
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700634 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
636 PackageManager.GET_META_DATA);
637
Bjorn Bringert5f857802010-02-10 23:09:48 +0000638 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 for (int i=0; i<N; i++) {
640 ResolveInfo ri = broadcastReceivers.get(i);
641 addProviderLocked(ri);
642 }
643 }
644
645 boolean addProviderLocked(ResolveInfo ri) {
646 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
647 ri.activityInfo.name), ri);
648 if (p != null) {
649 mInstalledProviders.add(p);
650 return true;
651 } else {
652 return false;
653 }
654 }
655
656 void removeProviderLocked(int index, Provider p) {
657 int N = p.instances.size();
658 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700659 AppWidgetId id = p.instances.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 // Call back with empty RemoteViews
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700661 updateAppWidgetInstanceLocked(id, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 // Stop telling the host about updates for this from now on
663 cancelBroadcasts(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700664 // clear out references to this appWidgetId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 id.host.instances.remove(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700666 mAppWidgetIds.remove(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 id.provider = null;
668 pruneHostLocked(id.host);
669 id.host = null;
670 }
671 p.instances.clear();
672 mInstalledProviders.remove(index);
673 // no need to send the DISABLE broadcast, since the receiver is gone anyway
674 cancelBroadcasts(p);
675 }
676
677 void sendEnableIntentLocked(Provider p) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700678 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 intent.setComponent(p.info.provider);
680 mContext.sendBroadcast(intent);
681 }
682
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700683 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
684 if (appWidgetIds != null && appWidgetIds.length > 0) {
685 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
686 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 intent.setComponent(p.info.provider);
688 mContext.sendBroadcast(intent);
689 }
690 }
691
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700692 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 if (p.info.updatePeriodMillis > 0) {
694 // if this is the first instance, set the alarm. otherwise,
695 // rely on the fact that we've already set it and that
696 // PendingIntent.getBroadcast will update the extras.
697 boolean alreadyRegistered = p.broadcast != null;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700698 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
699 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 intent.setComponent(p.info.provider);
701 long token = Binder.clearCallingIdentity();
702 try {
703 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
704 PendingIntent.FLAG_UPDATE_CURRENT);
705 } finally {
706 Binder.restoreCallingIdentity(token);
707 }
708 if (!alreadyRegistered) {
Joe Onoratobe96b3a2009-07-14 19:49:27 -0700709 long period = p.info.updatePeriodMillis;
710 if (period < MIN_UPDATE_PERIOD) {
711 period = MIN_UPDATE_PERIOD;
712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Joe Onoratobe96b3a2009-07-14 19:49:27 -0700714 SystemClock.elapsedRealtime() + period, period, p.broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716 }
717 }
718
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700719 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700721 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700723 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700725 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 }
727
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700728 public int[] getAppWidgetIds(ComponentName provider) {
729 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 Provider p = lookupProviderLocked(provider);
731 if (p != null && getCallingUid() == p.uid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700732 return getAppWidgetIds(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 } else {
734 return new int[0];
735 }
736 }
737 }
738
739 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
740 Provider p = null;
741
742 ActivityInfo activityInfo = ri.activityInfo;
743 XmlResourceParser parser = null;
744 try {
745 parser = activityInfo.loadXmlMetaData(mPackageManager,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700746 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 if (parser == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800748 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700749 + "AppWidget provider '" + component + '\'');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 return null;
751 }
752
753 AttributeSet attrs = Xml.asAttributeSet(parser);
754
755 int type;
756 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
757 && type != XmlPullParser.START_TAG) {
758 // drain whitespace, comments, etc.
759 }
760
761 String nodeName = parser.getName();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700762 if (!"appwidget-provider".equals(nodeName)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800763 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700764 + " AppWidget provider '" + component + '\'');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 return null;
766 }
767
768 p = new Provider();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700769 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
Romain Guyd2671e12010-03-11 18:06:42 -0800770 // If metaData was null, we would have returned earlier when getting
771 // the parser No need to do the check here
772 info.oldName = activityInfo.metaData.getString(
773 AppWidgetManager.META_DATA_APPWIDGET_OLD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774
775 info.provider = component;
776 p.uid = activityInfo.applicationInfo.uid;
777
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800778 Resources res = mPackageManager.getResourcesForApplication(
779 activityInfo.applicationInfo);
780
781 TypedArray sa = res.obtainAttributes(attrs,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700782 com.android.internal.R.styleable.AppWidgetProviderInfo);
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700783
784 // These dimensions has to be resolved in the application's context.
785 // We simply send back the raw complex data, which will be
786 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
787 TypedValue value = sa.peekValue(
788 com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
789 info.minWidth = value != null ? value.data : 0;
790 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
791 info.minHeight = value != null ? value.data : 0;
792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 info.updatePeriodMillis = sa.getInt(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700794 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 info.initialLayout = sa.getResourceId(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700796 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 String className = sa.getString(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700798 com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 if (className != null) {
800 info.configure = new ComponentName(component.getPackageName(), className);
801 }
802 info.label = activityInfo.loadLabel(mPackageManager).toString();
803 info.icon = ri.getIconResource();
Patrick Dubroyd2db2a52010-06-23 14:56:28 -0700804 info.previewImage = sa.getResourceId(
805 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 sa.recycle();
808 } catch (Exception e) {
809 // Ok to catch Exception here, because anything going wrong because
810 // of what a client process passes to us should not be fatal for the
811 // system process.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800812 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 return null;
814 } finally {
815 if (parser != null) parser.close();
816 }
817 return p;
818 }
819
820 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
821 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
822 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
823 throw new PackageManager.NameNotFoundException();
824 }
825 return pkgInfo.applicationInfo.uid;
826 }
827
828 int enforceCallingUid(String packageName) throws IllegalArgumentException {
829 int callingUid = getCallingUid();
830 int packageUid;
831 try {
832 packageUid = getUidForPackage(packageName);
833 } catch (PackageManager.NameNotFoundException ex) {
834 throw new IllegalArgumentException("packageName and uid don't match packageName="
835 + packageName);
836 }
Marco Nelissen54796e72009-04-30 15:16:30 -0700837 if (callingUid != packageUid && Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 throw new IllegalArgumentException("packageName and uid don't match packageName="
839 + packageName);
840 }
841 return callingUid;
842 }
843
844 void sendInitialBroadcasts() {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700845 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 final int N = mInstalledProviders.size();
847 for (int i=0; i<N; i++) {
848 Provider p = mInstalledProviders.get(i);
849 if (p.instances.size() > 0) {
850 sendEnableIntentLocked(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700851 int[] appWidgetIds = getAppWidgetIds(p);
852 sendUpdateIntentLocked(p, appWidgetIds);
853 registerForBroadcastsLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855 }
856 }
857 }
858
859 // only call from initialization -- it assumes that the data structures are all empty
860 void loadStateLocked() {
861 File temp = savedStateTempFile();
862 File real = savedStateRealFile();
863
864 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
865 // real one. if there is both a real file and a temp one, assume that the temp one isn't
866 // fully written and delete it.
867 if (real.exists()) {
868 readStateFromFileLocked(real);
869 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700870 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 temp.delete();
872 }
873 } else if (temp.exists()) {
874 readStateFromFileLocked(temp);
Romain Guya5475592009-07-01 17:20:08 -0700875 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 temp.renameTo(real);
877 }
878 }
879
880 void saveStateLocked() {
881 File temp = savedStateTempFile();
882 File real = savedStateRealFile();
883
884 if (!real.exists()) {
885 // If the real one doesn't exist, it's either because this is the first time
886 // or because something went wrong while copying them. In this case, we can't
887 // trust anything that's in temp. In order to have the loadState code not
888 // use the temporary one until it's fully written, create an empty file
889 // for real, which will we'll shortly delete.
890 try {
Romain Guya5475592009-07-01 17:20:08 -0700891 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 real.createNewFile();
893 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -0700894 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
896 }
897
898 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700899 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 temp.delete();
901 }
902
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700903 if (!writeStateToFileLocked(temp)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800904 Slog.w(TAG, "Failed to persist new settings");
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700905 return;
906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907
Romain Guya5475592009-07-01 17:20:08 -0700908 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 real.delete();
Romain Guya5475592009-07-01 17:20:08 -0700910 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 temp.renameTo(real);
912 }
913
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700914 boolean writeStateToFileLocked(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 FileOutputStream stream = null;
916 int N;
917
918 try {
919 stream = new FileOutputStream(file, false);
920 XmlSerializer out = new FastXmlSerializer();
921 out.setOutput(stream, "utf-8");
922 out.startDocument(null, true);
923
924
925 out.startTag(null, "gs");
926
927 int providerIndex = 0;
928 N = mInstalledProviders.size();
929 for (int i=0; i<N; i++) {
930 Provider p = mInstalledProviders.get(i);
931 if (p.instances.size() > 0) {
932 out.startTag(null, "p");
933 out.attribute(null, "pkg", p.info.provider.getPackageName());
934 out.attribute(null, "cl", p.info.provider.getClassName());
Patrick Tsaibd742e432010-05-01 00:30:19 +0800935 out.endTag(null, "p");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 p.tag = providerIndex;
937 providerIndex++;
938 }
939 }
940
941 N = mHosts.size();
942 for (int i=0; i<N; i++) {
943 Host host = mHosts.get(i);
944 out.startTag(null, "h");
945 out.attribute(null, "pkg", host.packageName);
946 out.attribute(null, "id", Integer.toHexString(host.hostId));
947 out.endTag(null, "h");
948 host.tag = i;
949 }
950
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700951 N = mAppWidgetIds.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700953 AppWidgetId id = mAppWidgetIds.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 out.startTag(null, "g");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700955 out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 out.attribute(null, "h", Integer.toHexString(id.host.tag));
957 if (id.provider != null) {
958 out.attribute(null, "p", Integer.toHexString(id.provider.tag));
959 }
960 out.endTag(null, "g");
961 }
962
963 out.endTag(null, "gs");
964
965 out.endDocument();
966 stream.close();
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700967 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 } catch (IOException e) {
969 try {
970 if (stream != null) {
971 stream.close();
972 }
973 } catch (IOException ex) {
Romain Guya5475592009-07-01 17:20:08 -0700974 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 }
976 if (file.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700977 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 file.delete();
979 }
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700980 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
982 }
983
984 void readStateFromFileLocked(File file) {
985 FileInputStream stream = null;
986
987 boolean success = false;
988
989 try {
990 stream = new FileInputStream(file);
991 XmlPullParser parser = Xml.newPullParser();
992 parser.setInput(stream, null);
993
994 int type;
995 int providerIndex = 0;
Romain Guya5475592009-07-01 17:20:08 -0700996 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 do {
998 type = parser.next();
999 if (type == XmlPullParser.START_TAG) {
1000 String tag = parser.getName();
1001 if ("p".equals(tag)) {
1002 // TODO: do we need to check that this package has the same signature
1003 // as before?
1004 String pkg = parser.getAttributeValue(null, "pkg");
1005 String cl = parser.getAttributeValue(null, "cl");
Romain Guyff3e61c62010-03-11 15:30:02 -08001006
1007 final PackageManager packageManager = mContext.getPackageManager();
1008 try {
1009 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
1010 } catch (PackageManager.NameNotFoundException e) {
1011 String[] pkgs = packageManager.currentToCanonicalPackageNames(
1012 new String[] { pkg });
1013 pkg = pkgs[0];
1014 }
1015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
1017 if (p == null && mSafeMode) {
1018 // if we're in safe mode, make a temporary one
1019 p = new Provider();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001020 p.info = new AppWidgetProviderInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 p.info.provider = new ComponentName(pkg, cl);
1022 p.zombie = true;
1023 mInstalledProviders.add(p);
1024 }
1025 if (p != null) {
1026 // if it wasn't uninstalled or something
1027 loadedProviders.put(providerIndex, p);
1028 }
1029 providerIndex++;
1030 }
1031 else if ("h".equals(tag)) {
1032 Host host = new Host();
1033
1034 // TODO: do we need to check that this package has the same signature
1035 // as before?
1036 host.packageName = parser.getAttributeValue(null, "pkg");
1037 try {
1038 host.uid = getUidForPackage(host.packageName);
1039 } catch (PackageManager.NameNotFoundException ex) {
1040 host.zombie = true;
1041 }
1042 if (!host.zombie || mSafeMode) {
1043 // In safe mode, we don't discard the hosts we don't recognize
1044 // so that they're not pruned from our list. Otherwise, we do.
1045 host.hostId = Integer.parseInt(
1046 parser.getAttributeValue(null, "id"), 16);
1047 mHosts.add(host);
1048 }
1049 }
1050 else if ("g".equals(tag)) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001051 AppWidgetId id = new AppWidgetId();
1052 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
1053 if (id.appWidgetId >= mNextAppWidgetId) {
1054 mNextAppWidgetId = id.appWidgetId + 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056
1057 String providerString = parser.getAttributeValue(null, "p");
1058 if (providerString != null) {
1059 // there's no provider if it hasn't been bound yet.
1060 // maybe we don't have to save this, but it brings the system
1061 // to the state it was in.
1062 int pIndex = Integer.parseInt(providerString, 16);
1063 id.provider = loadedProviders.get(pIndex);
1064 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001065 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 + pIndex + " which is " + id.provider);
1067 }
1068 if (id.provider == null) {
1069 // This provider is gone. We just let the host figure out
1070 // that this happened when it fails to load it.
1071 continue;
1072 }
1073 }
1074
1075 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
1076 id.host = mHosts.get(hIndex);
1077 if (id.host == null) {
1078 // This host is gone.
1079 continue;
1080 }
1081
1082 if (id.provider != null) {
1083 id.provider.instances.add(id);
1084 }
1085 id.host.instances.add(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001086 mAppWidgetIds.add(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 }
1088 }
1089 } while (type != XmlPullParser.END_DOCUMENT);
1090 success = true;
1091 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001092 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001094 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001096 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001098 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001100 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102 try {
1103 if (stream != null) {
1104 stream.close();
1105 }
1106 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -07001107 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 }
1109
1110 if (success) {
1111 // delete any hosts that didn't manage to get connected (should happen)
1112 // if it matters, they'll be reconnected.
Dianne Hackborn002716d2009-08-12 11:13:26 -07001113 for (int i=mHosts.size()-1; i>=0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 pruneHostLocked(mHosts.get(i));
1115 }
1116 } else {
1117 // failed reading, clean up
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001118 mAppWidgetIds.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 mHosts.clear();
1120 final int N = mInstalledProviders.size();
1121 for (int i=0; i<N; i++) {
1122 mInstalledProviders.get(i).instances.clear();
1123 }
1124 }
1125 }
1126
1127 File savedStateTempFile() {
1128 return new File("/data/system/" + SETTINGS_TMP_FILENAME);
1129 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
1130 }
1131
1132 File savedStateRealFile() {
1133 return new File("/data/system/" + SETTINGS_FILENAME);
1134 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
1135 }
1136
1137 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1138 public void onReceive(Context context, Intent intent) {
1139 String action = intent.getAction();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001140 //Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
1142 sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -07001143 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
1144 Locale revised = Locale.getDefault();
1145 if (revised == null || mLocale == null ||
1146 !(revised.equals(mLocale))) {
1147 mLocale = revised;
1148
1149 synchronized (mAppWidgetIds) {
1150 int N = mInstalledProviders.size();
1151 for (int i=N-1; i>=0; i--) {
1152 Provider p = mInstalledProviders.get(i);
1153 String pkgName = p.info.provider.getPackageName();
1154 updateProvidersForPackageLocked(pkgName);
1155 }
1156 saveStateLocked();
1157 }
1158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001160 boolean added = false;
1161 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001162 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001163 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1164 added = true;
Joe Onorato94258cd2010-08-24 16:45:40 -04001165 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001166 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1167 added = false;
1168 } else {
1169 Uri uri = intent.getData();
1170 if (uri == null) {
1171 return;
1172 }
1173 String pkgName = uri.getSchemeSpecificPart();
1174 if (pkgName == null) {
1175 return;
1176 }
1177 pkgList = new String[] { pkgName };
1178 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1179 }
1180 if (pkgList == null || pkgList.length == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 return;
1182 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001183 if (added) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001184 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 Bundle extras = intent.getExtras();
1186 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001187 for (String pkgName : pkgList) {
1188 // The package was just upgraded
1189 updateProvidersForPackageLocked(pkgName);
1190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 } else {
1192 // The package was just added
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001193 for (String pkgName : pkgList) {
1194 addProvidersForPackageLocked(pkgName);
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197 saveStateLocked();
1198 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001199 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 Bundle extras = intent.getExtras();
1201 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
1202 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
1203 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001204 synchronized (mAppWidgetIds) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001205 for (String pkgName : pkgList) {
1206 removeProvidersForPackageLocked(pkgName);
1207 saveStateLocked();
1208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 }
1210 }
1211 }
1212 }
1213 }
1214 };
1215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 void addProvidersForPackageLocked(String pkgName) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001217 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001218 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1220 PackageManager.GET_META_DATA);
1221
Bjorn Bringert5f857802010-02-10 23:09:48 +00001222 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 for (int i=0; i<N; i++) {
1224 ResolveInfo ri = broadcastReceivers.get(i);
1225 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc72010-08-24 17:02:09 -04001226 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1227 continue;
1228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 if (pkgName.equals(ai.packageName)) {
1230 addProviderLocked(ri);
1231 }
1232 }
1233 }
1234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 void updateProvidersForPackageLocked(String pkgName) {
Romain Guya5475592009-07-01 17:20:08 -07001236 HashSet<String> keep = new HashSet<String>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001237 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001238 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1240 PackageManager.GET_META_DATA);
1241
1242 // add the missing ones and collect which ones to keep
Bjorn Bringert5f857802010-02-10 23:09:48 +00001243 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 for (int i=0; i<N; i++) {
1245 ResolveInfo ri = broadcastReceivers.get(i);
1246 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc72010-08-24 17:02:09 -04001247 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1248 continue;
1249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 if (pkgName.equals(ai.packageName)) {
1251 ComponentName component = new ComponentName(ai.packageName, ai.name);
1252 Provider p = lookupProviderLocked(component);
1253 if (p == null) {
1254 if (addProviderLocked(ri)) {
1255 keep.add(ai.name);
1256 }
1257 } else {
1258 Provider parsed = parseProviderInfoXml(component, ri);
1259 if (parsed != null) {
1260 keep.add(ai.name);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001261 // Use the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 p.info = parsed.info;
1263 // If it's enabled
1264 final int M = p.instances.size();
1265 if (M > 0) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001266 int[] appWidgetIds = getAppWidgetIds(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 // Reschedule for the new updatePeriodMillis (don't worry about handling
1268 // it specially if updatePeriodMillis didn't change because we just sent
1269 // an update, and the next one will be updatePeriodMillis from now).
1270 cancelBroadcasts(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001271 registerForBroadcastsLocked(p, appWidgetIds);
1272 // If it's currently showing, call back with the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 for (int j=0; j<M; j++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001274 AppWidgetId id = p.instances.get(j);
Joe Onoratoa8a8a422010-06-16 15:06:16 -04001275 id.views = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 if (id.host != null && id.host.callbacks != null) {
1277 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001278 id.host.callbacks.providerChanged(id.appWidgetId, p.info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 } catch (RemoteException ex) {
1280 // It failed; remove the callback. No need to prune because
1281 // we know that this host is still referenced by this
1282 // instance.
1283 id.host.callbacks = null;
1284 }
1285 }
1286 }
1287 // Now that we've told the host, push out an update.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001288 sendUpdateIntentLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
1290 }
1291 }
1292 }
1293 }
1294
1295 // prune the ones we don't want to keep
1296 N = mInstalledProviders.size();
1297 for (int i=N-1; i>=0; i--) {
1298 Provider p = mInstalledProviders.get(i);
1299 if (pkgName.equals(p.info.provider.getPackageName())
1300 && !keep.contains(p.info.provider.getClassName())) {
1301 removeProviderLocked(i, p);
1302 }
1303 }
1304 }
1305
1306 void removeProvidersForPackageLocked(String pkgName) {
1307 int N = mInstalledProviders.size();
1308 for (int i=N-1; i>=0; i--) {
1309 Provider p = mInstalledProviders.get(i);
1310 if (pkgName.equals(p.info.provider.getPackageName())) {
1311 removeProviderLocked(i, p);
1312 }
1313 }
1314
1315 // Delete the hosts for this package too
1316 //
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001317 // By now, we have removed any AppWidgets that were in any hosts here,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 // so we don't need to worry about sending DISABLE broadcasts to them.
1319 N = mHosts.size();
1320 for (int i=N-1; i>=0; i--) {
1321 Host host = mHosts.get(i);
1322 if (pkgName.equals(host.packageName)) {
1323 deleteHostLocked(host);
1324 }
1325 }
1326 }
1327}
1328