AppWidgetService.java revision 0aa2d42e87e4a1ed5b83f356690e465d6a3587cc
1/*
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;
21import android.appwidget.AppWidgetManager;
22import android.appwidget.AppWidgetProviderInfo;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.ServiceConnection;
29import android.content.pm.PackageManager;
30import android.os.Bundle;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.os.UserHandle;
34import android.util.Pair;
35import android.util.Slog;
36import android.util.SparseArray;
37import android.widget.RemoteViews;
38
39import com.android.internal.appwidget.IAppWidgetHost;
40import com.android.internal.appwidget.IAppWidgetService;
41import com.android.internal.widget.IRemoteViewsAdapterConnection;
42
43import java.io.FileDescriptor;
44import java.io.PrintWriter;
45import java.util.ArrayList;
46import java.util.List;
47import java.util.Locale;
48
49
50/**
51 * Redirects calls to this service to the instance of the service for the appropriate user.
52 */
53class AppWidgetService extends IAppWidgetService.Stub
54{
55    private static final String TAG = "AppWidgetService";
56
57    /*
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;
65        AppWidgetProviderInfo info;
66        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
67        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;
77        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
78        IAppWidgetHost callbacks;
79        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
84    static class AppWidgetId {
85        int appWidgetId;
86        Provider provider;
87        RemoteViews views;
88        Host host;
89    }
90
91    /**
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 {
97        private final IBinder mConnectionCb;
98
99        ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
100            mConnectionCb = connectionCb;
101        }
102        public void onServiceConnected(ComponentName name, IBinder service) {
103            final IRemoteViewsAdapterConnection cb =
104                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
105            try {
106                cb.onServiceConnected(service);
107            } catch (Exception e) {
108                e.printStackTrace();
109            }
110        }
111        public void onServiceDisconnected(ComponentName name) {
112            disconnect();
113        }
114        public void disconnect() {
115            final IRemoteViewsAdapterConnection cb =
116                IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
117            try {
118                cb.onServiceDisconnected();
119            } catch (Exception e) {
120                e.printStackTrace();
121            }
122        }
123    }
124
125    Context mContext;
126    Locale mLocale;
127    PackageManager mPackageManager;
128    AlarmManager mAlarmManager;
129    ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
130    int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
131    final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
132    ArrayList<Host> mHosts = new ArrayList<Host>();
133    boolean mSafeMode;
134
135
136    private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
137
138    AppWidgetService(Context context) {
139        mContext = context;
140        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
141        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
142        mAppWidgetServices.append(0, primary);
143    }
144
145    public void systemReady(boolean safeMode) {
146        mSafeMode = safeMode;
147
148        mAppWidgetServices.get(0).systemReady(safeMode);
149
150        // Register for the boot completed broadcast, so we can send the
151        // ENABLE broacasts. If we try to send them now, they time out,
152        // because the system isn't ready to handle them yet.
153        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
154                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
155
156        // Register for configuration changes so we can update the names
157        // of the widgets when the locale changes.
158        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
159                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
160
161        // 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);
165        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
166        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
167        filter.addDataScheme("package");
168        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
169                filter, null, null);
170        // Register for events related to sdcard installation.
171        IntentFilter sdFilter = new IntentFilter();
172        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
173        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
174        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
175                sdFilter, null, null);
176
177        IntentFilter userFilter = new IntentFilter();
178        userFilter.addAction(Intent.ACTION_USER_REMOVED);
179        mContext.registerReceiver(new BroadcastReceiver() {
180            @Override
181            public void onReceive(Context context, Intent intent) {
182                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
183            }
184        }, userFilter);
185
186        IntentFilter userStopFilter = new IntentFilter();
187        userStopFilter.addAction(Intent.ACTION_USER_STOPPED);
188        mContext.registerReceiverAsUser(new BroadcastReceiver() {
189            @Override
190            public void onReceive(Context context, Intent intent) {
191                onUserStopped(getSendingUserId());
192            }
193        }, UserHandle.ALL, userFilter, null, null);
194    }
195
196    @Override
197    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
198        return getImplForUser(UserHandle.getCallingUserId()).allocateAppWidgetId(
199                packageName, hostId);
200    }
201
202    @Override
203    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
204        getImplForUser(UserHandle.getCallingUserId()).deleteAppWidgetId(appWidgetId);
205    }
206
207    @Override
208    public void deleteHost(int hostId) throws RemoteException {
209        getImplForUser(UserHandle.getCallingUserId()).deleteHost(hostId);
210    }
211
212    @Override
213    public void deleteAllHosts() throws RemoteException {
214        getImplForUser(UserHandle.getCallingUserId()).deleteAllHosts();
215    }
216
217    @Override
218    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
219            throws RemoteException {
220        getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetId(appWidgetId, provider,
221                options);
222    }
223
224    @Override
225    public boolean bindAppWidgetIdIfAllowed(
226            String packageName, int appWidgetId, ComponentName provider, Bundle options)
227                    throws RemoteException {
228        return getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetIdIfAllowed(
229                packageName, appWidgetId, provider, options);
230    }
231
232    @Override
233    public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
234        return getImplForUser(UserHandle.getCallingUserId()).hasBindAppWidgetPermission(
235                packageName);
236    }
237
238    @Override
239    public void setBindAppWidgetPermission(String packageName, boolean permission)
240            throws RemoteException {
241        getImplForUser(UserHandle.getCallingUserId()).setBindAppWidgetPermission(
242                packageName, permission);
243    }
244
245    @Override
246    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
247            throws RemoteException {
248        getImplForUser(UserHandle.getCallingUserId()).bindRemoteViewsService(
249                appWidgetId, intent, connection);
250    }
251
252    @Override
253    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
254            List<RemoteViews> updatedViews) throws RemoteException {
255        return getImplForUser(UserHandle.getCallingUserId()).startListening(host,
256                packageName, hostId, updatedViews);
257    }
258
259    public void onUserRemoved(int userId) {
260        AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
261        if (userId < 1) return;
262
263        if (impl == null) {
264            AppWidgetServiceImpl.getSettingsFile(userId).delete();
265        } else {
266            impl.onUserRemoved();
267        }
268    }
269
270    public void onUserStopped(int userId) {
271    }
272
273    private AppWidgetServiceImpl getImplForUser(int userId) {
274        AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
275        if (service == null) {
276            Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
277            // TODO: Verify that it's a valid user
278            service = new AppWidgetServiceImpl(mContext, userId);
279            service.systemReady(mSafeMode);
280            // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
281            service.sendInitialBroadcasts();
282            mAppWidgetServices.append(userId, service);
283        }
284
285        return service;
286    }
287
288    @Override
289    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
290        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetIds(provider);
291    }
292
293    @Override
294    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
295        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetInfo(appWidgetId);
296    }
297
298    @Override
299    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
300        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetViews(appWidgetId);
301    }
302
303    @Override
304    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
305        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetOptions(appWidgetId, options);
306    }
307
308    @Override
309    public Bundle getAppWidgetOptions(int appWidgetId) {
310        return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetOptions(appWidgetId);
311    }
312
313    static int[] getAppWidgetIds(Provider p) {
314        int instancesSize = p.instances.size();
315        int appWidgetIds[] = new int[instancesSize];
316        for (int i=0; i<instancesSize; i++) {
317            appWidgetIds[i] = p.instances.get(i).appWidgetId;
318        }
319        return appWidgetIds;
320    }
321
322    @Override
323    public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
324        return getImplForUser(UserHandle.getCallingUserId()).getInstalledProviders();
325    }
326
327    @Override
328    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
329            throws RemoteException {
330        getImplForUser(UserHandle.getCallingUserId()).notifyAppWidgetViewDataChanged(
331                appWidgetIds, viewId);
332    }
333
334    @Override
335    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
336            throws RemoteException {
337        getImplForUser(UserHandle.getCallingUserId()).partiallyUpdateAppWidgetIds(
338                appWidgetIds, views);
339    }
340
341    @Override
342    public void stopListening(int hostId) throws RemoteException {
343        getImplForUser(UserHandle.getCallingUserId()).stopListening(hostId);
344    }
345
346    @Override
347    public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
348        getImplForUser(UserHandle.getCallingUserId()).unbindRemoteViewsService(
349                appWidgetId, intent);
350    }
351
352    @Override
353    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
354        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetIds(appWidgetIds, views);
355    }
356
357    @Override
358    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
359            throws RemoteException {
360        getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetProvider(provider, views);
361    }
362
363    @Override
364    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
365        // Dump the state of all the app widget providers
366        for (int i = 0; i < mAppWidgetServices.size(); i++) {
367            AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
368            service.dump(fd, pw, args);
369        }
370    }
371
372    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
373        public void onReceive(Context context, Intent intent) {
374            String action = intent.getAction();
375            // Slog.d(TAG, "received " + action);
376            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
377                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
378                if (userId >= 0) {
379                    getImplForUser(userId).sendInitialBroadcasts();
380                } else {
381                    Slog.w(TAG, "Not user handle supplied in " + intent);
382                }
383            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
384                for (int i = 0; i < mAppWidgetServices.size(); i++) {
385                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
386                    service.onConfigurationChanged();
387                }
388            } else {
389                int sendingUser = getSendingUserId();
390                if (sendingUser == UserHandle.USER_ALL) {
391                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
392                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
393                        service.onBroadcastReceived(intent);
394                    }
395                } else {
396                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
397                    if (service != null) {
398                        service.onBroadcastReceived(intent);
399                    }
400                }
401            }
402        }
403    };
404}
405