blob: a85b605228b8e86e2be79a455ad337a6a71df0a0 [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;
Winson Chung81f39eb2011-01-11 18:05:01 -080028import android.content.ServiceConnection;
Winson Chung81f39eb2011-01-11 18:05:01 -080029import android.content.pm.PackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.Binder;
Winson Chung81f39eb2011-01-11 18:05:01 -080031import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.RemoteException;
Winson Chung81f39eb2011-01-11 18:05:01 -080033import android.util.Pair;
Joe Onorato8a9b2202010-02-26 18:56:32 -080034import android.util.Slog;
Amith Yamasani742a6712011-05-04 14:49:28 -070035import android.util.SparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.widget.RemoteViews;
37
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070038import com.android.internal.appwidget.IAppWidgetHost;
Winson Chung81f39eb2011-01-11 18:05:01 -080039import com.android.internal.appwidget.IAppWidgetService;
Winson Chung81f39eb2011-01-11 18:05:01 -080040import com.android.internal.widget.IRemoteViewsAdapterConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Adam Cohen97300312011-10-12 15:48:13 -070042import java.io.FileDescriptor;
Adam Cohen97300312011-10-12 15:48:13 -070043import java.io.PrintWriter;
44import java.util.ArrayList;
Adam Cohen97300312011-10-12 15:48:13 -070045import java.util.List;
46import java.util.Locale;
47
Amith Yamasani742a6712011-05-04 14:49:28 -070048
49/**
50 * Redirects calls to this service to the instance of the service for the appropriate user.
51 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070052class AppWidgetService extends IAppWidgetService.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053{
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070054 private static final String TAG = "AppWidgetService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 /*
57 * When identifying a Host or Provider based on the calling process, use the uid field.
58 * When identifying a Host or Provider based on a package manager broadcast, use the
59 * package given.
60 */
61
62 static class Provider {
63 int uid;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070064 AppWidgetProviderInfo info;
Romain Guya5475592009-07-01 17:20:08 -070065 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 PendingIntent broadcast;
67 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
68
69 int tag; // for use while saving state (the index)
70 }
71
72 static class Host {
73 int uid;
74 int hostId;
75 String packageName;
Romain Guya5475592009-07-01 17:20:08 -070076 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070077 IAppWidgetHost callbacks;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
79
80 int tag; // for use while saving state (the index)
81 }
82
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070083 static class AppWidgetId {
84 int appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 Provider provider;
86 RemoteViews views;
87 Host host;
88 }
89
Winson Chung81f39eb2011-01-11 18:05:01 -080090 /**
91 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
92 * This needs to be a static inner class since a reference to the ServiceConnection is held
93 * globally and may lead us to leak AppWidgetService instances (if there were more than one).
94 */
95 static class ServiceConnectionProxy implements ServiceConnection {
Winson Chung81f39eb2011-01-11 18:05:01 -080096 private final IBinder mConnectionCb;
97
Winson Chung16c8d8a2011-01-20 16:19:33 -080098 ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
Winson Chung81f39eb2011-01-11 18:05:01 -080099 mConnectionCb = connectionCb;
100 }
101 public void onServiceConnected(ComponentName name, IBinder service) {
Winson Chung16c8d8a2011-01-20 16:19:33 -0800102 final IRemoteViewsAdapterConnection cb =
Winson Chung81f39eb2011-01-11 18:05:01 -0800103 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
104 try {
105 cb.onServiceConnected(service);
Adam Cohenc2be22c2011-03-16 16:33:53 -0700106 } catch (Exception e) {
Winson Chung81f39eb2011-01-11 18:05:01 -0800107 e.printStackTrace();
108 }
109 }
110 public void onServiceDisconnected(ComponentName name) {
Winson Chung16c8d8a2011-01-20 16:19:33 -0800111 disconnect();
112 }
113 public void disconnect() {
114 final IRemoteViewsAdapterConnection cb =
Winson Chung81f39eb2011-01-11 18:05:01 -0800115 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
116 try {
117 cb.onServiceDisconnected();
Adam Cohenc2be22c2011-03-16 16:33:53 -0700118 } catch (Exception e) {
Winson Chung81f39eb2011-01-11 18:05:01 -0800119 e.printStackTrace();
120 }
121 }
122 }
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 Context mContext;
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700125 Locale mLocale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 PackageManager mPackageManager;
127 AlarmManager mAlarmManager;
Romain Guya5475592009-07-01 17:20:08 -0700128 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700129 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
Romain Guya5475592009-07-01 17:20:08 -0700130 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
131 ArrayList<Host> mHosts = new ArrayList<Host>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 boolean mSafeMode;
133
Amith Yamasani742a6712011-05-04 14:49:28 -0700134
135 private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
Adam Cohen7bb98832011-10-05 18:10:13 -0700136
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700137 AppWidgetService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 mContext = context;
Amith Yamasani742a6712011-05-04 14:49:28 -0700139 mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
140 AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
141 mAppWidgetServices.append(0, primary);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 }
143
144 public void systemReady(boolean safeMode) {
145 mSafeMode = safeMode;
146
Amith Yamasani742a6712011-05-04 14:49:28 -0700147 mAppWidgetServices.get(0).systemReady(safeMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
149 // Register for the boot completed broadcast, so we can send the
Amith Yamasani742a6712011-05-04 14:49:28 -0700150 // ENABLE broacasts. If we try to send them now, they time out,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 // because the system isn't ready to handle them yet.
152 mContext.registerReceiver(mBroadcastReceiver,
153 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
154
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700155 // Register for configuration changes so we can update the names
156 // of the widgets when the locale changes.
Amith Yamasani742a6712011-05-04 14:49:28 -0700157 mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
158 Intent.ACTION_CONFIGURATION_CHANGED), null, null);
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 // Register for broadcasts about package install, etc., so we can
161 // update the provider list.
162 IntentFilter filter = new IntentFilter();
163 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Joe Onoratod070e892011-01-07 20:50:37 -0800164 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
166 filter.addDataScheme("package");
167 mContext.registerReceiver(mBroadcastReceiver, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800168 // Register for events related to sdcard installation.
169 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800170 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
171 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800172 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 }
174
Amith Yamasani742a6712011-05-04 14:49:28 -0700175 @Override
176 public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
177 return getImplForUser().allocateAppWidgetId(packageName, hostId);
Jeff Sharkey15d161f2011-09-01 21:30:56 -0700178 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700179
180 @Override
181 public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
182 getImplForUser().deleteAppWidgetId(appWidgetId);
Adam Cohen7bb98832011-10-05 18:10:13 -0700183 }
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 @Override
Amith Yamasani742a6712011-05-04 14:49:28 -0700186 public void deleteHost(int hostId) throws RemoteException {
187 getImplForUser().deleteHost(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 }
189
Amith Yamasani742a6712011-05-04 14:49:28 -0700190 @Override
191 public void deleteAllHosts() throws RemoteException {
192 getImplForUser().deleteAllHosts();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 }
194
195 void cancelBroadcasts(Provider p) {
196 if (p.broadcast != null) {
197 mAlarmManager.cancel(p.broadcast);
198 long token = Binder.clearCallingIdentity();
199 try {
200 p.broadcast.cancel();
201 } finally {
202 Binder.restoreCallingIdentity(token);
203 }
204 p.broadcast = null;
205 }
206 }
207
Amith Yamasani742a6712011-05-04 14:49:28 -0700208 @Override
209 public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
210 getImplForUser().bindAppWidgetId(appWidgetId, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
212
Amith Yamasani742a6712011-05-04 14:49:28 -0700213 @Override
214 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
215 throws RemoteException {
216 getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
Winson Chung81f39eb2011-01-11 18:05:01 -0800217 }
218
Amith Yamasani742a6712011-05-04 14:49:28 -0700219 @Override
220 public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
221 List<RemoteViews> updatedViews) throws RemoteException {
222 return getImplForUser().startListening(host, packageName, hostId, updatedViews);
Winson Chung81f39eb2011-01-11 18:05:01 -0800223 }
224
Amith Yamasani742a6712011-05-04 14:49:28 -0700225 // TODO: Call this from PackageManagerService when a user is removed
226 public void removeUser(int userId) {
Winson Chung84bbb022011-02-21 13:57:45 -0800227 }
228
Amith Yamasani742a6712011-05-04 14:49:28 -0700229 private AppWidgetServiceImpl getImplForUser() {
230 final int userId = Binder.getOrigCallingUser();
231 AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
232 if (service == null) {
233 Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
234 // TODO: Verify that it's a valid user
235 service = new AppWidgetServiceImpl(mContext, userId);
236 service.systemReady(mSafeMode);
237 // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
238 service.sendInitialBroadcasts();
239 mAppWidgetServices.append(userId, service);
Winson Chung84bbb022011-02-21 13:57:45 -0800240 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700241
242 return service;
Winson Chung84bbb022011-02-21 13:57:45 -0800243 }
244
Amith Yamasani742a6712011-05-04 14:49:28 -0700245 @Override
246 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
247 return getImplForUser().getAppWidgetIds(provider);
Winson Chung84bbb022011-02-21 13:57:45 -0800248 }
249
Amith Yamasani742a6712011-05-04 14:49:28 -0700250 @Override
251 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
252 return getImplForUser().getAppWidgetInfo(appWidgetId);
Winson Chung81f39eb2011-01-11 18:05:01 -0800253 }
254
Amith Yamasani742a6712011-05-04 14:49:28 -0700255 @Override
256 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
257 return getImplForUser().getAppWidgetViews(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 }
259
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700260 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700262 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700264 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700266 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700268
269 @Override
270 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
271 return getImplForUser().getInstalledProviders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
273
Amith Yamasani742a6712011-05-04 14:49:28 -0700274 @Override
275 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
276 throws RemoteException {
277 getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 }
279
Amith Yamasani742a6712011-05-04 14:49:28 -0700280 @Override
281 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
282 throws RemoteException {
283 getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285
Amith Yamasani742a6712011-05-04 14:49:28 -0700286 @Override
287 public void stopListening(int hostId) throws RemoteException {
288 getImplForUser().stopListening(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 }
290
Amith Yamasani742a6712011-05-04 14:49:28 -0700291 @Override
292 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
293 getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 }
295
Amith Yamasani742a6712011-05-04 14:49:28 -0700296 @Override
297 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
298 getImplForUser().updateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 }
Adam Cohen97300312011-10-12 15:48:13 -0700300
Amith Yamasani742a6712011-05-04 14:49:28 -0700301 @Override
302 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
303 throws RemoteException {
304 getImplForUser().updateAppWidgetProvider(provider, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 }
306
Amith Yamasani742a6712011-05-04 14:49:28 -0700307 @Override
308 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
309 // Dump the state of all the app widget providers
310 for (int i = 0; i < mAppWidgetServices.size(); i++) {
311 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
312 service.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 }
314 }
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
317 public void onReceive(Context context, Intent intent) {
318 String action = intent.getAction();
Amith Yamasani742a6712011-05-04 14:49:28 -0700319 // Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700321 getImplForUser().sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700322 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700323 for (int i = 0; i < mAppWidgetServices.size(); i++) {
324 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
325 service.onConfigurationChanged();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 } else {
Amith Yamasani483f3b02012-03-13 16:08:00 -0700328 for (int i = 0; i < mAppWidgetServices.size(); i++) {
329 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
330 service.onBroadcastReceived(intent);
331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 }
333 }
334 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335}