Files
frameworks_base/services/java/com/android/server/print/UserState.java
Svetoslav Ganov 55b409a97c Iteration of the print sub-system.
1. Added APIs for adding partially initialized PrintInfo objects
   enabling light-weight lookps for print serivces that want to
   populate the list of available printers without querying each
   of them for its capabilities. This includes APIs for the system
   to request from a print service to update certain printers.

2. Fixed a bug in PrinterId#equals().

3. Added equals and hasCode implementaion to PrinterInfo. Also
   the defaul in PrinterInfo are now an array instead of a
   SparseArray - cheaper.

4. Now PrintJobConfigActivity works with partially specified
   printers. Specifically, if such a printer is selected the
   activity is requesting from the print service to update
   the printer. We are currently not handling the timeout case.
   It also handles udpated pritners.

Change-Id: I5e83e924ef597c9e22cbd06a971d4f4d3bd3a9c1
2013-07-31 18:59:53 -07:00

291 lines
9.8 KiB
Java

/*
* Copyright (C) 2013 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.print;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.Slog;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents the print state for a user.
*/
final class UserState implements PrintSpoolerCallbacks {
private static final String LOG_TAG = "UserState";
private static final char COMPONENT_NAME_SEPARATOR = ':';
private final SimpleStringSplitter mStringColonSplitter =
new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
private final Intent mQueryIntent =
new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
private final Map<ComponentName, RemotePrintService> mActiveServices =
new HashMap<ComponentName, RemotePrintService>();
private final List<PrintServiceInfo> mInstalledServices =
new ArrayList<PrintServiceInfo>();
private final Set<ComponentName> mEnabledServices =
new HashSet<ComponentName>();
private final Object mLock;
private final Context mContext;
private final int mUserId;
private final RemotePrintSpooler mSpooler;
private boolean mDestroyed;
public UserState(Context context, int userId, Object lock) {
mContext = context;
mUserId = userId;
mLock = lock;
mSpooler = new RemotePrintSpooler(context, userId, this);
}
@Override
public void onPrintJobQueued(PrintJobInfo printJob) {
final RemotePrintService service;
synchronized (mLock) {
throwIfDestroyedLocked();
ComponentName printServiceName = printJob.getPrinterId().getService();
service = mActiveServices.get(printServiceName);
}
if (service != null) {
service.onPrintJobQueued(printJob);
}
}
@Override
public void onAllPrintJobsForServiceHandled(ComponentName printService) {
final RemotePrintService service;
synchronized (mLock) {
throwIfDestroyedLocked();
service = mActiveServices.get(printService);
}
if (service != null) {
service.onAllPrintJobsHandled();
}
}
@Override
public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
final List<RemotePrintService> services;
synchronized (mLock) {
throwIfDestroyedLocked();
if (mActiveServices.isEmpty()) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.onStartPrinterDiscovery(observer);
}
}
@Override
public void onStopPrinterDiscovery() {
final List<RemotePrintService> services;
synchronized (mLock) {
throwIfDestroyedLocked();
if (mActiveServices.isEmpty()) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.onStopPrinterDiscovery();
}
}
@Override
public void onRequestUpdatePrinters(List<PrinterId> printerIds) {
final RemotePrintService service;
synchronized (mLock) {
throwIfDestroyedLocked();
if (mActiveServices.isEmpty()) {
return;
}
service = mActiveServices.get(printerIds.get(0).getService());
}
if (service != null) {
service.onRequestUpdatePrinters(printerIds);
}
}
public void updateIfNeededLocked() {
throwIfDestroyedLocked();
if (readConfigurationLocked()) {
onConfigurationChangedLocked();
}
}
public RemotePrintSpooler getSpoolerLocked() {
throwIfDestroyedLocked();
return mSpooler;
}
public Map<ComponentName, RemotePrintService> getActiveServices() {
synchronized(mLock) {
throwIfDestroyedLocked();
return mActiveServices;
}
}
public Set<ComponentName> getEnabledServices() {
synchronized(mLock) {
throwIfDestroyedLocked();
return mEnabledServices;
}
}
public void destroyLocked() {
throwIfDestroyedLocked();
mSpooler.destroy();
for (RemotePrintService service : mActiveServices.values()) {
service.destroy();
}
mActiveServices.clear();
mInstalledServices.clear();
mEnabledServices.clear();
mDestroyed = true;
}
private boolean readConfigurationLocked() {
boolean somethingChanged = false;
somethingChanged |= readInstalledPrintServicesLocked();
somethingChanged |= readEnabledPrintServicesLocked();
return somethingChanged;
}
private boolean readInstalledPrintServicesLocked() {
Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
List<ResolveInfo> installedServices = mContext.getPackageManager()
.queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES
| PackageManager.GET_META_DATA, mUserId);
final int installedCount = installedServices.size();
for (int i = 0, count = installedCount; i < count; i++) {
ResolveInfo installedService = installedServices.get(i);
if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals(
installedService.serviceInfo.permission)) {
ComponentName serviceName = new ComponentName(
installedService.serviceInfo.packageName,
installedService.serviceInfo.name);
Slog.w(LOG_TAG, "Skipping print service "
+ serviceName.flattenToShortString()
+ " since it does not require permission "
+ android.Manifest.permission.BIND_PRINT_SERVICE);
continue;
}
tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
}
if (!tempPrintServices.equals(mInstalledServices)) {
mInstalledServices.clear();
mInstalledServices.addAll(tempPrintServices);
return true;
}
return false;
}
private boolean readEnabledPrintServicesLocked() {
Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
if (!TextUtils.isEmpty(settingValue)) {
TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(settingValue);
while (splitter.hasNext()) {
String string = splitter.next();
if (TextUtils.isEmpty(string)) {
continue;
}
ComponentName componentName = ComponentName.unflattenFromString(string);
if (componentName != null) {
tempEnabledServiceNameSet.add(componentName);
}
}
}
if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
mEnabledServices.clear();
mEnabledServices.addAll(tempEnabledServiceNameSet);
return true;
}
return false;
}
private void onConfigurationChangedLocked() {
final int installedCount = mInstalledServices.size();
for (int i = 0; i < installedCount; i++) {
ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo();
ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name);
if (mEnabledServices.contains(serviceName)) {
if (!mActiveServices.containsKey(serviceName)) {
mActiveServices.put(serviceName, new RemotePrintService(
mContext, serviceName, mUserId, mSpooler));
}
} else {
RemotePrintService service = mActiveServices.remove(serviceName);
if (service != null) {
service.destroy();
}
}
}
}
private void throwIfDestroyedLocked() {
if (mDestroyed) {
throw new IllegalStateException("Cannot interact with a destroyed instance.");
}
}
}