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