blob: bf958a587c69433fb9c2804cf19ec8b879b4df5e [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
211 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
212 throws RemoteException {
213 getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
Winson Chung81f39eb2011-01-11 18:05:01 -0800214 }
215
Amith Yamasani742a6712011-05-04 14:49:28 -0700216 @Override
217 public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
218 List<RemoteViews> updatedViews) throws RemoteException {
219 return getImplForUser().startListening(host, packageName, hostId, updatedViews);
Winson Chung81f39eb2011-01-11 18:05:01 -0800220 }
221
Amith Yamasani13593602012-03-22 16:16:17 -0700222 public void onUserRemoved(int userId) {
223 AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
224 if (userId < 1) return;
225
226 if (impl == null) {
227 AppWidgetServiceImpl.getSettingsFile(userId).delete();
228 } else {
229 impl.onUserRemoved();
230 }
Winson Chung84bbb022011-02-21 13:57:45 -0800231 }
232
Amith Yamasani742a6712011-05-04 14:49:28 -0700233 private AppWidgetServiceImpl getImplForUser() {
234 final int userId = Binder.getOrigCallingUser();
235 AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
236 if (service == null) {
237 Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
238 // TODO: Verify that it's a valid user
239 service = new AppWidgetServiceImpl(mContext, userId);
240 service.systemReady(mSafeMode);
241 // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
242 service.sendInitialBroadcasts();
243 mAppWidgetServices.append(userId, service);
Winson Chung84bbb022011-02-21 13:57:45 -0800244 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700245
246 return service;
Winson Chung84bbb022011-02-21 13:57:45 -0800247 }
248
Amith Yamasani742a6712011-05-04 14:49:28 -0700249 @Override
250 public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
251 return getImplForUser().getAppWidgetIds(provider);
Winson Chung84bbb022011-02-21 13:57:45 -0800252 }
253
Amith Yamasani742a6712011-05-04 14:49:28 -0700254 @Override
255 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
256 return getImplForUser().getAppWidgetInfo(appWidgetId);
Winson Chung81f39eb2011-01-11 18:05:01 -0800257 }
258
Amith Yamasani742a6712011-05-04 14:49:28 -0700259 @Override
260 public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
261 return getImplForUser().getAppWidgetViews(appWidgetId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 }
263
Adam Cohene8724c82012-04-19 17:11:40 -0700264 @Override
265 public void updateAppWidgetExtras(int appWidgetId, Bundle extras) {
266 getImplForUser().updateAppWidgetExtras(appWidgetId, extras);
267 }
268
269 @Override
270 public Bundle getAppWidgetExtras(int appWidgetId) {
271 return getImplForUser().getAppWidgetExtras(appWidgetId);
272 }
273
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700274 static int[] getAppWidgetIds(Provider p) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 int instancesSize = p.instances.size();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700276 int appWidgetIds[] = new int[instancesSize];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 for (int i=0; i<instancesSize; i++) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700278 appWidgetIds[i] = p.instances.get(i).appWidgetId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700280 return appWidgetIds;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700282
283 @Override
284 public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
285 return getImplForUser().getInstalledProviders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
287
Amith Yamasani742a6712011-05-04 14:49:28 -0700288 @Override
289 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
290 throws RemoteException {
291 getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 }
293
Amith Yamasani742a6712011-05-04 14:49:28 -0700294 @Override
295 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
296 throws RemoteException {
297 getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 }
299
Amith Yamasani742a6712011-05-04 14:49:28 -0700300 @Override
301 public void stopListening(int hostId) throws RemoteException {
302 getImplForUser().stopListening(hostId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
304
Amith Yamasani742a6712011-05-04 14:49:28 -0700305 @Override
306 public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
307 getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 }
309
Amith Yamasani742a6712011-05-04 14:49:28 -0700310 @Override
311 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
312 getImplForUser().updateAppWidgetIds(appWidgetIds, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 }
Adam Cohen97300312011-10-12 15:48:13 -0700314
Amith Yamasani742a6712011-05-04 14:49:28 -0700315 @Override
316 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
317 throws RemoteException {
318 getImplForUser().updateAppWidgetProvider(provider, views);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320
Amith Yamasani742a6712011-05-04 14:49:28 -0700321 @Override
322 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
323 // Dump the state of all the app widget providers
324 for (int i = 0; i < mAppWidgetServices.size(); i++) {
325 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
326 service.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 }
328 }
329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
331 public void onReceive(Context context, Intent intent) {
332 String action = intent.getAction();
Amith Yamasani742a6712011-05-04 14:49:28 -0700333 // Slog.d(TAG, "received " + action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700335 getImplForUser().sendInitialBroadcasts();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700336 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700337 for (int i = 0; i < mAppWidgetServices.size(); i++) {
338 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
339 service.onConfigurationChanged();
Eric Fischer63c2d9e2009-10-22 15:22:50 -0700340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 } else {
Amith Yamasani483f3b02012-03-13 16:08:00 -0700342 for (int i = 0; i < mAppWidgetServices.size(); i++) {
343 AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
344 service.onBroadcastReceived(intent);
345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347 }
348 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349}