a00271533f
1. Now a user state has ins own spooler since the spooler app is running per user. The user state registers an observer for the state of the spooler to get information needed to orchestrate unbinding from print serivces that have no work and eventually unbinding from the spooler when all no service has any work. 2. Abstracted a remote print service from the perspective of the system in a class that is transparently managing binding and unbinding to the remote instance. 3. Abstracted the remote print spooler to transparently manage binding and unbinding to the remote instance when there is work and when there is no work, respectively. 4. Cleaned up the print document adapter (ex-PrintAdapter) APIs to enable implementing the all callbacks on a thread of choice. If the document is really small, using the main thread makes sense. Now if an app that does not need the UI state to layout the printed content, it can schedule all the work for allocating resources, laying out, writing, and releasing resources on a dedicated thread. 5. Added info class for the printed document that is now propagated the the print services. A print service gets an instance of a new document class that encapsulates the document info and a method to access the document's data. 6. Added APIs for describing the type of a document to the new document info class. This allows a print service to do smarts based on the doc type. For now we have only photo and document types. 7. Renamed the systemReady method for system services that implement it with different semantics to systemRunning. Such methods assume the the service can run third-party code which is not the same as systemReady. 8. Cleaned up the print job configuration activity. 9. Sigh... code clean up here and there. Factoring out classes to improve readability. Change-Id: I637ba28412793166cbf519273fdf022241159a92
364 lines
14 KiB
Java
364 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.ActivityManager;
|
|
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.pm.PackageManager;
|
|
import android.os.Binder;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.RemoteException;
|
|
import android.os.UserHandle;
|
|
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.os.BackgroundThread;
|
|
import com.android.internal.util.IndentingPrintWriter;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
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";
|
|
|
|
Context mContext;
|
|
Locale mLocale;
|
|
PackageManager mPackageManager;
|
|
boolean mSafeMode;
|
|
private final Handler mSaveStateHandler;
|
|
|
|
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
|
|
|
|
AppWidgetService(Context context) {
|
|
mContext = context;
|
|
|
|
mSaveStateHandler = BackgroundThread.getHandler();
|
|
|
|
mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
|
|
AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
|
|
mAppWidgetServices.append(0, primary);
|
|
}
|
|
|
|
public void systemRunning(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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
|
|
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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
|
|
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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
|
|
filter, null, null);
|
|
// 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.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
|
|
sdFilter, null, null);
|
|
|
|
IntentFilter userFilter = new IntentFilter();
|
|
userFilter.addAction(Intent.ACTION_USER_REMOVED);
|
|
userFilter.addAction(Intent.ACTION_USER_STOPPING);
|
|
mContext.registerReceiver(new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
|
|
onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
|
|
UserHandle.USER_NULL));
|
|
} else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
|
|
onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
|
|
UserHandle.USER_NULL));
|
|
}
|
|
}
|
|
}, userFilter);
|
|
}
|
|
|
|
@Override
|
|
public int allocateAppWidgetId(String packageName, int hostId, int userId)
|
|
throws RemoteException {
|
|
return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
|
|
}
|
|
|
|
@Override
|
|
public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
|
|
return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
|
|
}
|
|
|
|
@Override
|
|
public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
|
|
getImplForUser(userId).deleteAppWidgetId(appWidgetId);
|
|
}
|
|
|
|
@Override
|
|
public void deleteHost(int hostId, int userId) throws RemoteException {
|
|
getImplForUser(userId).deleteHost(hostId);
|
|
}
|
|
|
|
@Override
|
|
public void deleteAllHosts(int userId) throws RemoteException {
|
|
getImplForUser(userId).deleteAllHosts();
|
|
}
|
|
|
|
@Override
|
|
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
|
|
}
|
|
|
|
@Override
|
|
public boolean bindAppWidgetIdIfAllowed(
|
|
String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId)
|
|
throws RemoteException {
|
|
return getImplForUser(userId).bindAppWidgetIdIfAllowed(
|
|
packageName, appWidgetId, provider, options);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasBindAppWidgetPermission(String packageName, int userId)
|
|
throws RemoteException {
|
|
return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
|
|
}
|
|
|
|
@Override
|
|
public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
|
|
}
|
|
|
|
@Override
|
|
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
|
|
int userId) throws RemoteException {
|
|
getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
|
|
}
|
|
|
|
@Override
|
|
public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
|
|
List<RemoteViews> updatedViews, int userId) throws RemoteException {
|
|
return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
|
|
}
|
|
|
|
public void onUserRemoved(int userId) {
|
|
if (userId < 1) return;
|
|
synchronized (mAppWidgetServices) {
|
|
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
|
|
mAppWidgetServices.remove(userId);
|
|
|
|
if (impl == null) {
|
|
AppWidgetServiceImpl.getSettingsFile(userId).delete();
|
|
} else {
|
|
impl.onUserRemoved();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void onUserStopping(int userId) {
|
|
if (userId < 1) return;
|
|
synchronized (mAppWidgetServices) {
|
|
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
|
|
if (impl != null) {
|
|
mAppWidgetServices.remove(userId);
|
|
impl.onUserStopping();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void checkPermission(int userId) {
|
|
int realUserId = ActivityManager.handleIncomingUser(
|
|
Binder.getCallingPid(),
|
|
Binder.getCallingUid(),
|
|
userId,
|
|
false, /* allowAll */
|
|
true, /* requireFull */
|
|
this.getClass().getSimpleName(),
|
|
this.getClass().getPackage().getName());
|
|
}
|
|
|
|
private AppWidgetServiceImpl getImplForUser(int userId) {
|
|
checkPermission(userId);
|
|
boolean sendInitial = false;
|
|
AppWidgetServiceImpl service;
|
|
synchronized (mAppWidgetServices) {
|
|
service = mAppWidgetServices.get(userId);
|
|
if (service == null) {
|
|
Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
|
|
// TODO: Verify that it's a valid user
|
|
service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
|
|
service.systemReady(mSafeMode);
|
|
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
|
|
mAppWidgetServices.append(userId, service);
|
|
sendInitial = true;
|
|
}
|
|
}
|
|
if (sendInitial) {
|
|
service.sendInitialBroadcasts();
|
|
}
|
|
return service;
|
|
}
|
|
|
|
@Override
|
|
public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
|
|
return getImplForUser(userId).getAppWidgetIds(provider);
|
|
}
|
|
|
|
@Override
|
|
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
|
|
throws RemoteException {
|
|
return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
|
|
}
|
|
|
|
@Override
|
|
public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
|
|
return getImplForUser(userId).getAppWidgetViews(appWidgetId);
|
|
}
|
|
|
|
@Override
|
|
public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
|
|
getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
|
|
}
|
|
|
|
@Override
|
|
public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
|
|
return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
|
|
}
|
|
|
|
@Override
|
|
public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
|
|
throws RemoteException {
|
|
return getImplForUser(userId).getInstalledProviders(categoryFilter);
|
|
}
|
|
|
|
@Override
|
|
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).notifyAppWidgetViewDataChanged(
|
|
appWidgetIds, viewId);
|
|
}
|
|
|
|
@Override
|
|
public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).partiallyUpdateAppWidgetIds(
|
|
appWidgetIds, views);
|
|
}
|
|
|
|
@Override
|
|
public void stopListening(int hostId, int userId) throws RemoteException {
|
|
getImplForUser(userId).stopListening(hostId);
|
|
}
|
|
|
|
@Override
|
|
public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).unbindRemoteViewsService(
|
|
appWidgetId, intent);
|
|
}
|
|
|
|
@Override
|
|
public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
|
|
}
|
|
|
|
@Override
|
|
public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
|
|
throws RemoteException {
|
|
getImplForUser(userId).updateAppWidgetProvider(provider, views);
|
|
}
|
|
|
|
@Override
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
|
|
|
|
// Dump the state of all the app widget providers
|
|
synchronized (mAppWidgetServices) {
|
|
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
|
for (int i = 0; i < mAppWidgetServices.size(); i++) {
|
|
pw.println("User: " + mAppWidgetServices.keyAt(i));
|
|
ipw.increaseIndent();
|
|
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
|
|
service.dump(fd, ipw, args);
|
|
ipw.decreaseIndent();
|
|
}
|
|
}
|
|
}
|
|
|
|
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, UserHandle.USER_NULL);
|
|
if (userId >= 0) {
|
|
getImplForUser(userId).sendInitialBroadcasts();
|
|
} else {
|
|
Slog.w(TAG, "Incorrect 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 {
|
|
int sendingUser = getSendingUserId();
|
|
if (sendingUser == UserHandle.USER_ALL) {
|
|
for (int i = 0; i < mAppWidgetServices.size(); i++) {
|
|
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
|
|
service.onBroadcastReceived(intent);
|
|
}
|
|
} else {
|
|
AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
|
|
if (service != null) {
|
|
service.onBroadcastReceived(intent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|