AppWidgetService.java revision 2a00329c6d55c6cd9166e01963d7410e95d80d21
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.Binder;
31import android.os.Bundle;
32import android.os.IBinder;
33import android.os.RemoteException;
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.registerReceiver(mBroadcastReceiver,
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.registerReceiver(mBroadcastReceiver, new IntentFilter(
159                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.registerReceiver(mBroadcastReceiver, filter);
169        // Register for events related to sdcard installation.
170        IntentFilter sdFilter = new IntentFilter();
171        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
172        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
173        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
174
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_USER_HANDLE, -1));
181            }
182        }, userFilter);
183    }
184
185    @Override
186    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
187        return getImplForUser().allocateAppWidgetId(packageName, hostId);
188    }
189
190    @Override
191    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
192        getImplForUser().deleteAppWidgetId(appWidgetId);
193    }
194
195    @Override
196    public void deleteHost(int hostId) throws RemoteException {
197        getImplForUser().deleteHost(hostId);
198    }
199
200    @Override
201    public void deleteAllHosts() throws RemoteException {
202        getImplForUser().deleteAllHosts();
203    }
204
205    @Override
206    public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
207        getImplForUser().bindAppWidgetId(appWidgetId, provider);
208    }
209
210    @Override
211    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
228    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
229            throws RemoteException {
230        getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
231    }
232
233    @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);
237    }
238
239    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        }
248    }
249
250    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);
261        }
262
263        return service;
264    }
265
266    @Override
267    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
268        return getImplForUser().getAppWidgetIds(provider);
269    }
270
271    @Override
272    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
273        return getImplForUser().getAppWidgetInfo(appWidgetId);
274    }
275
276    @Override
277    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
278        return getImplForUser().getAppWidgetViews(appWidgetId);
279    }
280
281    @Override
282    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
283        getImplForUser().updateAppWidgetOptions(appWidgetId, options);
284    }
285
286    @Override
287    public Bundle getAppWidgetOptions(int appWidgetId) {
288        return getImplForUser().getAppWidgetOptions(appWidgetId);
289    }
290
291    static int[] getAppWidgetIds(Provider p) {
292        int instancesSize = p.instances.size();
293        int appWidgetIds[] = new int[instancesSize];
294        for (int i=0; i<instancesSize; i++) {
295            appWidgetIds[i] = p.instances.get(i).appWidgetId;
296        }
297        return appWidgetIds;
298    }
299
300    @Override
301    public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
302        return getImplForUser().getInstalledProviders();
303    }
304
305    @Override
306    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
307            throws RemoteException {
308        getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
309    }
310
311    @Override
312    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
313            throws RemoteException {
314        getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
315    }
316
317    @Override
318    public void stopListening(int hostId) throws RemoteException {
319        getImplForUser().stopListening(hostId);
320    }
321
322    @Override
323    public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
324        getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
325    }
326
327    @Override
328    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
329        getImplForUser().updateAppWidgetIds(appWidgetIds, views);
330    }
331
332    @Override
333    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
334            throws RemoteException {
335        getImplForUser().updateAppWidgetProvider(provider, views);
336    }
337
338    @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);
344        }
345    }
346
347    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
348        public void onReceive(Context context, Intent intent) {
349            String action = intent.getAction();
350            // Slog.d(TAG, "received " + action);
351            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
352                getImplForUser().sendInitialBroadcasts();
353            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
354                for (int i = 0; i < mAppWidgetServices.size(); i++) {
355                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
356                    service.onConfigurationChanged();
357                }
358            } else {
359                for (int i = 0; i < mAppWidgetServices.size(); i++) {
360                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
361                    service.onBroadcastReceived(intent);
362                }
363            }
364        }
365    };
366}
367