AppWidgetService.java revision a1a2f967e2a0de4c4190a775ac314ad32288727e
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.ActivityManagerNative;
20import android.appwidget.AppWidgetProviderInfo;
21import android.content.BroadcastReceiver;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.os.Binder;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.HandlerThread;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.os.UserHandle;
34import android.util.Slog;
35import android.util.SparseArray;
36import android.widget.RemoteViews;
37
38import com.android.internal.appwidget.IAppWidgetHost;
39import com.android.internal.appwidget.IAppWidgetService;
40import com.android.internal.util.IndentingPrintWriter;
41
42import java.io.FileDescriptor;
43import java.io.PrintWriter;
44import java.util.List;
45import java.util.Locale;
46
47
48/**
49 * Redirects calls to this service to the instance of the service for the appropriate user.
50 */
51class AppWidgetService extends IAppWidgetService.Stub
52{
53    private static final String TAG = "AppWidgetService";
54
55    Context mContext;
56    Locale mLocale;
57    PackageManager mPackageManager;
58    boolean mSafeMode;
59    private final Handler mSaveStateHandler;
60
61    private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
62
63    AppWidgetService(Context context) {
64        mContext = context;
65
66        HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state");
67        handlerThread.start();
68        mSaveStateHandler = new Handler(handlerThread.getLooper());
69
70        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
71        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
72        mAppWidgetServices.append(0, primary);
73    }
74
75    public void systemReady(boolean safeMode) {
76        mSafeMode = safeMode;
77
78        mAppWidgetServices.get(0).systemReady(safeMode);
79
80        // Register for the boot completed broadcast, so we can send the
81        // ENABLE broacasts. If we try to send them now, they time out,
82        // because the system isn't ready to handle them yet.
83        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
84                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
85
86        // Register for configuration changes so we can update the names
87        // of the widgets when the locale changes.
88        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
89                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
90
91        // Register for broadcasts about package install, etc., so we can
92        // update the provider list.
93        IntentFilter filter = new IntentFilter();
94        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
95        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
96        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
97        filter.addDataScheme("package");
98        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
99                filter, null, null);
100        // Register for events related to sdcard installation.
101        IntentFilter sdFilter = new IntentFilter();
102        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
103        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
104        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
105                sdFilter, null, null);
106
107        IntentFilter userFilter = new IntentFilter();
108        userFilter.addAction(Intent.ACTION_USER_REMOVED);
109        userFilter.addAction(Intent.ACTION_USER_STOPPING);
110        mContext.registerReceiver(new BroadcastReceiver() {
111            @Override
112            public void onReceive(Context context, Intent intent) {
113                if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
114                    onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
115                            UserHandle.USER_NULL));
116                } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
117                    onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
118                            UserHandle.USER_NULL));
119                }
120            }
121        }, userFilter);
122    }
123
124    /**
125     * This returns the user id of the caller, if the caller is not the system process,
126     * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
127     * current user. TODO: Instead, have lockscreen make explicit calls with userId
128     */
129    private int getCallingOrCurrentUserId() {
130        int callingUid = Binder.getCallingUid();
131        // Also check the PID because Settings (power control widget) also runs as System UID
132        if (callingUid == android.os.Process.myUid()
133                && Binder.getCallingPid() == android.os.Process.myPid()) {
134            try {
135                return ActivityManagerNative.getDefault().getCurrentUser().id;
136            } catch (RemoteException re) {
137                return UserHandle.getUserId(callingUid);
138            }
139        } else {
140            return UserHandle.getUserId(callingUid);
141        }
142    }
143
144    @Override
145    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
146        return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
147                packageName, hostId);
148    }
149
150    @Override
151    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
152        getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId);
153    }
154
155    @Override
156    public void deleteHost(int hostId) throws RemoteException {
157        getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId);
158    }
159
160    @Override
161    public void deleteAllHosts() throws RemoteException {
162        getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts();
163    }
164
165    @Override
166    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
167            throws RemoteException {
168        getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider,
169                options);
170    }
171
172    @Override
173    public boolean bindAppWidgetIdIfAllowed(
174            String packageName, int appWidgetId, ComponentName provider, Bundle options)
175                    throws RemoteException {
176        return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed(
177                packageName, appWidgetId, provider, options);
178    }
179
180    @Override
181    public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
182        return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission(
183                packageName);
184    }
185
186    @Override
187    public void setBindAppWidgetPermission(String packageName, boolean permission)
188            throws RemoteException {
189        getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission(
190                packageName, permission);
191    }
192
193    @Override
194    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
195            throws RemoteException {
196        getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService(
197                appWidgetId, intent, connection);
198    }
199
200    @Override
201    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
202            List<RemoteViews> updatedViews) throws RemoteException {
203        return getImplForUser(getCallingOrCurrentUserId()).startListening(host,
204                packageName, hostId, updatedViews);
205    }
206
207    public void onUserRemoved(int userId) {
208        if (userId < 1) return;
209        synchronized (mAppWidgetServices) {
210            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
211            mAppWidgetServices.remove(userId);
212
213            if (impl == null) {
214                AppWidgetServiceImpl.getSettingsFile(userId).delete();
215            } else {
216                impl.onUserRemoved();
217            }
218        }
219    }
220
221    public void onUserStopping(int userId) {
222        if (userId < 1) return;
223        synchronized (mAppWidgetServices) {
224            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
225            if (impl != null) {
226                mAppWidgetServices.remove(userId);
227                impl.onUserStopping();
228            }
229        }
230    }
231
232    private AppWidgetServiceImpl getImplForUser(int userId) {
233        boolean sendInitial = false;
234        AppWidgetServiceImpl service;
235        synchronized (mAppWidgetServices) {
236            service = mAppWidgetServices.get(userId);
237            if (service == null) {
238                Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
239                // TODO: Verify that it's a valid user
240                service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
241                service.systemReady(mSafeMode);
242                // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
243                mAppWidgetServices.append(userId, service);
244                sendInitial = true;
245            }
246        }
247        if (sendInitial) {
248            service.sendInitialBroadcasts();
249        }
250        return service;
251    }
252
253    @Override
254    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
255        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider);
256    }
257
258    @Override
259    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
260        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId);
261    }
262
263    @Override
264    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
265        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId);
266    }
267
268    @Override
269    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
270        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options);
271    }
272
273    @Override
274    public Bundle getAppWidgetOptions(int appWidgetId) {
275        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
276    }
277
278    @Override
279    public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
280        return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
281    }
282
283    @Override
284    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
285            throws RemoteException {
286        getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged(
287                appWidgetIds, viewId);
288    }
289
290    @Override
291    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
292            throws RemoteException {
293        getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds(
294                appWidgetIds, views);
295    }
296
297    @Override
298    public void stopListening(int hostId) throws RemoteException {
299        getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId);
300    }
301
302    @Override
303    public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
304        getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService(
305                appWidgetId, intent);
306    }
307
308    @Override
309    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
310        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views);
311    }
312
313    @Override
314    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
315            throws RemoteException {
316        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views);
317    }
318
319    @Override
320    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
321        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
322
323        // Dump the state of all the app widget providers
324        synchronized (mAppWidgetServices) {
325            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
326            for (int i = 0; i < mAppWidgetServices.size(); i++) {
327                pw.println("User: " + mAppWidgetServices.keyAt(i));
328                ipw.increaseIndent();
329                AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
330                service.dump(fd, ipw, args);
331                ipw.decreaseIndent();
332            }
333        }
334    }
335
336    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
337        public void onReceive(Context context, Intent intent) {
338            String action = intent.getAction();
339            // Slog.d(TAG, "received " + action);
340            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
341                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
342                if (userId >= 0) {
343                    getImplForUser(userId).sendInitialBroadcasts();
344                } else {
345                    Slog.w(TAG, "Incorrect user handle supplied in " + intent);
346                }
347            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
348                for (int i = 0; i < mAppWidgetServices.size(); i++) {
349                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
350                    service.onConfigurationChanged();
351                }
352            } else {
353                int sendingUser = getSendingUserId();
354                if (sendingUser == UserHandle.USER_ALL) {
355                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
356                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
357                        service.onBroadcastReceived(intent);
358                    }
359                } else {
360                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
361                    if (service != null) {
362                        service.onBroadcastReceived(intent);
363                    }
364                }
365            }
366        }
367    };
368}
369