blob: 38f4554caf5ca019b5cef11722f67d4ee1d869b1 [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;
Adam Cohene8724c82012-04-19 17:11:40 -070031import android.os.Bundle;
Winson Chung81f39eb2011-01-11 18:05:01 -080032import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.RemoteException;
Winson Chung81f39eb2011-01-11 18:05:01 -080034import android.util.Pair;
Joe Onorato8a9b2202010-02-26 18:56:32 -080035import android.util.Slog;
Amith Yamasani742a6712011-05-04 14:49:28 -070036import android.util.SparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.widget.RemoteViews;
38
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070039import com.android.internal.appwidget.IAppWidgetHost;
Winson Chung81f39eb2011-01-11 18:05:01 -080040import com.android.internal.appwidget.IAppWidgetService;
Winson Chung81f39eb2011-01-11 18:05:01 -080041import com.android.internal.widget.IRemoteViewsAdapterConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
Adam Cohen97300312011-10-12 15:48:13 -070043import java.io.FileDescriptor;
Adam Cohen97300312011-10-12 15:48:13 -070044import java.io.PrintWriter;
45import java.util.ArrayList;
Adam Cohen97300312011-10-12 15:48:13 -070046import java.util.List;
47import java.util.Locale;
48
Amith Yamasani742a6712011-05-04 14:49:28 -070049
50/**
51 * Redirects calls to this service to the instance of the service for the appropriate user.
52 */
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070053class AppWidgetService extends IAppWidgetService.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054{
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070055 private static final String TAG = "AppWidgetService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 /*
58 * When identifying a Host or Provider based on the calling process, use the uid field.
59 * When identifying a Host or Provider based on a package manager broadcast, use the
60 * package given.
61 */
62
63 static class Provider {
64 int uid;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070065 AppWidgetProviderInfo info;
Romain Guya5475592009-07-01 17:20:08 -070066 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 PendingIntent broadcast;
68 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
69
70 int tag; // for use while saving state (the index)
71 }
72
73 static class Host {
74 int uid;
75 int hostId;
76 String packageName;
Romain Guya5475592009-07-01 17:20:08 -070077 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070078 IAppWidgetHost callbacks;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
80
81 int tag; // for use while saving state (the index)
82 }
83
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070084 static class AppWidgetId {
85 int appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 Provider provider;
87 RemoteViews views;
88 Host host;
89 }
90
Winson Chung81f39eb2011-01-11 18:05:01 -080091 /**
92 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
93 * This needs to be a static inner class since a reference to the ServiceConnection is held
94 * globally and may lead us to leak AppWidgetService instances (if there were more than one).
95 */
96 static class ServiceConnectionProxy implements ServiceConnection {
Winson Chung81f39eb2011-01-11 18:05:01 -080097 private final IBinder mConnectionCb;
98
Winson Chung16c8d8a2011-01-20 16:19:33 -080099 ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
Winson Chung81f39eb2011-01-11 18:05:01 -0800100 mConnectionCb = connectionCb;
101 }
102 public void onServiceConnected(ComponentName name, IBinder service) {
Winson Chung16c8d8a2011-01-20 16:19:33 -0800103 final IRemoteViewsAdapterConnection cb =
Winson Chung81f39eb2011-01-11 18:05:01 -0800104 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
105 try {
106 cb.onServiceConnected(service);
Adam Cohenc2be22c2011-03-16 16:33:53 -0700107 } catch (Exception e) {
Winson Chung81f39eb2011-01-11 18:05:01 -0800108 e.printStackTrace();
109 }
110 }
111 public void onServiceDisconnected(ComponentName name) {
Winson Chung16c8d8a2011-01-20 16:19:33 -0800112 disconnect();
113 }
114 public void disconnect() {
115 final IRemoteViewsAdapterConnection cb =
Winson Chung81f39eb2011-01-11 18:05:01 -0800116 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
117 try {
118 cb.onServiceDisconnected();
Adam Cohenc2be22c2011-03-16 16:33:53 -0700119 } catch (Exception e) {
Winson Chung81f39eb2011-01-11 18:05:01 -0800120 e.printStackTrace();
121 }
122 }
123 }
124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 Context mContext;
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700126 Locale mLocale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 PackageManager mPackageManager;
128 AlarmManager mAlarmManager;
Romain Guya5475592009-07-01 17:20:08 -0700129 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700130 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
Romain Guya5475592009-07-01 17:20:08 -0700131 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
132 ArrayList<Host> mHosts = new ArrayList<Host>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 boolean mSafeMode;
134
Amith Yamasani742a6712011-05-04 14:49:28 -0700135
136 private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
Adam Cohen7bb98832011-10-05 18:10:13 -0700137
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700138 AppWidgetService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 mContext = context;
Amith Yamasani742a6712011-05-04 14:49:28 -0700140 mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
141 AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
142 mAppWidgetServices.append(0, primary);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 }
144
145 public void systemReady(boolean safeMode) {
146 mSafeMode = safeMode;
147
Amith Yamasani742a6712011-05-04 14:49:28 -0700148 mAppWidgetServices.get(0).systemReady(safeMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
150 // Register for the boot completed broadcast, so we can send the
Amith Yamasani742a6712011-05-04 14:49:28 -0700151 // ENABLE broacasts. If we try to send them now, they time out,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 // because the system isn't ready to handle them yet.
153 mContext.registerReceiver(mBroadcastReceiver,
154 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
155
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700156 // Register for configuration changes so we can update the names
157 // of the widgets when the locale changes.
Amith Yamasani742a6712011-05-04 14:49:28 -0700158 mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
159 Intent.ACTION_CONFIGURATION_CHANGED), null, null);
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 // Register for broadcasts about package install, etc., so we can
162 // update the provider list.
163 IntentFilter filter = new IntentFilter();
164 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Joe Onoratod070e892011-01-07 20:50:37 -0800165 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
167 filter.addDataScheme("package");
168 mContext.registerReceiver(mBroadcastReceiver, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800169 // Register for events related to sdcard installation.
170 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800171 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
172 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800173 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
Amith Yamasani13593602012-03-22 16:16:17 -0700174
175 IntentFilter userFilter = new IntentFilter();
176 userFilter.addAction(Intent.ACTION_USER_REMOVED);
177 mContext.registerReceiver(new BroadcastReceiver() {
178 @Override
179 public void onReceive(Context context, Intent intent) {
180 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
181 }
182 }, userFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 }
184
Amith Yamasani742a6712011-05-04 14:49:28 -0700185 @Override
186 public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
187 return getImplForUser().allocateAppWidgetId(packageName, hostId);
Jeff Sharkey15d161f2011-09-01 21:30:56 -0700188 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700189
190 @Override
191 public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
192 getImplForUser().deleteAppWidgetId(appWidgetId);
Adam Cohen7bb98832011-10-05 18:10:13 -0700193 }
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 @Override
Amith Yamasani742a6712011-05-04 14:49:28 -0700196 public void deleteHost(int hostId) throws RemoteException {
197 getImplForUser().deleteHost(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 }
199
Amith Yamasani742a6712011-05-04 14:49:28 -0700200 @Override
201 public void deleteAllHosts() throws RemoteException {
202 getImplForUser().deleteAllHosts();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 }
204
Amith Yamasani742a6712011-05-04 14:49:28 -0700205 @Override
206 public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
207 getImplForUser().bindAppWidgetId(appWidgetId, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 }
209
Amith Yamasani742a6712011-05-04 14:49:28 -0700210 @Override
Michael Jurka61a5b012012-04-13 10:39:45 -0700211 public boolean bindAppWidgetIdIfAllowed(
212 String packageName, int appWidgetId, ComponentName provider) throws RemoteException {
213 return getImplForUser().bindAppWidgetIdIfAllowed(packageName, appWidgetId, provider);
214 }
215
216 @Override
217 public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
218 return getImplForUser().hasBindAppWidgetPermission(packageName);
219 }
220
221 @Override
222 public void setBindAppWidgetPermission(String packageName, boolean permission)
223 throws RemoteException {
224 getImplForUser().setBindAppWidgetPermission(packageName, permission);
225 }
226
227 @Override
Amith Yamasani742a6712011-05-04 14:49:28 -0700228 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
229 throws RemoteException {
230 getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
Winson Chung81f39eb2011-01-11 18:05:01 -0800231 }
232
Amith Yamasani742a6712011-05-04 14:49:28 -0700233 @Override
234 public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
235 List<RemoteViews> updatedViews) throws RemoteException {
236 return getImplForUser().startListening(host, packageName, hostId, updatedViews);
Winson Chung81f39eb2011-01-11 18:05:01 -0800237 }
238
Amith Yamasani13593602012-03-22 16:16:17 -0700239 public void onUserRemoved(int userId) {
240 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
241 if (userId < 1) return;
242
243 if (impl == null) {
244 AppWidgetServiceImpl.getSettingsFile(userId).delete();
245 } else {
246 impl.onUserRemoved();
247 }
Winson Chung84bbb022011-02-21 13:57:45 -0800248 }
249
Amith Yamasani742a6712011-05-04 14:49:28 -0700250 private AppWidgetServiceImpl getImplForUser() {
251 final int userId = Binder.getOrigCallingUser();
252 AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
253 if (service == null) {
254 Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
255 // TODO: Verify that it's a valid user
256 service = new AppWidgetServiceImpl(mContext, userId);
257 service.systemReady(mSafeMode);
258 // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
259 service.sendInitialBroadcasts();
260 mAppWidgetServices.append(userId, service);
Winson Chung84bbb022011-02-21 13:57:45 -0800261 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700262
263 return service;
Winson Chung84bbb022011-02-21 13:57:45 -0800264 }
265
Amith Yamasani742a6712011-05-04 14:49:28 -0700266 @Override
267 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
268 return getImplForUser().getAppWidgetIds(provider);
Winson Chung84bbb022011-02-21 13:57:45 -0800269 }
270
Amith Yamasani742a6712011-05-04 14:49:28 -0700271 @Override
272 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
273 return getImplForUser().getAppWidgetInfo(appWidgetId);
Winson Chung81f39eb2011-01-11 18:05:01 -0800274 }
275
Amith Yamasani742a6712011-05-04 14:49:28 -0700276 @Override
277 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
278 return getImplForUser().getAppWidgetViews(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 }
280
Adam Cohene8724c82012-04-19 17:11:40 -0700281 @Override
Adam Cohend2097eb2012-05-01 18:10:28 -0700282 public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
283 getImplForUser().updateAppWidgetOptions(appWidgetId, options);
Adam Cohene8724c82012-04-19 17:11:40 -0700284 }
285
286 @Override
Adam Cohend2097eb2012-05-01 18:10:28 -0700287 public Bundle getAppWidgetOptions(int appWidgetId) {
288 return getImplForUser().getAppWidgetOptions(appWidgetId);
Adam Cohene8724c82012-04-19 17:11:40 -0700289 }
290
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700291 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700293 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700295 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700297 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700299
300 @Override
301 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
302 return getImplForUser().getInstalledProviders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
304
Amith Yamasani742a6712011-05-04 14:49:28 -0700305 @Override
306 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
307 throws RemoteException {
308 getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 }
310
Amith Yamasani742a6712011-05-04 14:49:28 -0700311 @Override
312 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
313 throws RemoteException {
314 getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
Amith Yamasani742a6712011-05-04 14:49:28 -0700317 @Override
318 public void stopListening(int hostId) throws RemoteException {
319 getImplForUser().stopListening(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 }
321
Amith Yamasani742a6712011-05-04 14:49:28 -0700322 @Override
323 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
324 getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326
Amith Yamasani742a6712011-05-04 14:49:28 -0700327 @Override
328 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
329 getImplForUser().updateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 }
Adam Cohen97300312011-10-12 15:48:13 -0700331
Amith Yamasani742a6712011-05-04 14:49:28 -0700332 @Override
333 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
334 throws RemoteException {
335 getImplForUser().updateAppWidgetProvider(provider, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
337
Amith Yamasani742a6712011-05-04 14:49:28 -0700338 @Override
339 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
340 // Dump the state of all the app widget providers
341 for (int i = 0; i < mAppWidgetServices.size(); i++) {
342 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
343 service.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 }
345 }
346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
348 public void onReceive(Context context, Intent intent) {
349 String action = intent.getAction();
Amith Yamasani742a6712011-05-04 14:49:28 -0700350 // Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700352 getImplForUser().sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700353 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700354 for (int i = 0; i < mAppWidgetServices.size(); i++) {
355 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
356 service.onConfigurationChanged();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 } else {
Amith Yamasani483f3b02012-03-13 16:08:00 -0700359 for (int i = 0; i < mAppWidgetServices.size(); i++) {
360 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
361 service.onBroadcastReceived(intent);
362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
364 }
365 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366}