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        userFilter.addAction(Intent.ACTION_USER_STOPPING);
102        mContext.registerReceiver(new BroadcastReceiver() {
103            @Override
104            public void onReceive(Context context, Intent intent) {
105                if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
106                    onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
107                            UserHandle.USER_NULL));
108                } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
109                    onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
110                            UserHandle.USER_NULL));
111                }
112            }
113        }, userFilter);
114    }
115
116    /**
117     * This returns the user id of the caller, if the caller is not the system process,
118     * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
119     * current user. TODO: Instead, have lockscreen make explicit calls with userId
120     */
121    private int getCallingOrCurrentUserId() {
122        int callingUid = Binder.getCallingUid();
123        // Also check the PID because Settings (power control widget) also runs as System UID
124        if (callingUid == android.os.Process.myUid()
125                && Binder.getCallingPid() == android.os.Process.myPid()) {
126            try {
127                return ActivityManagerNative.getDefault().getCurrentUser().id;
128            } catch (RemoteException re) {
129                return UserHandle.getUserId(callingUid);
130            }
131        } else {
132            return UserHandle.getUserId(callingUid);
133        }
134    }
135
136    @Override
137    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
138        return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
139                packageName, hostId);
140    }
141
142    @Override
143    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
144        getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId);
145    }
146
147    @Override
148    public void deleteHost(int hostId) throws RemoteException {
149        getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId);
150    }
151
152    @Override
153    public void deleteAllHosts() throws RemoteException {
154        getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts();
155    }
156
157    @Override
158    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
159            throws RemoteException {
160        getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider,
161                options);
162    }
163
164    @Override
165    public boolean bindAppWidgetIdIfAllowed(
166            String packageName, int appWidgetId, ComponentName provider, Bundle options)
167                    throws RemoteException {
168        return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed(
169                packageName, appWidgetId, provider, options);
170    }
171
172    @Override
173    public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
174        return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission(
175                packageName);
176    }
177
178    @Override
179    public void setBindAppWidgetPermission(String packageName, boolean permission)
180            throws RemoteException {
181        getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission(
182                packageName, permission);
183    }
184
185    @Override
186    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
187            throws RemoteException {
188        getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService(
189                appWidgetId, intent, connection);
190    }
191
192    @Override
193    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
194            List<RemoteViews> updatedViews) throws RemoteException {
195        return getImplForUser(getCallingOrCurrentUserId()).startListening(host,
196                packageName, hostId, updatedViews);
197    }
198
199    public void onUserRemoved(int userId) {
200        if (userId < 1) return;
201        synchronized (mAppWidgetServices) {
202            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
203            mAppWidgetServices.remove(userId);
204
205            if (impl == null) {
206                AppWidgetServiceImpl.getSettingsFile(userId).delete();
207            } else {
208                impl.onUserRemoved();
209            }
210        }
211    }
212
213    public void onUserStopping(int userId) {
214        if (userId < 1) return;
215        synchronized (mAppWidgetServices) {
216            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
217            if (impl != null) {
218                mAppWidgetServices.remove(userId);
219                impl.onUserStopping();
220            }
221        }
222    }
223
224    private AppWidgetServiceImpl getImplForUser(int userId) {
225        boolean sendInitial = false;
226        AppWidgetServiceImpl service;
227        synchronized (mAppWidgetServices) {
228            service = mAppWidgetServices.get(userId);
229            if (service == null) {
230                Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
231                // TODO: Verify that it's a valid user
232                service = new AppWidgetServiceImpl(mContext, userId);
233                service.systemReady(mSafeMode);
234                // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
235                mAppWidgetServices.append(userId, service);
236                sendInitial = true;
237            }
238        }
239        if (sendInitial) {
240            service.sendInitialBroadcasts();
241        }
242        return service;
243    }
244
245    @Override
246    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
247        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider);
248    }
249
250    @Override
251    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
252        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId);
253    }
254
255    @Override
256    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
257        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId);
258    }
259
260    @Override
261    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
262        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options);
263    }
264
265    @Override
266    public Bundle getAppWidgetOptions(int appWidgetId) {
267        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
268    }
269
270    @Override
271    public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
272        return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
273    }
274
275    @Override
276    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
277            throws RemoteException {
278        getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged(
279                appWidgetIds, viewId);
280    }
281
282    @Override
283    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
284            throws RemoteException {
285        getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds(
286                appWidgetIds, views);
287    }
288
289    @Override
290    public void stopListening(int hostId) throws RemoteException {
291        getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId);
292    }
293
294    @Override
295    public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
296        getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService(
297                appWidgetId, intent);
298    }
299
300    @Override
301    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
302        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views);
303    }
304
305    @Override
306    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
307            throws RemoteException {
308        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views);
309    }
310
311    @Override
312    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
313        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
314
315        // Dump the state of all the app widget providers
316        synchronized (mAppWidgetServices) {
317            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
318            for (int i = 0; i < mAppWidgetServices.size(); i++) {
319                pw.println("User: " + mAppWidgetServices.keyAt(i));
320                ipw.increaseIndent();
321                AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
322                service.dump(fd, ipw, args);
323                ipw.decreaseIndent();
324            }
325        }
326    }
327
328    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
329        public void onReceive(Context context, Intent intent) {
330            String action = intent.getAction();
331            // Slog.d(TAG, "received " + action);
332            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
333                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
334                if (userId >= 0) {
335                    getImplForUser(userId).sendInitialBroadcasts();
336                } else {
337                    Slog.w(TAG, "Incorrect user handle supplied in " + intent);
338                }
339            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
340                for (int i = 0; i < mAppWidgetServices.size(); i++) {
341                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
342                    service.onConfigurationChanged();
343                }
344            } else {
345                int sendingUser = getSendingUserId();
346                if (sendingUser == UserHandle.USER_ALL) {
347                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
348                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
349                        service.onBroadcastReceived(intent);
350                    }
351                } else {
352                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
353                    if (service != null) {
354                        service.onBroadcastReceived(intent);
355                    }
356                }
357            }
358        }
359    };
360}
361