blob: eb024e94245c54569639e67fd3da0fad3d88aab4 [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);
Amith Yamasani13593602012-03-22 16:16:17 -0700173
174 IntentFilter userFilter = new IntentFilter();
175 userFilter.addAction(Intent.ACTION_USER_REMOVED);
176 mContext.registerReceiver(new BroadcastReceiver() {
177 @Override
178 public void onReceive(Context context, Intent intent) {
179 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
180 }
181 }, userFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 }
183
Amith Yamasani742a6712011-05-04 14:49:28 -0700184 @Override
185 public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
186 return getImplForUser().allocateAppWidgetId(packageName, hostId);
Jeff Sharkey15d161f2011-09-01 21:30:56 -0700187 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700188
189 @Override
190 public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
191 getImplForUser().deleteAppWidgetId(appWidgetId);
Adam Cohen7bb98832011-10-05 18:10:13 -0700192 }
193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 @Override
Amith Yamasani742a6712011-05-04 14:49:28 -0700195 public void deleteHost(int hostId) throws RemoteException {
196 getImplForUser().deleteHost(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 }
198
Amith Yamasani742a6712011-05-04 14:49:28 -0700199 @Override
200 public void deleteAllHosts() throws RemoteException {
201 getImplForUser().deleteAllHosts();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 }
203
Amith Yamasani742a6712011-05-04 14:49:28 -0700204 @Override
205 public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
206 getImplForUser().bindAppWidgetId(appWidgetId, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
208
Amith Yamasani742a6712011-05-04 14:49:28 -0700209 @Override
210 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
211 throws RemoteException {
212 getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
Winson Chung81f39eb2011-01-11 18:05:01 -0800213 }
214
Amith Yamasani742a6712011-05-04 14:49:28 -0700215 @Override
216 public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
217 List<RemoteViews> updatedViews) throws RemoteException {
218 return getImplForUser().startListening(host, packageName, hostId, updatedViews);
Winson Chung81f39eb2011-01-11 18:05:01 -0800219 }
220
Amith Yamasani13593602012-03-22 16:16:17 -0700221 public void onUserRemoved(int userId) {
222 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
223 if (userId < 1) return;
224
225 if (impl == null) {
226 AppWidgetServiceImpl.getSettingsFile(userId).delete();
227 } else {
228 impl.onUserRemoved();
229 }
Winson Chung84bbb022011-02-21 13:57:45 -0800230 }
231
Amith Yamasani742a6712011-05-04 14:49:28 -0700232 private AppWidgetServiceImpl getImplForUser() {
233 final int userId = Binder.getOrigCallingUser();
234 AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
235 if (service == null) {
236 Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
237 // TODO: Verify that it's a valid user
238 service = new AppWidgetServiceImpl(mContext, userId);
239 service.systemReady(mSafeMode);
240 // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
241 service.sendInitialBroadcasts();
242 mAppWidgetServices.append(userId, service);
Winson Chung84bbb022011-02-21 13:57:45 -0800243 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700244
245 return service;
Winson Chung84bbb022011-02-21 13:57:45 -0800246 }
247
Amith Yamasani742a6712011-05-04 14:49:28 -0700248 @Override
249 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
250 return getImplForUser().getAppWidgetIds(provider);
Winson Chung84bbb022011-02-21 13:57:45 -0800251 }
252
Amith Yamasani742a6712011-05-04 14:49:28 -0700253 @Override
254 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
255 return getImplForUser().getAppWidgetInfo(appWidgetId);
Winson Chung81f39eb2011-01-11 18:05:01 -0800256 }
257
Amith Yamasani742a6712011-05-04 14:49:28 -0700258 @Override
259 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
260 return getImplForUser().getAppWidgetViews(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 }
262
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700263 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700265 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700267 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700269 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700271
272 @Override
273 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
274 return getImplForUser().getInstalledProviders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 }
276
Amith Yamasani742a6712011-05-04 14:49:28 -0700277 @Override
278 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
279 throws RemoteException {
280 getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
282
Amith Yamasani742a6712011-05-04 14:49:28 -0700283 @Override
284 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
285 throws RemoteException {
286 getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 }
288
Amith Yamasani742a6712011-05-04 14:49:28 -0700289 @Override
290 public void stopListening(int hostId) throws RemoteException {
291 getImplForUser().stopListening(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 }
293
Amith Yamasani742a6712011-05-04 14:49:28 -0700294 @Override
295 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
296 getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 }
298
Amith Yamasani742a6712011-05-04 14:49:28 -0700299 @Override
300 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
301 getImplForUser().updateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 }
Adam Cohen97300312011-10-12 15:48:13 -0700303
Amith Yamasani742a6712011-05-04 14:49:28 -0700304 @Override
305 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
306 throws RemoteException {
307 getImplForUser().updateAppWidgetProvider(provider, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 }
309
Amith Yamasani742a6712011-05-04 14:49:28 -0700310 @Override
311 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
312 // Dump the state of all the app widget providers
313 for (int i = 0; i < mAppWidgetServices.size(); i++) {
314 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
315 service.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317 }
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
320 public void onReceive(Context context, Intent intent) {
321 String action = intent.getAction();
Amith Yamasani742a6712011-05-04 14:49:28 -0700322 // Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700324 getImplForUser().sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700325 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700326 for (int i = 0; i < mAppWidgetServices.size(); i++) {
327 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
328 service.onConfigurationChanged();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 } else {
Amith Yamasani483f3b02012-03-13 16:08:00 -0700331 for (int i = 0; i < mAppWidgetServices.size(); i++) {
332 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
333 service.onBroadcastReceived(intent);
334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 }
336 }
337 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338}