Files
frameworks_base/services/java/com/android/server/AppWidgetService.java
Dianne Hackborn 4120375d46 Remove Binder.getOrigCallingUid().
Replaced all remaining places that used it with explicit user
specification.

While doing this, I ran into stuff that was creating PendingIntent
objects (that now need to specify the explicit user they are for),
which are also posting notifications...  but have no way to specify
the user for the notification.

So the notification manager in the system process now also gets a
formal concept of a user associated with the notification, which
is passed in to all the necessary aidl calls.  I also removed the
old deprecated aidl interface for posting/cancelling notifications,
since we now always need a user supplied.

There is more work that needs to be done here, though.  For example
I think we need to be able to specify USER_ALL for a notification that
should be shown to all users (such as low storage or low battery).
Along with that, the PendingIntent creation needs to be tweaked to
be able to handle USER_CURRENT by evaluating the user at the point the
pending intent is sent.

That's for another change, however.

Change-Id: I468e14dce8def0e13e0870571e7c31ed32b6310c
2012-08-31 15:11:13 -07:00

381 lines
14 KiB
Java

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Redirects calls to this service to the instance of the service for the appropriate user.
*/
class AppWidgetService extends IAppWidgetService.Stub
{
private static final String TAG = "AppWidgetService";
/*
* When identifying a Host or Provider based on the calling process, use the uid field.
* When identifying a Host or Provider based on a package manager broadcast, use the
* package given.
*/
static class Provider {
int uid;
AppWidgetProviderInfo info;
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
int tag; // for use while saving state (the index)
}
static class Host {
int uid;
int hostId;
String packageName;
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
IAppWidgetHost callbacks;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
int tag; // for use while saving state (the index)
}
static class AppWidgetId {
int appWidgetId;
Provider provider;
RemoteViews views;
Host host;
}
/**
* Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
* This needs to be a static inner class since a reference to the ServiceConnection is held
* globally and may lead us to leak AppWidgetService instances (if there were more than one).
*/
static class ServiceConnectionProxy implements ServiceConnection {
private final IBinder mConnectionCb;
ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
mConnectionCb = connectionCb;
}
public void onServiceConnected(ComponentName name, IBinder service) {
final IRemoteViewsAdapterConnection cb =
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
try {
cb.onServiceConnected(service);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
disconnect();
}
public void disconnect() {
final IRemoteViewsAdapterConnection cb =
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
try {
cb.onServiceDisconnected();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Context mContext;
Locale mLocale;
PackageManager mPackageManager;
AlarmManager mAlarmManager;
ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
ArrayList<Host> mHosts = new ArrayList<Host>();
boolean mSafeMode;
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
AppWidgetService(Context context) {
mContext = context;
mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
mAppWidgetServices.append(0, primary);
}
public void systemReady(boolean safeMode) {
mSafeMode = safeMode;
mAppWidgetServices.get(0).systemReady(safeMode);
// Register for the boot completed broadcast, so we can send the
// ENABLE broacasts. If we try to send them now, they time out,
// because the system isn't ready to handle them yet.
mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
// Register for configuration changes so we can update the names
// of the widgets when the locale changes.
mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
Intent.ACTION_CONFIGURATION_CHANGED), null, null);
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
}
}, userFilter);
}
@Override
public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).allocateAppWidgetId(
packageName, hostId);
}
@Override
public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).deleteAppWidgetId(appWidgetId);
}
@Override
public void deleteHost(int hostId) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).deleteHost(hostId);
}
@Override
public void deleteAllHosts() throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).deleteAllHosts();
}
@Override
public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetId(appWidgetId, provider);
}
@Override
public boolean bindAppWidgetIdIfAllowed(
String packageName, int appWidgetId, ComponentName provider) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).bindAppWidgetIdIfAllowed(
packageName, appWidgetId, provider);
}
@Override
public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).hasBindAppWidgetPermission(
packageName);
}
@Override
public void setBindAppWidgetPermission(String packageName, boolean permission)
throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).setBindAppWidgetPermission(
packageName, permission);
}
@Override
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).bindRemoteViewsService(
appWidgetId, intent, connection);
}
@Override
public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
List<RemoteViews> updatedViews) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).startListening(host,
packageName, hostId, updatedViews);
}
public void onUserRemoved(int userId) {
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
if (userId < 1) return;
if (impl == null) {
AppWidgetServiceImpl.getSettingsFile(userId).delete();
} else {
impl.onUserRemoved();
}
}
private AppWidgetServiceImpl getImplForUser(int userId) {
AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
if (service == null) {
Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
// TODO: Verify that it's a valid user
service = new AppWidgetServiceImpl(mContext, userId);
service.systemReady(mSafeMode);
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
service.sendInitialBroadcasts();
mAppWidgetServices.append(userId, service);
}
return service;
}
@Override
public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetIds(provider);
}
@Override
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetInfo(appWidgetId);
}
@Override
public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetViews(appWidgetId);
}
@Override
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetOptions(appWidgetId, options);
}
@Override
public Bundle getAppWidgetOptions(int appWidgetId) {
return getImplForUser(UserHandle.getCallingUserId()).getAppWidgetOptions(appWidgetId);
}
static int[] getAppWidgetIds(Provider p) {
int instancesSize = p.instances.size();
int appWidgetIds[] = new int[instancesSize];
for (int i=0; i<instancesSize; i++) {
appWidgetIds[i] = p.instances.get(i).appWidgetId;
}
return appWidgetIds;
}
@Override
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
return getImplForUser(UserHandle.getCallingUserId()).getInstalledProviders();
}
@Override
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).notifyAppWidgetViewDataChanged(
appWidgetIds, viewId);
}
@Override
public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).partiallyUpdateAppWidgetIds(
appWidgetIds, views);
}
@Override
public void stopListening(int hostId) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).stopListening(hostId);
}
@Override
public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).unbindRemoteViewsService(
appWidgetId, intent);
}
@Override
public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetIds(appWidgetIds, views);
}
@Override
public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
throws RemoteException {
getImplForUser(UserHandle.getCallingUserId()).updateAppWidgetProvider(provider, views);
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
// Dump the state of all the app widget providers
for (int i = 0; i < mAppWidgetServices.size(); i++) {
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
service.dump(fd, pw, args);
}
}
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Slog.d(TAG, "received " + action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId >= 0) {
getImplForUser(userId).sendInitialBroadcasts();
} else {
Slog.w(TAG, "Not user handle supplied in " + intent);
}
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
for (int i = 0; i < mAppWidgetServices.size(); i++) {
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
service.onConfigurationChanged();
}
} else {
for (int i = 0; i < mAppWidgetServices.size(); i++) {
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
service.onBroadcastReceived(intent);
}
}
}
};
}