Fields Summary |
---|
private static final String | LOG_TAG |
private static final boolean | DEBUG_PRINT_JOB_LIFECYCLE |
private static final boolean | DEBUG_PERSISTENCE |
private static final boolean | PERSISTENCE_MANAGER_ENABLED |
private static final long | CHECK_ALL_PRINTJOBS_HANDLED_DELAY |
private static final String | PRINT_JOB_FILE_PREFIX |
private static final String | PRINT_FILE_EXTENSION |
private static final Object | sLock |
private final Object | mLock |
private final List | mPrintJobs |
private static PrintSpoolerService | sInstance |
private android.print.IPrintSpoolerClient | mClient |
private com.android.internal.os.HandlerCaller | mHandlerCaller |
private PersistenceManager | mPersistanceManager |
private NotificationController | mNotificationController |
Methods Summary |
---|
private void | addPrintJobLocked(android.print.PrintJobInfo printJob)
mPrintJobs.add(printJob);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[ADD] " + printJob);
}
|
public void | checkAllPrintJobsHandled()
synchronized (mLock) {
if (!hasActivePrintJobsLocked()) {
notifyOnAllPrintJobsHandled();
}
}
|
public void | createPrintJob(android.print.PrintJobInfo printJob)
synchronized (mLock) {
addPrintJobLocked(printJob);
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
}
|
protected void | dump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)
synchronized (mLock) {
String prefix = (args.length > 0) ? args[0] : "";
String tab = " ";
pw.append(prefix).append("print jobs:").println();
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
pw.append(prefix).append(tab).append(printJob.toString());
pw.println();
}
pw.append(prefix).append("print job files:").println();
File[] files = getFilesDir().listFiles();
if (files != null) {
final int fileCount = files.length;
for (int i = 0; i < fileCount; i++) {
File file = files[i];
if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
pw.append(prefix).append(tab).append(file.getName()).println();
}
}
}
}
|
public static java.io.File | generateFileForPrintJob(android.content.Context context, android.print.PrintJobId printJobId)
return new File(context.getFilesDir(), PRINT_JOB_FILE_PREFIX
+ printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
|
public android.print.PrintJobInfo | getPrintJobInfo(android.print.PrintJobId printJobId, int appId)
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (printJob.getId().equals(printJobId)
&& (appId == PrintManager.APP_ID_ANY
|| appId == printJob.getAppId())) {
return printJob;
}
}
return null;
}
|
public java.util.List | getPrintJobInfos(android.content.ComponentName componentName, int state, int appId)
List<PrintJobInfo> foundPrintJobs = null;
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
PrinterId printerId = printJob.getPrinterId();
final boolean sameComponent = (componentName == null
|| (printerId != null
&& componentName.equals(printerId.getServiceName())));
final boolean sameAppId = appId == PrintManager.APP_ID_ANY
|| printJob.getAppId() == appId;
final boolean sameState = (state == printJob.getState())
|| (state == PrintJobInfo.STATE_ANY)
|| (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
&& isStateVisibleToUser(printJob.getState()))
|| (state == PrintJobInfo.STATE_ANY_ACTIVE
&& isActiveState(printJob.getState()))
|| (state == PrintJobInfo.STATE_ANY_SCHEDULED
&& isScheduledState(printJob.getState()));
if (sameComponent && sameAppId && sameState) {
if (foundPrintJobs == null) {
foundPrintJobs = new ArrayList<>();
}
foundPrintJobs.add(printJob);
}
}
}
return foundPrintJobs;
|
private void | handleReadPrintJobsLocked()
// Make a map with the files for a print job since we may have
// to delete some. One example of getting orphan files if the
// spooler crashes while constructing a print job. We do not
// persist partially populated print jobs under construction to
// avoid special handling for various attributes missing.
ArrayMap<PrintJobId, File> fileForJobMap = null;
File[] files = getFilesDir().listFiles();
if (files != null) {
final int fileCount = files.length;
for (int i = 0; i < fileCount; i++) {
File file = files[i];
if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
if (fileForJobMap == null) {
fileForJobMap = new ArrayMap<PrintJobId, File>();
}
String printJobIdString = file.getName().substring(
PRINT_JOB_FILE_PREFIX.length(),
file.getName().indexOf('."));
PrintJobId printJobId = PrintJobId.unflattenFromString(
printJobIdString);
fileForJobMap.put(printJobId, file);
}
}
}
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
// We want to have only the orphan files at the end.
if (fileForJobMap != null) {
fileForJobMap.remove(printJob.getId());
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED:
case PrintJobInfo.STATE_BLOCKED: {
// We have a print job that was queued or started or blocked in
// the past but the device battery died or a crash occurred. In
// this case we assume the print job failed and let the user
// decide whether to restart the job or just cancel it.
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
getString(R.string.no_connection_to_printer));
} break;
}
}
if (!mPrintJobs.isEmpty()) {
// Update the notification.
mNotificationController.onUpdateNotifications(mPrintJobs);
}
// Delete the orphan files.
if (fileForJobMap != null) {
final int orphanFileCount = fileForJobMap.size();
for (int i = 0; i < orphanFileCount; i++) {
File file = fileForJobMap.valueAt(i);
file.delete();
}
}
|
public boolean | hasActivePrintJobsForServiceLocked(android.content.ComponentName service)
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null
&& printJob.getPrinterId().getServiceName().equals(service)) {
return true;
}
}
return false;
|
public boolean | hasActivePrintJobsLocked()
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (isActiveState(printJob.getState())) {
return true;
}
}
return false;
|
private boolean | isActiveState(int printJobState)
return printJobState == PrintJobInfo.STATE_CREATED
|| printJobState == PrintJobInfo.STATE_QUEUED
|| printJobState == PrintJobInfo.STATE_STARTED
|| printJobState == PrintJobInfo.STATE_BLOCKED;
|
private boolean | isObsoleteState(int printJobState)
return (isTerminalState(printJobState)
|| printJobState == PrintJobInfo.STATE_QUEUED);
|
private boolean | isScheduledState(int printJobState)
return printJobState == PrintJobInfo.STATE_QUEUED
|| printJobState == PrintJobInfo.STATE_STARTED
|| printJobState == PrintJobInfo.STATE_BLOCKED;
|
private boolean | isStateVisibleToUser(int state)
return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
|| state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
|| state == PrintJobInfo.STATE_BLOCKED));
|
private boolean | isTerminalState(int printJobState)
return printJobState == PrintJobInfo.STATE_COMPLETED
|| printJobState == PrintJobInfo.STATE_CANCELED;
|
private void | notifyOnAllPrintJobsHandled()
// This has to run on the tread that is persisting the current state
// since this call may result in the system unbinding from the spooler
// and as a result the spooler process may get killed before the write
// completes.
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
sendOnAllPrintJobsHandled();
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
|
public android.os.IBinder | onBind(android.content.Intent intent)
return new PrintSpooler();
|
public void | onCreate()
super.onCreate();
mHandlerCaller = new HandlerCaller(this, getMainLooper(),
new HandlerCallerCallback(), false);
mPersistanceManager = new PersistenceManager();
mNotificationController = new NotificationController(PrintSpoolerService.this);
synchronized (mLock) {
mPersistanceManager.readStateLocked();
handleReadPrintJobsLocked();
}
synchronized (sLock) {
sInstance = this;
}
|
public static com.android.printspooler.model.PrintSpoolerService | peekInstance()
synchronized (sLock) {
return sInstance;
}
|
private void | removeObsoletePrintJobs()
synchronized (mLock) {
boolean persistState = false;
final int printJobCount = mPrintJobs.size();
for (int i = printJobCount - 1; i >= 0; i--) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (isObsoleteState(printJob.getState())) {
mPrintJobs.remove(i);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
}
removePrintJobFileLocked(printJob.getId());
persistState = true;
}
}
if (persistState) {
mPersistanceManager.writeStateLocked();
}
}
|
private void | removePrintJobFileLocked(android.print.PrintJobId printJobId)
File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
if (file.exists()) {
file.delete();
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
}
}
|
private void | sendOnAllPrintJobsForServiceHandled(android.content.ComponentName service)
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service);
mHandlerCaller.executeOrSendMessage(message);
|
private void | sendOnAllPrintJobsHandled()
Message message = mHandlerCaller.obtainMessage(
HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED);
mHandlerCaller.executeOrSendMessage(message);
|
private void | sendOnPrintJobQueued(android.print.PrintJobInfo printJob)
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
mHandlerCaller.executeOrSendMessage(message);
|
public void | setPrintJobCancelling(android.print.PrintJobId printJobId, boolean cancelling)
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setCancelling(cancelling);
if (shouldPersistPrintJob(printJob)) {
mPersistanceManager.writeStateLocked();
}
mNotificationController.onUpdateNotifications(mPrintJobs);
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
}
}
|
public boolean | setPrintJobState(android.print.PrintJobId printJobId, int state, java.lang.String error)
boolean success = false;
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
final int oldState = printJob.getState();
if (oldState == state) {
return false;
}
success = true;
printJob.setState(state);
printJob.setStateReason(error);
printJob.setCancelling(false);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
}
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED:
mPrintJobs.remove(printJob);
removePrintJobFileLocked(printJob.getId());
// $fall-through$
case PrintJobInfo.STATE_FAILED: {
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
ComponentName service = printerId.getServiceName();
if (!hasActivePrintJobsForServiceLocked(service)) {
sendOnAllPrintJobsForServiceHandled(service);
}
}
} break;
case PrintJobInfo.STATE_QUEUED: {
sendOnPrintJobQueued(new PrintJobInfo(printJob));
} break;
}
if (shouldPersistPrintJob(printJob)) {
mPersistanceManager.writeStateLocked();
}
if (!hasActivePrintJobsLocked()) {
notifyOnAllPrintJobsHandled();
}
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
mNotificationController.onUpdateNotifications(mPrintJobs);
}
}
return success;
|
public boolean | setPrintJobTag(android.print.PrintJobId printJobId, java.lang.String tag)
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
String printJobTag = printJob.getTag();
if (printJobTag == null) {
if (tag == null) {
return false;
}
} else if (printJobTag.equals(tag)) {
return false;
}
printJob.setTag(tag);
if (shouldPersistPrintJob(printJob)) {
mPersistanceManager.writeStateLocked();
}
return true;
}
}
return false;
|
private boolean | shouldPersistPrintJob(android.print.PrintJobInfo printJob)
return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
|
public void | updatePrintJobUserConfigurableOptionsNoPersistence(android.print.PrintJobInfo printJob)
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo cachedPrintJob = mPrintJobs.get(i);
if (cachedPrintJob.getId().equals(printJob.getId())) {
cachedPrintJob.setPrinterId(printJob.getPrinterId());
cachedPrintJob.setPrinterName(printJob.getPrinterName());
cachedPrintJob.setCopies(printJob.getCopies());
cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo());
cachedPrintJob.setPages(printJob.getPages());
cachedPrintJob.setAttributes(printJob.getAttributes());
cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions());
return;
}
}
throw new IllegalArgumentException("No print job with id:" + printJob.getId());
}
|
public void | writePrintJobData(android.os.ParcelFileDescriptor fd, android.print.PrintJobId printJobId)
final PrintJobInfo printJob;
synchronized (mLock) {
printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
}
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
FileInputStream in = null;
FileOutputStream out = null;
try {
if (printJob != null) {
File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
in = new FileInputStream(file);
out = new FileOutputStream(fd.getFileDescriptor());
}
final byte[] buffer = new byte[8192];
while (true) {
final int readByteCount = in.read(buffer);
if (readByteCount < 0) {
return null;
}
out.write(buffer, 0, readByteCount);
}
} catch (FileNotFoundException fnfe) {
Log.e(LOG_TAG, "Error writing print job data!", fnfe);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error writing print job data!", ioe);
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(fd);
}
Log.i(LOG_TAG, "[END WRITE]");
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|