blob: ae408fccd8dc20d1e8439f0dc6c018b692114748 [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 Onorato331fbdc2010-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);
Adam Cohena02fdf12010-11-03 13:27:40 -0700806 info.autoAdvanceViewId = sa.getResourceId(
807 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
Patrick Dubroyd2db2a52010-06-23 14:56:28 -0700808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 sa.recycle();
810 } catch (Exception e) {
811 // Ok to catch Exception here, because anything going wrong because
812 // of what a client process passes to us should not be fatal for the
813 // system process.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800814 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 return null;
816 } finally {
817 if (parser != null) parser.close();
818 }
819 return p;
820 }
821
822 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
823 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
824 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
825 throw new PackageManager.NameNotFoundException();
826 }
827 return pkgInfo.applicationInfo.uid;
828 }
829
830 int enforceCallingUid(String packageName) throws IllegalArgumentException {
831 int callingUid = getCallingUid();
832 int packageUid;
833 try {
834 packageUid = getUidForPackage(packageName);
835 } catch (PackageManager.NameNotFoundException ex) {
836 throw new IllegalArgumentException("packageName and uid don't match packageName="
837 + packageName);
838 }
Marco Nelissen54796e72009-04-30 15:16:30 -0700839 if (callingUid != packageUid && Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 throw new IllegalArgumentException("packageName and uid don't match packageName="
841 + packageName);
842 }
843 return callingUid;
844 }
845
846 void sendInitialBroadcasts() {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700847 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 final int N = mInstalledProviders.size();
849 for (int i=0; i<N; i++) {
850 Provider p = mInstalledProviders.get(i);
851 if (p.instances.size() > 0) {
852 sendEnableIntentLocked(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700853 int[] appWidgetIds = getAppWidgetIds(p);
854 sendUpdateIntentLocked(p, appWidgetIds);
855 registerForBroadcastsLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 }
857 }
858 }
859 }
860
861 // only call from initialization -- it assumes that the data structures are all empty
862 void loadStateLocked() {
863 File temp = savedStateTempFile();
864 File real = savedStateRealFile();
865
866 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
867 // real one. if there is both a real file and a temp one, assume that the temp one isn't
868 // fully written and delete it.
869 if (real.exists()) {
870 readStateFromFileLocked(real);
871 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700872 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 temp.delete();
874 }
875 } else if (temp.exists()) {
876 readStateFromFileLocked(temp);
Romain Guya5475592009-07-01 17:20:08 -0700877 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 temp.renameTo(real);
879 }
880 }
881
882 void saveStateLocked() {
883 File temp = savedStateTempFile();
884 File real = savedStateRealFile();
885
886 if (!real.exists()) {
887 // If the real one doesn't exist, it's either because this is the first time
888 // or because something went wrong while copying them. In this case, we can't
889 // trust anything that's in temp. In order to have the loadState code not
890 // use the temporary one until it's fully written, create an empty file
891 // for real, which will we'll shortly delete.
892 try {
Romain Guya5475592009-07-01 17:20:08 -0700893 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 real.createNewFile();
895 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -0700896 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 }
898 }
899
900 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700901 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 temp.delete();
903 }
904
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700905 if (!writeStateToFileLocked(temp)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800906 Slog.w(TAG, "Failed to persist new settings");
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700907 return;
908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909
Romain Guya5475592009-07-01 17:20:08 -0700910 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 real.delete();
Romain Guya5475592009-07-01 17:20:08 -0700912 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 temp.renameTo(real);
914 }
915
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700916 boolean writeStateToFileLocked(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 FileOutputStream stream = null;
918 int N;
919
920 try {
921 stream = new FileOutputStream(file, false);
922 XmlSerializer out = new FastXmlSerializer();
923 out.setOutput(stream, "utf-8");
924 out.startDocument(null, true);
925
926
927 out.startTag(null, "gs");
928
929 int providerIndex = 0;
930 N = mInstalledProviders.size();
931 for (int i=0; i<N; i++) {
932 Provider p = mInstalledProviders.get(i);
933 if (p.instances.size() > 0) {
934 out.startTag(null, "p");
935 out.attribute(null, "pkg", p.info.provider.getPackageName());
936 out.attribute(null, "cl", p.info.provider.getClassName());
Patrick Tsaibd742e432010-05-01 00:30:19 +0800937 out.endTag(null, "p");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 p.tag = providerIndex;
939 providerIndex++;
940 }
941 }
942
943 N = mHosts.size();
944 for (int i=0; i<N; i++) {
945 Host host = mHosts.get(i);
946 out.startTag(null, "h");
947 out.attribute(null, "pkg", host.packageName);
948 out.attribute(null, "id", Integer.toHexString(host.hostId));
949 out.endTag(null, "h");
950 host.tag = i;
951 }
952
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700953 N = mAppWidgetIds.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700955 AppWidgetId id = mAppWidgetIds.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 out.startTag(null, "g");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700957 out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 out.attribute(null, "h", Integer.toHexString(id.host.tag));
959 if (id.provider != null) {
960 out.attribute(null, "p", Integer.toHexString(id.provider.tag));
961 }
962 out.endTag(null, "g");
963 }
964
965 out.endTag(null, "gs");
966
967 out.endDocument();
968 stream.close();
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700969 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 } catch (IOException e) {
971 try {
972 if (stream != null) {
973 stream.close();
974 }
975 } catch (IOException ex) {
Romain Guya5475592009-07-01 17:20:08 -0700976 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 }
978 if (file.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700979 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 file.delete();
981 }
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700982 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 }
984 }
985
986 void readStateFromFileLocked(File file) {
987 FileInputStream stream = null;
988
989 boolean success = false;
990
991 try {
992 stream = new FileInputStream(file);
993 XmlPullParser parser = Xml.newPullParser();
994 parser.setInput(stream, null);
995
996 int type;
997 int providerIndex = 0;
Romain Guya5475592009-07-01 17:20:08 -0700998 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 do {
1000 type = parser.next();
1001 if (type == XmlPullParser.START_TAG) {
1002 String tag = parser.getName();
1003 if ("p".equals(tag)) {
1004 // TODO: do we need to check that this package has the same signature
1005 // as before?
1006 String pkg = parser.getAttributeValue(null, "pkg");
1007 String cl = parser.getAttributeValue(null, "cl");
Romain Guyff3e61c2010-03-11 15:30:02 -08001008
1009 final PackageManager packageManager = mContext.getPackageManager();
1010 try {
1011 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
1012 } catch (PackageManager.NameNotFoundException e) {
1013 String[] pkgs = packageManager.currentToCanonicalPackageNames(
1014 new String[] { pkg });
1015 pkg = pkgs[0];
1016 }
1017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
1019 if (p == null && mSafeMode) {
1020 // if we're in safe mode, make a temporary one
1021 p = new Provider();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001022 p.info = new AppWidgetProviderInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 p.info.provider = new ComponentName(pkg, cl);
1024 p.zombie = true;
1025 mInstalledProviders.add(p);
1026 }
1027 if (p != null) {
1028 // if it wasn't uninstalled or something
1029 loadedProviders.put(providerIndex, p);
1030 }
1031 providerIndex++;
1032 }
1033 else if ("h".equals(tag)) {
1034 Host host = new Host();
1035
1036 // TODO: do we need to check that this package has the same signature
1037 // as before?
1038 host.packageName = parser.getAttributeValue(null, "pkg");
1039 try {
1040 host.uid = getUidForPackage(host.packageName);
1041 } catch (PackageManager.NameNotFoundException ex) {
1042 host.zombie = true;
1043 }
1044 if (!host.zombie || mSafeMode) {
1045 // In safe mode, we don't discard the hosts we don't recognize
1046 // so that they're not pruned from our list. Otherwise, we do.
1047 host.hostId = Integer.parseInt(
1048 parser.getAttributeValue(null, "id"), 16);
1049 mHosts.add(host);
1050 }
1051 }
1052 else if ("g".equals(tag)) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001053 AppWidgetId id = new AppWidgetId();
1054 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
1055 if (id.appWidgetId >= mNextAppWidgetId) {
1056 mNextAppWidgetId = id.appWidgetId + 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058
1059 String providerString = parser.getAttributeValue(null, "p");
1060 if (providerString != null) {
1061 // there's no provider if it hasn't been bound yet.
1062 // maybe we don't have to save this, but it brings the system
1063 // to the state it was in.
1064 int pIndex = Integer.parseInt(providerString, 16);
1065 id.provider = loadedProviders.get(pIndex);
1066 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001067 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 + pIndex + " which is " + id.provider);
1069 }
1070 if (id.provider == null) {
1071 // This provider is gone. We just let the host figure out
1072 // that this happened when it fails to load it.
1073 continue;
1074 }
1075 }
1076
1077 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
1078 id.host = mHosts.get(hIndex);
1079 if (id.host == null) {
1080 // This host is gone.
1081 continue;
1082 }
1083
1084 if (id.provider != null) {
1085 id.provider.instances.add(id);
1086 }
1087 id.host.instances.add(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001088 mAppWidgetIds.add(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090 }
1091 } while (type != XmlPullParser.END_DOCUMENT);
1092 success = true;
1093 } catch (NullPointerException 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 (NumberFormatException 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 (XmlPullParserException 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 (IOException 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 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001102 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 }
1104 try {
1105 if (stream != null) {
1106 stream.close();
1107 }
1108 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -07001109 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111
1112 if (success) {
1113 // delete any hosts that didn't manage to get connected (should happen)
1114 // if it matters, they'll be reconnected.
Dianne Hackborn002716d2009-08-12 11:13:26 -07001115 for (int i=mHosts.size()-1; i>=0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 pruneHostLocked(mHosts.get(i));
1117 }
1118 } else {
1119 // failed reading, clean up
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001120 mAppWidgetIds.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 mHosts.clear();
1122 final int N = mInstalledProviders.size();
1123 for (int i=0; i<N; i++) {
1124 mInstalledProviders.get(i).instances.clear();
1125 }
1126 }
1127 }
1128
1129 File savedStateTempFile() {
1130 return new File("/data/system/" + SETTINGS_TMP_FILENAME);
1131 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
1132 }
1133
1134 File savedStateRealFile() {
1135 return new File("/data/system/" + SETTINGS_FILENAME);
1136 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
1137 }
1138
1139 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1140 public void onReceive(Context context, Intent intent) {
1141 String action = intent.getAction();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001142 //Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
1144 sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -07001145 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
1146 Locale revised = Locale.getDefault();
1147 if (revised == null || mLocale == null ||
1148 !(revised.equals(mLocale))) {
1149 mLocale = revised;
1150
1151 synchronized (mAppWidgetIds) {
1152 int N = mInstalledProviders.size();
1153 for (int i=N-1; i>=0; i--) {
1154 Provider p = mInstalledProviders.get(i);
1155 String pkgName = p.info.provider.getPackageName();
1156 updateProvidersForPackageLocked(pkgName);
1157 }
1158 saveStateLocked();
1159 }
1160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001162 boolean added = false;
1163 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001164 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001165 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1166 added = true;
Joe Onorato94258cd2010-08-24 16:45:40 -04001167 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001168 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1169 added = false;
1170 } else {
1171 Uri uri = intent.getData();
1172 if (uri == null) {
1173 return;
1174 }
1175 String pkgName = uri.getSchemeSpecificPart();
1176 if (pkgName == null) {
1177 return;
1178 }
1179 pkgList = new String[] { pkgName };
1180 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1181 }
1182 if (pkgList == null || pkgList.length == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 return;
1184 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001185 if (added) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001186 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 Bundle extras = intent.getExtras();
1188 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001189 for (String pkgName : pkgList) {
1190 // The package was just upgraded
1191 updateProvidersForPackageLocked(pkgName);
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 } else {
1194 // The package was just added
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001195 for (String pkgName : pkgList) {
1196 addProvidersForPackageLocked(pkgName);
1197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
1199 saveStateLocked();
1200 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001201 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 Bundle extras = intent.getExtras();
1203 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
1204 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
1205 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001206 synchronized (mAppWidgetIds) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001207 for (String pkgName : pkgList) {
1208 removeProvidersForPackageLocked(pkgName);
1209 saveStateLocked();
1210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212 }
1213 }
1214 }
1215 }
1216 };
1217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 void addProvidersForPackageLocked(String pkgName) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001219 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001220 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1222 PackageManager.GET_META_DATA);
1223
Bjorn Bringert5f857802010-02-10 23:09:48 +00001224 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 for (int i=0; i<N; i++) {
1226 ResolveInfo ri = broadcastReceivers.get(i);
1227 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc2010-08-24 17:02:09 -04001228 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1229 continue;
1230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 if (pkgName.equals(ai.packageName)) {
1232 addProviderLocked(ri);
1233 }
1234 }
1235 }
1236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 void updateProvidersForPackageLocked(String pkgName) {
Romain Guya5475592009-07-01 17:20:08 -07001238 HashSet<String> keep = new HashSet<String>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001239 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001240 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1242 PackageManager.GET_META_DATA);
1243
1244 // add the missing ones and collect which ones to keep
Bjorn Bringert5f857802010-02-10 23:09:48 +00001245 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 for (int i=0; i<N; i++) {
1247 ResolveInfo ri = broadcastReceivers.get(i);
1248 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc2010-08-24 17:02:09 -04001249 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1250 continue;
1251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 if (pkgName.equals(ai.packageName)) {
1253 ComponentName component = new ComponentName(ai.packageName, ai.name);
1254 Provider p = lookupProviderLocked(component);
1255 if (p == null) {
1256 if (addProviderLocked(ri)) {
1257 keep.add(ai.name);
1258 }
1259 } else {
1260 Provider parsed = parseProviderInfoXml(component, ri);
1261 if (parsed != null) {
1262 keep.add(ai.name);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001263 // Use the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 p.info = parsed.info;
1265 // If it's enabled
1266 final int M = p.instances.size();
1267 if (M > 0) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001268 int[] appWidgetIds = getAppWidgetIds(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 // Reschedule for the new updatePeriodMillis (don't worry about handling
1270 // it specially if updatePeriodMillis didn't change because we just sent
1271 // an update, and the next one will be updatePeriodMillis from now).
1272 cancelBroadcasts(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001273 registerForBroadcastsLocked(p, appWidgetIds);
1274 // If it's currently showing, call back with the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 for (int j=0; j<M; j++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001276 AppWidgetId id = p.instances.get(j);
Joe Onoratoa8a8a422010-06-16 15:06:16 -04001277 id.views = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 if (id.host != null && id.host.callbacks != null) {
1279 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001280 id.host.callbacks.providerChanged(id.appWidgetId, p.info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 } catch (RemoteException ex) {
1282 // It failed; remove the callback. No need to prune because
1283 // we know that this host is still referenced by this
1284 // instance.
1285 id.host.callbacks = null;
1286 }
1287 }
1288 }
1289 // Now that we've told the host, push out an update.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001290 sendUpdateIntentLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292 }
1293 }
1294 }
1295 }
1296
1297 // prune the ones we don't want to keep
1298 N = mInstalledProviders.size();
1299 for (int i=N-1; i>=0; i--) {
1300 Provider p = mInstalledProviders.get(i);
1301 if (pkgName.equals(p.info.provider.getPackageName())
1302 && !keep.contains(p.info.provider.getClassName())) {
1303 removeProviderLocked(i, p);
1304 }
1305 }
1306 }
1307
1308 void removeProvidersForPackageLocked(String pkgName) {
1309 int N = mInstalledProviders.size();
1310 for (int i=N-1; i>=0; i--) {
1311 Provider p = mInstalledProviders.get(i);
1312 if (pkgName.equals(p.info.provider.getPackageName())) {
1313 removeProviderLocked(i, p);
1314 }
1315 }
1316
1317 // Delete the hosts for this package too
1318 //
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001319 // By now, we have removed any AppWidgets that were in any hosts here,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 // so we don't need to worry about sending DISABLE broadcasts to them.
1321 N = mHosts.size();
1322 for (int i=N-1; i>=0; i--) {
1323 Host host = mHosts.get(i);
1324 if (pkgName.equals(host.packageName)) {
1325 deleteHostLocked(host);
1326 }
1327 }
1328 }
1329}
1330