blob: 22dd804f604bb92a8a92a62b488a660a03317bf8 [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);
Joe Onoratod070e892011-01-07 20:50:37 -0800147 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
149 filter.addDataScheme("package");
150 mContext.registerReceiver(mBroadcastReceiver, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800151 // Register for events related to sdcard installation.
152 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800153 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
154 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800155 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 }
157
158 @Override
159 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
160 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
161 != PackageManager.PERMISSION_GRANTED) {
162 pw.println("Permission Denial: can't dump from from pid="
163 + Binder.getCallingPid()
164 + ", uid=" + Binder.getCallingUid());
165 return;
166 }
167
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700168 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 int N = mInstalledProviders.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700170 pw.println("Providers:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 for (int i=0; i<N; i++) {
172 Provider p = mInstalledProviders.get(i);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700173 AppWidgetProviderInfo info = p.info;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700174 pw.print(" ["); pw.print(i); pw.print("] provider ");
175 pw.print(info.provider.flattenToShortString());
176 pw.println(':');
177 pw.print(" min=("); pw.print(info.minWidth);
178 pw.print("x"); pw.print(info.minHeight);
179 pw.print(") updatePeriodMillis=");
180 pw.print(info.updatePeriodMillis);
181 pw.print(" initialLayout=#");
182 pw.print(Integer.toHexString(info.initialLayout));
183 pw.print(" zombie="); pw.println(p.zombie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 }
185
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700186 N = mAppWidgetIds.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700187 pw.println(" ");
188 pw.println("AppWidgetIds:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700190 AppWidgetId id = mAppWidgetIds.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700191 pw.print(" ["); pw.print(i); pw.print("] id=");
Romain Guya5475592009-07-01 17:20:08 -0700192 pw.println(id.appWidgetId);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700193 pw.print(" hostId=");
194 pw.print(id.host.hostId); pw.print(' ');
195 pw.print(id.host.packageName); pw.print('/');
196 pw.println(id.host.uid);
197 if (id.provider != null) {
198 pw.print(" provider=");
199 pw.println(id.provider.info.provider.flattenToShortString());
200 }
201 if (id.host != null) {
202 pw.print(" host.callbacks="); pw.println(id.host.callbacks);
203 }
204 if (id.views != null) {
205 pw.print(" views="); pw.println(id.views);
206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
208
209 N = mHosts.size();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700210 pw.println(" ");
211 pw.println("Hosts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 for (int i=0; i<N; i++) {
213 Host host = mHosts.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700214 pw.print(" ["); pw.print(i); pw.print("] hostId=");
215 pw.print(host.hostId); pw.print(' ');
216 pw.print(host.packageName); pw.print('/');
217 pw.print(host.uid); pw.println(':');
218 pw.print(" callbacks="); pw.println(host.callbacks);
219 pw.print(" instances.size="); pw.print(host.instances.size());
220 pw.print(" zombie="); pw.println(host.zombie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 }
222 }
223 }
224
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700225 public int allocateAppWidgetId(String packageName, int hostId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 int callingUid = enforceCallingUid(packageName);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700227 synchronized (mAppWidgetIds) {
228 int appWidgetId = mNextAppWidgetId++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
230 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
231
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700232 AppWidgetId id = new AppWidgetId();
233 id.appWidgetId = appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 id.host = host;
235
236 host.instances.add(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700237 mAppWidgetIds.add(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 saveStateLocked();
240
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700241 return appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243 }
244
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700245 public void deleteAppWidgetId(int appWidgetId) {
246 synchronized (mAppWidgetIds) {
247 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 if (id != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700249 deleteAppWidgetLocked(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 saveStateLocked();
251 }
252 }
253 }
254
255 public void deleteHost(int hostId) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700256 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 int callingUid = getCallingUid();
258 Host host = lookupHostLocked(callingUid, hostId);
259 if (host != null) {
260 deleteHostLocked(host);
261 saveStateLocked();
262 }
263 }
264 }
265
266 public void deleteAllHosts() {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700267 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 int callingUid = getCallingUid();
269 final int N = mHosts.size();
270 boolean changed = false;
271 for (int i=N-1; i>=0; i--) {
272 Host host = mHosts.get(i);
273 if (host.uid == callingUid) {
274 deleteHostLocked(host);
275 changed = true;
276 }
277 }
278 if (changed) {
279 saveStateLocked();
280 }
281 }
282 }
283
284 void deleteHostLocked(Host host) {
285 final int N = host.instances.size();
286 for (int i=N-1; i>=0; i--) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700287 AppWidgetId id = host.instances.get(i);
288 deleteAppWidgetLocked(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 }
290 host.instances.clear();
291 mHosts.remove(host);
292 // it's gone or going away, abruptly drop the callback connection
293 host.callbacks = null;
294 }
295
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700296 void deleteAppWidgetLocked(AppWidgetId id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 Host host = id.host;
298 host.instances.remove(id);
299 pruneHostLocked(host);
300
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700301 mAppWidgetIds.remove(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302
303 Provider p = id.provider;
304 if (p != null) {
305 p.instances.remove(id);
306 if (!p.zombie) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700307 // send the broacast saying that this appWidgetId has been deleted
308 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 intent.setComponent(p.info.provider);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700310 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 mContext.sendBroadcast(intent);
312 if (p.instances.size() == 0) {
313 // cancel the future updates
314 cancelBroadcasts(p);
315
316 // send the broacast saying that the provider is not in use any more
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700317 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 intent.setComponent(p.info.provider);
319 mContext.sendBroadcast(intent);
320 }
321 }
322 }
323 }
324
325 void cancelBroadcasts(Provider p) {
326 if (p.broadcast != null) {
327 mAlarmManager.cancel(p.broadcast);
328 long token = Binder.clearCallingIdentity();
329 try {
330 p.broadcast.cancel();
331 } finally {
332 Binder.restoreCallingIdentity(token);
333 }
334 p.broadcast = null;
335 }
336 }
337
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700338 public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
339 mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
340 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
341 synchronized (mAppWidgetIds) {
342 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 if (id == null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700344 throw new IllegalArgumentException("bad appWidgetId");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 }
346 if (id.provider != null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700347 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 + id.provider.info.provider);
349 }
350 Provider p = lookupProviderLocked(provider);
351 if (p == null) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700352 throw new IllegalArgumentException("not a appwidget provider: " + provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 }
354 if (p.zombie) {
355 throw new IllegalArgumentException("can't bind to a 3rd party provider in"
356 + " safe mode: " + provider);
357 }
358
359 id.provider = p;
360 p.instances.add(id);
361 int instancesSize = p.instances.size();
362 if (instancesSize == 1) {
363 // tell the provider that it's ready
364 sendEnableIntentLocked(p);
365 }
366
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700367 // send an update now -- We need this update now, and just for this appWidgetId.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 // It's less critical when the next one happens, so when we schdule the next one,
369 // we add updatePeriodMillis to its start time. That time will have some slop,
370 // but that's okay.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700371 sendUpdateIntentLocked(p, new int[] { appWidgetId });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372
373 // schedule the future updates
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700374 registerForBroadcastsLocked(p, getAppWidgetIds(p));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 saveStateLocked();
376 }
377 }
378
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700379 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
380 synchronized (mAppWidgetIds) {
381 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 if (id != null && id.provider != null && !id.provider.zombie) {
383 return id.provider.info;
384 }
385 return null;
386 }
387 }
388
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700389 public RemoteViews getAppWidgetViews(int appWidgetId) {
390 synchronized (mAppWidgetIds) {
391 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 if (id != null) {
393 return id.views;
394 }
395 return null;
396 }
397 }
398
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700399 public List<AppWidgetProviderInfo> getInstalledProviders() {
400 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 final int N = mInstalledProviders.size();
Romain Guya5475592009-07-01 17:20:08 -0700402 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 for (int i=0; i<N; i++) {
404 Provider p = mInstalledProviders.get(i);
405 if (!p.zombie) {
406 result.add(p.info);
407 }
408 }
409 return result;
410 }
411 }
412
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700413 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
414 if (appWidgetIds == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 return;
416 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700417 if (appWidgetIds.length == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 return;
419 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700420 final int N = appWidgetIds.length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700422 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700424 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
425 updateAppWidgetInstanceLocked(id, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
427 }
428 }
429
Adam Cohen2dd21972010-08-15 18:20:04 -0700430 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
431 if (appWidgetIds == null) {
432 return;
433 }
434 if (appWidgetIds.length == 0) {
435 return;
436 }
437 final int N = appWidgetIds.length;
438
439 synchronized (mAppWidgetIds) {
440 for (int i=0; i<N; i++) {
441 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
442 updateAppWidgetInstanceLocked(id, views, true);
443 }
444 }
445 }
446
Winson Chung6394c0e2010-08-16 10:14:56 -0700447 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700448 if (appWidgetIds == null) {
449 return;
450 }
451 if (appWidgetIds.length == 0) {
452 return;
453 }
454 final int N = appWidgetIds.length;
455
456 synchronized (mAppWidgetIds) {
457 for (int i=0; i<N; i++) {
458 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
Winson Chung6394c0e2010-08-16 10:14:56 -0700459 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700460 }
461 }
462 }
463
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700464 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
465 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 Provider p = lookupProviderLocked(provider);
467 if (p == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800468 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 return;
470 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700471 ArrayList<AppWidgetId> instances = p.instances;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 final int N = instances.size();
473 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700474 AppWidgetId id = instances.get(i);
475 updateAppWidgetInstanceLocked(id, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477 }
478 }
479
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700480 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700481 updateAppWidgetInstanceLocked(id, views, false);
482 }
483
484 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700485 // allow for stale appWidgetIds and other badness
486 // lookup also checks that the calling process can access the appWidgetId
487 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
Adam Cohen2dd21972010-08-15 18:20:04 -0700489
490 // We do not want to save this RemoteViews
491 if (!isPartialUpdate) id.views = views;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492
493 // is anyone listening?
494 if (id.host.callbacks != null) {
495 try {
496 // the lock is held, but this is a oneway call
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700497 id.host.callbacks.updateAppWidget(id.appWidgetId, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 } catch (RemoteException e) {
499 // It failed; remove the callback. No need to prune because
500 // we know that this host is still referenced by this instance.
501 id.host.callbacks = null;
502 }
503 }
504 }
505 }
506
Winson Chung6394c0e2010-08-16 10:14:56 -0700507 void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700508 // allow for stale appWidgetIds and other badness
509 // lookup also checks that the calling process can access the appWidgetId
510 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
511 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700512 // is anyone listening?
513 if (id.host.callbacks != null) {
514 try {
515 // the lock is held, but this is a oneway call
Winson Chung6394c0e2010-08-16 10:14:56 -0700516 id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700517 } catch (RemoteException e) {
518 // It failed; remove the callback. No need to prune because
519 // we know that this host is still referenced by this instance.
520 id.host.callbacks = null;
521 }
522 }
523 }
524 }
525
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700526 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 List<RemoteViews> updatedViews) {
528 int callingUid = enforceCallingUid(packageName);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700529 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
531 host.callbacks = callbacks;
532
533 updatedViews.clear();
534
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700535 ArrayList<AppWidgetId> instances = host.instances;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 int N = instances.size();
537 int[] updatedIds = new int[N];
538 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700539 AppWidgetId id = instances.get(i);
540 updatedIds[i] = id.appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 updatedViews.add(id.views);
542 }
543 return updatedIds;
544 }
545 }
546
547 public void stopListening(int hostId) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700548 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 Host host = lookupHostLocked(getCallingUid(), hostId);
Ken Shirriffe21167a2009-09-23 16:42:53 -0700550 if (host != null) {
551 host.callbacks = null;
552 pruneHostLocked(host);
553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 }
555 }
556
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700557 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 if (id.host.uid == callingUid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700559 // Apps hosting the AppWidget have access to it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 return true;
561 }
562 if (id.provider != null && id.provider.uid == callingUid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700563 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 return true;
565 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700566 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 == PackageManager.PERMISSION_GRANTED) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700568 // Apps that can bind have access to all appWidgetIds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 return true;
570 }
571 // Nobody else can access it.
572 return false;
573 }
574
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700575 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 int callingUid = getCallingUid();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700577 final int N = mAppWidgetIds.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700579 AppWidgetId id = mAppWidgetIds.get(i);
580 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 return id;
582 }
583 }
584 return null;
585 }
586
587 Provider lookupProviderLocked(ComponentName provider) {
Romain Guyd2671e12010-03-11 18:06:42 -0800588 final String className = provider.getClassName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 final int N = mInstalledProviders.size();
590 for (int i=0; i<N; i++) {
591 Provider p = mInstalledProviders.get(i);
Romain Guyd2671e12010-03-11 18:06:42 -0800592 if (p.info.provider.equals(provider) || className.equals(p.info.oldName)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 return p;
594 }
595 }
596 return null;
597 }
598
599 Host lookupHostLocked(int uid, int hostId) {
600 final int N = mHosts.size();
601 for (int i=0; i<N; i++) {
602 Host h = mHosts.get(i);
603 if (h.uid == uid && h.hostId == hostId) {
604 return h;
605 }
606 }
607 return null;
608 }
609
610 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
611 final int N = mHosts.size();
612 for (int i=0; i<N; i++) {
613 Host h = mHosts.get(i);
614 if (h.hostId == hostId && h.packageName.equals(packageName)) {
615 return h;
616 }
617 }
618 Host host = new Host();
619 host.packageName = packageName;
620 host.uid = uid;
621 host.hostId = hostId;
622 mHosts.add(host);
623 return host;
624 }
625
626 void pruneHostLocked(Host host) {
627 if (host.instances.size() == 0 && host.callbacks == null) {
628 mHosts.remove(host);
629 }
630 }
631
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700632 void loadAppWidgetList() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 PackageManager pm = mPackageManager;
634
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700635 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
637 PackageManager.GET_META_DATA);
638
Bjorn Bringert5f857802010-02-10 23:09:48 +0000639 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 for (int i=0; i<N; i++) {
641 ResolveInfo ri = broadcastReceivers.get(i);
642 addProviderLocked(ri);
643 }
644 }
645
646 boolean addProviderLocked(ResolveInfo ri) {
Joe Onoratod070e892011-01-07 20:50:37 -0800647 if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
648 return false;
649 }
650 if (!ri.activityInfo.isEnabled()) {
651 return false;
652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
654 ri.activityInfo.name), ri);
655 if (p != null) {
656 mInstalledProviders.add(p);
657 return true;
658 } else {
659 return false;
660 }
661 }
662
663 void removeProviderLocked(int index, Provider p) {
664 int N = p.instances.size();
665 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700666 AppWidgetId id = p.instances.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 // Call back with empty RemoteViews
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700668 updateAppWidgetInstanceLocked(id, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 // Stop telling the host about updates for this from now on
670 cancelBroadcasts(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700671 // clear out references to this appWidgetId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 id.host.instances.remove(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700673 mAppWidgetIds.remove(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 id.provider = null;
675 pruneHostLocked(id.host);
676 id.host = null;
677 }
678 p.instances.clear();
679 mInstalledProviders.remove(index);
680 // no need to send the DISABLE broadcast, since the receiver is gone anyway
681 cancelBroadcasts(p);
682 }
683
684 void sendEnableIntentLocked(Provider p) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700685 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 intent.setComponent(p.info.provider);
687 mContext.sendBroadcast(intent);
688 }
689
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700690 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
691 if (appWidgetIds != null && appWidgetIds.length > 0) {
692 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
693 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 intent.setComponent(p.info.provider);
695 mContext.sendBroadcast(intent);
696 }
697 }
698
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700699 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 if (p.info.updatePeriodMillis > 0) {
701 // if this is the first instance, set the alarm. otherwise,
702 // rely on the fact that we've already set it and that
703 // PendingIntent.getBroadcast will update the extras.
704 boolean alreadyRegistered = p.broadcast != null;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700705 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
706 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 intent.setComponent(p.info.provider);
708 long token = Binder.clearCallingIdentity();
709 try {
710 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
711 PendingIntent.FLAG_UPDATE_CURRENT);
712 } finally {
713 Binder.restoreCallingIdentity(token);
714 }
715 if (!alreadyRegistered) {
Joe Onoratobe96b3a2009-07-14 19:49:27 -0700716 long period = p.info.updatePeriodMillis;
717 if (period < MIN_UPDATE_PERIOD) {
718 period = MIN_UPDATE_PERIOD;
719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Joe Onoratobe96b3a2009-07-14 19:49:27 -0700721 SystemClock.elapsedRealtime() + period, period, p.broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 }
723 }
724 }
725
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700726 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700728 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700730 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700732 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 }
734
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700735 public int[] getAppWidgetIds(ComponentName provider) {
736 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 Provider p = lookupProviderLocked(provider);
738 if (p != null && getCallingUid() == p.uid) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700739 return getAppWidgetIds(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 } else {
741 return new int[0];
742 }
743 }
744 }
745
746 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
747 Provider p = null;
748
749 ActivityInfo activityInfo = ri.activityInfo;
750 XmlResourceParser parser = null;
751 try {
752 parser = activityInfo.loadXmlMetaData(mPackageManager,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700753 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 if (parser == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800755 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700756 + "AppWidget provider '" + component + '\'');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 return null;
758 }
759
760 AttributeSet attrs = Xml.asAttributeSet(parser);
761
762 int type;
763 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
764 && type != XmlPullParser.START_TAG) {
765 // drain whitespace, comments, etc.
766 }
767
768 String nodeName = parser.getName();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700769 if (!"appwidget-provider".equals(nodeName)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800770 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700771 + " AppWidget provider '" + component + '\'');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 return null;
773 }
774
775 p = new Provider();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700776 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
Romain Guyd2671e12010-03-11 18:06:42 -0800777 // If metaData was null, we would have returned earlier when getting
778 // the parser No need to do the check here
779 info.oldName = activityInfo.metaData.getString(
780 AppWidgetManager.META_DATA_APPWIDGET_OLD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781
782 info.provider = component;
783 p.uid = activityInfo.applicationInfo.uid;
784
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800785 Resources res = mPackageManager.getResourcesForApplication(
786 activityInfo.applicationInfo);
787
788 TypedArray sa = res.obtainAttributes(attrs,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700789 com.android.internal.R.styleable.AppWidgetProviderInfo);
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700790
791 // These dimensions has to be resolved in the application's context.
792 // We simply send back the raw complex data, which will be
793 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
794 TypedValue value = sa.peekValue(
795 com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
796 info.minWidth = value != null ? value.data : 0;
797 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
798 info.minHeight = value != null ? value.data : 0;
799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 info.updatePeriodMillis = sa.getInt(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700801 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 info.initialLayout = sa.getResourceId(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700803 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 String className = sa.getString(
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700805 com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 if (className != null) {
807 info.configure = new ComponentName(component.getPackageName(), className);
808 }
809 info.label = activityInfo.loadLabel(mPackageManager).toString();
810 info.icon = ri.getIconResource();
Patrick Dubroyd2db2a52010-06-23 14:56:28 -0700811 info.previewImage = sa.getResourceId(
812 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
Adam Cohena02fdf12010-11-03 13:27:40 -0700813 info.autoAdvanceViewId = sa.getResourceId(
814 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
Patrick Dubroyd2db2a52010-06-23 14:56:28 -0700815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 sa.recycle();
817 } catch (Exception e) {
818 // Ok to catch Exception here, because anything going wrong because
819 // of what a client process passes to us should not be fatal for the
820 // system process.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800821 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 return null;
823 } finally {
824 if (parser != null) parser.close();
825 }
826 return p;
827 }
828
829 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
830 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
831 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
832 throw new PackageManager.NameNotFoundException();
833 }
834 return pkgInfo.applicationInfo.uid;
835 }
836
837 int enforceCallingUid(String packageName) throws IllegalArgumentException {
838 int callingUid = getCallingUid();
839 int packageUid;
840 try {
841 packageUid = getUidForPackage(packageName);
842 } catch (PackageManager.NameNotFoundException ex) {
843 throw new IllegalArgumentException("packageName and uid don't match packageName="
844 + packageName);
845 }
Marco Nelissen54796e72009-04-30 15:16:30 -0700846 if (callingUid != packageUid && Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 throw new IllegalArgumentException("packageName and uid don't match packageName="
848 + packageName);
849 }
850 return callingUid;
851 }
852
853 void sendInitialBroadcasts() {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700854 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 final int N = mInstalledProviders.size();
856 for (int i=0; i<N; i++) {
857 Provider p = mInstalledProviders.get(i);
858 if (p.instances.size() > 0) {
859 sendEnableIntentLocked(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700860 int[] appWidgetIds = getAppWidgetIds(p);
861 sendUpdateIntentLocked(p, appWidgetIds);
862 registerForBroadcastsLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 }
864 }
865 }
866 }
867
868 // only call from initialization -- it assumes that the data structures are all empty
869 void loadStateLocked() {
870 File temp = savedStateTempFile();
871 File real = savedStateRealFile();
872
873 // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
874 // real one. if there is both a real file and a temp one, assume that the temp one isn't
875 // fully written and delete it.
876 if (real.exists()) {
877 readStateFromFileLocked(real);
878 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700879 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 temp.delete();
881 }
882 } else if (temp.exists()) {
883 readStateFromFileLocked(temp);
Romain Guya5475592009-07-01 17:20:08 -0700884 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 temp.renameTo(real);
886 }
887 }
888
889 void saveStateLocked() {
890 File temp = savedStateTempFile();
891 File real = savedStateRealFile();
892
893 if (!real.exists()) {
894 // If the real one doesn't exist, it's either because this is the first time
895 // or because something went wrong while copying them. In this case, we can't
896 // trust anything that's in temp. In order to have the loadState code not
897 // use the temporary one until it's fully written, create an empty file
898 // for real, which will we'll shortly delete.
899 try {
Romain Guya5475592009-07-01 17:20:08 -0700900 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 real.createNewFile();
902 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -0700903 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 }
905 }
906
907 if (temp.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700908 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 temp.delete();
910 }
911
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700912 if (!writeStateToFileLocked(temp)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800913 Slog.w(TAG, "Failed to persist new settings");
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700914 return;
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916
Romain Guya5475592009-07-01 17:20:08 -0700917 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 real.delete();
Romain Guya5475592009-07-01 17:20:08 -0700919 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 temp.renameTo(real);
921 }
922
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700923 boolean writeStateToFileLocked(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 FileOutputStream stream = null;
925 int N;
926
927 try {
928 stream = new FileOutputStream(file, false);
929 XmlSerializer out = new FastXmlSerializer();
930 out.setOutput(stream, "utf-8");
931 out.startDocument(null, true);
932
933
934 out.startTag(null, "gs");
935
936 int providerIndex = 0;
937 N = mInstalledProviders.size();
938 for (int i=0; i<N; i++) {
939 Provider p = mInstalledProviders.get(i);
940 if (p.instances.size() > 0) {
941 out.startTag(null, "p");
942 out.attribute(null, "pkg", p.info.provider.getPackageName());
943 out.attribute(null, "cl", p.info.provider.getClassName());
Patrick Tsaibd742e432010-05-01 00:30:19 +0800944 out.endTag(null, "p");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 p.tag = providerIndex;
946 providerIndex++;
947 }
948 }
949
950 N = mHosts.size();
951 for (int i=0; i<N; i++) {
952 Host host = mHosts.get(i);
953 out.startTag(null, "h");
954 out.attribute(null, "pkg", host.packageName);
955 out.attribute(null, "id", Integer.toHexString(host.hostId));
956 out.endTag(null, "h");
957 host.tag = i;
958 }
959
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700960 N = mAppWidgetIds.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 for (int i=0; i<N; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700962 AppWidgetId id = mAppWidgetIds.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 out.startTag(null, "g");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700964 out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 out.attribute(null, "h", Integer.toHexString(id.host.tag));
966 if (id.provider != null) {
967 out.attribute(null, "p", Integer.toHexString(id.provider.tag));
968 }
969 out.endTag(null, "g");
970 }
971
972 out.endTag(null, "gs");
973
974 out.endDocument();
975 stream.close();
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700976 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 } catch (IOException e) {
978 try {
979 if (stream != null) {
980 stream.close();
981 }
982 } catch (IOException ex) {
Romain Guya5475592009-07-01 17:20:08 -0700983 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985 if (file.exists()) {
Romain Guya5475592009-07-01 17:20:08 -0700986 //noinspection ResultOfMethodCallIgnored
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 file.delete();
988 }
Suchi Amalapurapu8550f252009-09-29 15:20:32 -0700989 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 }
991 }
992
993 void readStateFromFileLocked(File file) {
994 FileInputStream stream = null;
995
996 boolean success = false;
997
998 try {
999 stream = new FileInputStream(file);
1000 XmlPullParser parser = Xml.newPullParser();
1001 parser.setInput(stream, null);
1002
1003 int type;
1004 int providerIndex = 0;
Romain Guya5475592009-07-01 17:20:08 -07001005 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 do {
1007 type = parser.next();
1008 if (type == XmlPullParser.START_TAG) {
1009 String tag = parser.getName();
1010 if ("p".equals(tag)) {
1011 // TODO: do we need to check that this package has the same signature
1012 // as before?
1013 String pkg = parser.getAttributeValue(null, "pkg");
1014 String cl = parser.getAttributeValue(null, "cl");
Romain Guyff3e61c2010-03-11 15:30:02 -08001015
1016 final PackageManager packageManager = mContext.getPackageManager();
1017 try {
1018 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
1019 } catch (PackageManager.NameNotFoundException e) {
1020 String[] pkgs = packageManager.currentToCanonicalPackageNames(
1021 new String[] { pkg });
1022 pkg = pkgs[0];
1023 }
1024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
1026 if (p == null && mSafeMode) {
1027 // if we're in safe mode, make a temporary one
1028 p = new Provider();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001029 p.info = new AppWidgetProviderInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 p.info.provider = new ComponentName(pkg, cl);
1031 p.zombie = true;
1032 mInstalledProviders.add(p);
1033 }
1034 if (p != null) {
1035 // if it wasn't uninstalled or something
1036 loadedProviders.put(providerIndex, p);
1037 }
1038 providerIndex++;
1039 }
1040 else if ("h".equals(tag)) {
1041 Host host = new Host();
1042
1043 // TODO: do we need to check that this package has the same signature
1044 // as before?
1045 host.packageName = parser.getAttributeValue(null, "pkg");
1046 try {
1047 host.uid = getUidForPackage(host.packageName);
1048 } catch (PackageManager.NameNotFoundException ex) {
1049 host.zombie = true;
1050 }
1051 if (!host.zombie || mSafeMode) {
1052 // In safe mode, we don't discard the hosts we don't recognize
1053 // so that they're not pruned from our list. Otherwise, we do.
1054 host.hostId = Integer.parseInt(
1055 parser.getAttributeValue(null, "id"), 16);
1056 mHosts.add(host);
1057 }
1058 }
1059 else if ("g".equals(tag)) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001060 AppWidgetId id = new AppWidgetId();
1061 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
1062 if (id.appWidgetId >= mNextAppWidgetId) {
1063 mNextAppWidgetId = id.appWidgetId + 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 }
1065
1066 String providerString = parser.getAttributeValue(null, "p");
1067 if (providerString != null) {
1068 // there's no provider if it hasn't been bound yet.
1069 // maybe we don't have to save this, but it brings the system
1070 // to the state it was in.
1071 int pIndex = Integer.parseInt(providerString, 16);
1072 id.provider = loadedProviders.get(pIndex);
1073 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001074 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 + pIndex + " which is " + id.provider);
1076 }
1077 if (id.provider == null) {
1078 // This provider is gone. We just let the host figure out
1079 // that this happened when it fails to load it.
1080 continue;
1081 }
1082 }
1083
1084 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
1085 id.host = mHosts.get(hIndex);
1086 if (id.host == null) {
1087 // This host is gone.
1088 continue;
1089 }
1090
1091 if (id.provider != null) {
1092 id.provider.instances.add(id);
1093 }
1094 id.host.instances.add(id);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001095 mAppWidgetIds.add(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097 }
1098 } while (type != XmlPullParser.END_DOCUMENT);
1099 success = true;
1100 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001101 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001103 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001105 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001107 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001109 Slog.w(TAG, "failed parsing " + file, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111 try {
1112 if (stream != null) {
1113 stream.close();
1114 }
1115 } catch (IOException e) {
Romain Guya5475592009-07-01 17:20:08 -07001116 // Ignore
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 }
1118
1119 if (success) {
1120 // delete any hosts that didn't manage to get connected (should happen)
1121 // if it matters, they'll be reconnected.
Dianne Hackborn002716d2009-08-12 11:13:26 -07001122 for (int i=mHosts.size()-1; i>=0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 pruneHostLocked(mHosts.get(i));
1124 }
1125 } else {
1126 // failed reading, clean up
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001127 mAppWidgetIds.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 mHosts.clear();
1129 final int N = mInstalledProviders.size();
1130 for (int i=0; i<N; i++) {
1131 mInstalledProviders.get(i).instances.clear();
1132 }
1133 }
1134 }
1135
1136 File savedStateTempFile() {
1137 return new File("/data/system/" + SETTINGS_TMP_FILENAME);
1138 //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
1139 }
1140
1141 File savedStateRealFile() {
1142 return new File("/data/system/" + SETTINGS_FILENAME);
1143 //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
1144 }
1145
1146 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1147 public void onReceive(Context context, Intent intent) {
1148 String action = intent.getAction();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001149 //Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
1151 sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -07001152 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
1153 Locale revised = Locale.getDefault();
1154 if (revised == null || mLocale == null ||
1155 !(revised.equals(mLocale))) {
1156 mLocale = revised;
1157
1158 synchronized (mAppWidgetIds) {
1159 int N = mInstalledProviders.size();
1160 for (int i=N-1; i>=0; i--) {
1161 Provider p = mInstalledProviders.get(i);
1162 String pkgName = p.info.provider.getPackageName();
1163 updateProvidersForPackageLocked(pkgName);
1164 }
1165 saveStateLocked();
1166 }
1167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001169 boolean added = false;
Joe Onoratod070e892011-01-07 20:50:37 -08001170 boolean changed = false;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001171 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001172 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001173 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1174 added = true;
Joe Onorato94258cd2010-08-24 16:45:40 -04001175 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001176 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1177 added = false;
1178 } else {
1179 Uri uri = intent.getData();
1180 if (uri == null) {
1181 return;
1182 }
1183 String pkgName = uri.getSchemeSpecificPart();
1184 if (pkgName == null) {
1185 return;
1186 }
1187 pkgList = new String[] { pkgName };
1188 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
Joe Onoratod070e892011-01-07 20:50:37 -08001189 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001190 }
1191 if (pkgList == null || pkgList.length == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 return;
1193 }
Joe Onoratod070e892011-01-07 20:50:37 -08001194 if (added || changed) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001195 synchronized (mAppWidgetIds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 Bundle extras = intent.getExtras();
Joe Onoratod070e892011-01-07 20:50:37 -08001197 if (changed || (extras != null &&
1198 extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001199 for (String pkgName : pkgList) {
1200 // The package was just upgraded
1201 updateProvidersForPackageLocked(pkgName);
1202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 } else {
1204 // The package was just added
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001205 for (String pkgName : pkgList) {
1206 addProvidersForPackageLocked(pkgName);
1207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209 saveStateLocked();
1210 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001211 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 Bundle extras = intent.getExtras();
1213 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
1214 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
1215 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001216 synchronized (mAppWidgetIds) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001217 for (String pkgName : pkgList) {
1218 removeProvidersForPackageLocked(pkgName);
1219 saveStateLocked();
1220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 }
1222 }
1223 }
1224 }
1225 }
1226 };
1227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 void addProvidersForPackageLocked(String pkgName) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001229 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001230 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1232 PackageManager.GET_META_DATA);
1233
Bjorn Bringert5f857802010-02-10 23:09:48 +00001234 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 for (int i=0; i<N; i++) {
1236 ResolveInfo ri = broadcastReceivers.get(i);
1237 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc2010-08-24 17:02:09 -04001238 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1239 continue;
1240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 if (pkgName.equals(ai.packageName)) {
1242 addProviderLocked(ri);
1243 }
1244 }
1245 }
1246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 void updateProvidersForPackageLocked(String pkgName) {
Romain Guya5475592009-07-01 17:20:08 -07001248 HashSet<String> keep = new HashSet<String>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001249 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
Joe Onoratof6133fe2010-02-01 18:24:46 -05001250 intent.setPackage(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
1252 PackageManager.GET_META_DATA);
1253
1254 // add the missing ones and collect which ones to keep
Bjorn Bringert5f857802010-02-10 23:09:48 +00001255 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 for (int i=0; i<N; i++) {
1257 ResolveInfo ri = broadcastReceivers.get(i);
1258 ActivityInfo ai = ri.activityInfo;
Joe Onorato331fbdc2010-08-24 17:02:09 -04001259 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1260 continue;
1261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 if (pkgName.equals(ai.packageName)) {
1263 ComponentName component = new ComponentName(ai.packageName, ai.name);
1264 Provider p = lookupProviderLocked(component);
1265 if (p == null) {
1266 if (addProviderLocked(ri)) {
1267 keep.add(ai.name);
1268 }
1269 } else {
1270 Provider parsed = parseProviderInfoXml(component, ri);
1271 if (parsed != null) {
1272 keep.add(ai.name);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001273 // Use the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 p.info = parsed.info;
1275 // If it's enabled
1276 final int M = p.instances.size();
1277 if (M > 0) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001278 int[] appWidgetIds = getAppWidgetIds(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 // Reschedule for the new updatePeriodMillis (don't worry about handling
1280 // it specially if updatePeriodMillis didn't change because we just sent
1281 // an update, and the next one will be updatePeriodMillis from now).
1282 cancelBroadcasts(p);
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001283 registerForBroadcastsLocked(p, appWidgetIds);
1284 // If it's currently showing, call back with the new AppWidgetProviderInfo.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 for (int j=0; j<M; j++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001286 AppWidgetId id = p.instances.get(j);
Joe Onoratoa8a8a422010-06-16 15:06:16 -04001287 id.views = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 if (id.host != null && id.host.callbacks != null) {
1289 try {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001290 id.host.callbacks.providerChanged(id.appWidgetId, p.info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 } catch (RemoteException ex) {
1292 // It failed; remove the callback. No need to prune because
1293 // we know that this host is still referenced by this
1294 // instance.
1295 id.host.callbacks = null;
1296 }
1297 }
1298 }
1299 // Now that we've told the host, push out an update.
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001300 sendUpdateIntentLocked(p, appWidgetIds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302 }
1303 }
1304 }
1305 }
1306
1307 // prune the ones we don't want to keep
1308 N = mInstalledProviders.size();
1309 for (int i=N-1; i>=0; i--) {
1310 Provider p = mInstalledProviders.get(i);
1311 if (pkgName.equals(p.info.provider.getPackageName())
1312 && !keep.contains(p.info.provider.getClassName())) {
1313 removeProviderLocked(i, p);
1314 }
1315 }
1316 }
1317
1318 void removeProvidersForPackageLocked(String pkgName) {
1319 int N = mInstalledProviders.size();
1320 for (int i=N-1; i>=0; i--) {
1321 Provider p = mInstalledProviders.get(i);
1322 if (pkgName.equals(p.info.provider.getPackageName())) {
1323 removeProviderLocked(i, p);
1324 }
1325 }
1326
1327 // Delete the hosts for this package too
1328 //
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001329 // By now, we have removed any AppWidgets that were in any hosts here,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 // so we don't need to worry about sending DISABLE broadcasts to them.
1331 N = mHosts.size();
1332 for (int i=N-1; i>=0; i--) {
1333 Host host = mHosts.get(i);
1334 if (pkgName.equals(host.packageName)) {
1335 deleteHostLocked(host);
1336 }
1337 }
1338 }
1339}
1340