am 86d2db97: Merge "Print spooler security and some new print service facing APIs." into klp-dev
* commit '86d2db9750657401deadea6766c94300c3bfc7cd': Print spooler security and some new print service facing APIs.
This commit is contained in:
@@ -25,6 +25,7 @@ package android {
|
||||
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
|
||||
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
|
||||
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
|
||||
field public static final java.lang.String BIND_PRINT_SPOOLER_SERVICE = "android.permission.BIND_PRINT_SPOOLER_SERVICE";
|
||||
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
|
||||
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
|
||||
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
|
||||
@@ -19147,7 +19148,7 @@ package android.print {
|
||||
method public void onFinish();
|
||||
method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
|
||||
method public void onStart();
|
||||
method public abstract void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
|
||||
method public abstract void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
|
||||
field public static final java.lang.String METADATA_KEY_PRINT_PREVIEW = "KEY_METADATA_PRINT_PREVIEW";
|
||||
}
|
||||
|
||||
@@ -19167,6 +19168,7 @@ package android.print {
|
||||
method public int describeContents();
|
||||
method public int getColorMode();
|
||||
method public int getContentType();
|
||||
method public long getDataSize();
|
||||
method public int getFittingMode();
|
||||
method public android.print.PrintAttributes.Margins getMargins();
|
||||
method public android.print.PrintAttributes.MediaSize getMediaSize();
|
||||
@@ -19198,7 +19200,7 @@ package android.print {
|
||||
public class PrintFileDocumentAdapter extends android.print.PrintDocumentAdapter {
|
||||
ctor public PrintFileDocumentAdapter(android.content.Context, java.io.File, android.print.PrintDocumentInfo);
|
||||
method public void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
|
||||
method public void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
|
||||
method public void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
|
||||
}
|
||||
|
||||
public final class PrintJob {
|
||||
@@ -19220,9 +19222,10 @@ package android.print {
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int PRINT_JOB_ID_UNDEFINED = -1; // 0xffffffff
|
||||
field public static final int STATE_CANCELED = 6; // 0x6
|
||||
field public static final int STATE_COMPLETED = 4; // 0x4
|
||||
field public static final int STATE_FAILED = 5; // 0x5
|
||||
field public static final int STATE_BLOCKED = 4; // 0x4
|
||||
field public static final int STATE_CANCELED = 7; // 0x7
|
||||
field public static final int STATE_COMPLETED = 5; // 0x5
|
||||
field public static final int STATE_FAILED = 6; // 0x6
|
||||
field public static final int STATE_QUEUED = 2; // 0x2
|
||||
field public static final int STATE_STARTED = 3; // 0x3
|
||||
}
|
||||
@@ -19340,17 +19343,19 @@ package android.print.pdf {
|
||||
package android.printservice {
|
||||
|
||||
public final class PrintDocument {
|
||||
method public java.io.FileDescriptor getData();
|
||||
method public android.os.ParcelFileDescriptor getData();
|
||||
method public android.print.PrintDocumentInfo getInfo();
|
||||
}
|
||||
|
||||
public final class PrintJob {
|
||||
method public boolean block(java.lang.String);
|
||||
method public boolean cancel();
|
||||
method public boolean complete();
|
||||
method public boolean fail(java.lang.String);
|
||||
method public android.printservice.PrintDocument getDocument();
|
||||
method public int getId();
|
||||
method public android.print.PrintJobInfo getInfo();
|
||||
method public boolean isBlocked();
|
||||
method public boolean isCancelled();
|
||||
method public boolean isCompleted();
|
||||
method public boolean isFailed();
|
||||
@@ -19382,9 +19387,11 @@ package android.printservice {
|
||||
method public final boolean isDestroyed();
|
||||
method public final boolean isPrinterDiscoveryStarted();
|
||||
method public abstract void onDestroy();
|
||||
method public abstract void onRequestPrinterUpdate(android.print.PrinterId);
|
||||
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
|
||||
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
|
||||
method public abstract void onStopPrinterDiscovery();
|
||||
method public abstract void onStopPrinterStateTracking(android.print.PrinterId);
|
||||
method public abstract void onValidatePrinters(java.util.List<android.print.PrinterId>);
|
||||
method public final void removePrinters(java.util.List<android.print.PrinterId>);
|
||||
method public final void updatePrinters(java.util.List<android.print.PrinterInfo>);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ interface IPrintManager {
|
||||
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
|
||||
in List<PrinterId> priorityList, int userId);
|
||||
void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
|
||||
void requestPrinterUpdate(in PrinterId printerId, int userId);
|
||||
void validatePrinters(in List<PrinterId> printerIds, int userId);
|
||||
void startPrinterStateTracking(in PrinterId printerId, int userId);
|
||||
void stopPrinterStateTracking(in PrinterId printerId, int userId);
|
||||
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
|
||||
int userId);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ package android.print;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ import java.util.List;
|
||||
* <li>
|
||||
* After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
|
||||
* CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
|
||||
* {@link #onWrite(PageRange[], FileDescriptor, CancellationSignal, WriteResultCallback)}
|
||||
* {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
|
||||
* asking you to write a PDF file with the content for specific pages.
|
||||
* </li>
|
||||
* <li>
|
||||
@@ -64,7 +64,7 @@ import java.util.List;
|
||||
* PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on
|
||||
* the UI thread (assuming onStart initializes resources needed for layout).
|
||||
* This will ensure that the UI does not change while you are laying out the
|
||||
* printed content. Then you can handle {@link #onWrite(PageRange[], FileDescriptor,
|
||||
* printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
|
||||
* CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
|
||||
* thread. This will ensure that the UI is frozen for the minimal amount of
|
||||
* time. Also this assumes that you will generate the printed content in
|
||||
@@ -150,10 +150,10 @@ public abstract class PrintDocumentAdapter {
|
||||
* from of a PDF file to the given file descriptor. This method is invoked
|
||||
* on the main thread.
|
||||
*<p>
|
||||
* After you are done writing, you should <strong>not</strong> close the
|
||||
* file descriptor, rather you must invoke: {@link WriteResultCallback
|
||||
* #onWriteFinished(List)}, if writing completed successfully; or {@link
|
||||
* WriteResultCallback#onWriteFailed(CharSequence)}, if an error occurred.
|
||||
* After you are done writing, you should close the file descriptor and
|
||||
* invoke {@link WriteResultCallback #onWriteFinished(List)}, if writing
|
||||
* completed successfully; or {@link WriteResultCallback#onWriteFailed(
|
||||
* CharSequence)}, if an error occurred.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note:</strong> If the printed content is large, it is a good
|
||||
@@ -171,7 +171,7 @@ public abstract class PrintDocumentAdapter {
|
||||
* @see WriteResultCallback
|
||||
* @see CancellationSignal
|
||||
*/
|
||||
public abstract void onWrite(PageRange[] pages, FileDescriptor destination,
|
||||
public abstract void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
|
||||
CancellationSignal cancellationSignal, WriteResultCallback callback);
|
||||
|
||||
/**
|
||||
@@ -185,7 +185,7 @@ public abstract class PrintDocumentAdapter {
|
||||
|
||||
/**
|
||||
* Base class for implementing a callback for the result of {@link
|
||||
* PrintDocumentAdapter#onWrite(PageRange[], FileDescriptor, CancellationSignal,
|
||||
* PrintDocumentAdapter#onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
|
||||
* WriteResultCallback)}.
|
||||
*/
|
||||
public static abstract class WriteResultCallback {
|
||||
|
||||
@@ -60,6 +60,7 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
private int mColorMode;
|
||||
private Margins mMargins;
|
||||
private MediaSize mMediaSize;
|
||||
private long mDataSize;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@@ -82,6 +83,7 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
mColorMode = prototype.mColorMode;
|
||||
mMargins = prototype.mMargins;
|
||||
mMediaSize = prototype.mMediaSize;
|
||||
mDataSize = prototype.mDataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +100,7 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
mColorMode = parcel.readInt();
|
||||
mMargins = Margins.createFromParcel(parcel);
|
||||
mMediaSize = MediaSize.createFromParcel(parcel);
|
||||
mDataSize = parcel.readLong();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,6 +191,26 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
return mMediaSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the document data size in bytes.
|
||||
*
|
||||
* @return The data size.
|
||||
*/
|
||||
public long getDataSize() {
|
||||
return mDataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the document data size in bytes.
|
||||
*
|
||||
* @param dataSize The data size.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setDataSize(long dataSize) {
|
||||
mDataSize = dataSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -203,6 +226,7 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
parcel.writeInt(mColorMode);
|
||||
mMargins.writeToParcel(parcel);
|
||||
mMediaSize.writeToParcel(parcel);
|
||||
parcel.writeLong(mDataSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,6 +241,8 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
result = prime * result + mColorMode;
|
||||
result = prime * result + (mMargins != null ? mMargins.hashCode() : 0);
|
||||
result = prime * result + (mMediaSize != null ? mMediaSize.hashCode() : 0);
|
||||
result = prime * result + (int) mDataSize;
|
||||
result = prime * result + (int) mDataSize >> 32;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -264,6 +290,9 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
} else if (!mMediaSize.equals(other.mMediaSize)) {
|
||||
return false;
|
||||
}
|
||||
if (mDataSize != other.mDataSize) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -279,6 +308,7 @@ public final class PrintDocumentInfo implements Parcelable {
|
||||
builder.append(", colorMode=").append(PrintAttributes.colorModeToString(mColorMode));
|
||||
builder.append(", margins=").append(mMargins);
|
||||
builder.append(", mediaSize=").append(mMediaSize);
|
||||
builder.append(", size=").append(mDataSize);
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.CancellationSignal.OnCancelListener;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -28,7 +29,6 @@ import com.android.internal.R;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -81,7 +81,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWrite(PageRange[] pages, FileDescriptor destination,
|
||||
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
|
||||
CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||
mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
|
||||
mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
@@ -90,13 +90,13 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
|
||||
|
||||
private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
private final FileDescriptor mDestination;
|
||||
private final ParcelFileDescriptor mDestination;
|
||||
|
||||
private final WriteResultCallback mResultCallback;
|
||||
|
||||
private final CancellationSignal mCancellationSignal;
|
||||
|
||||
public WriteFileAsyncTask(FileDescriptor destination,
|
||||
public WriteFileAsyncTask(ParcelFileDescriptor destination,
|
||||
CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||
mDestination = destination;
|
||||
mResultCallback = callback;
|
||||
@@ -112,7 +112,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
InputStream in = null;
|
||||
OutputStream out = new FileOutputStream(mDestination);
|
||||
OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
|
||||
final byte[] buffer = new byte[8192];
|
||||
try {
|
||||
in = new FileInputStream(mFile);
|
||||
|
||||
@@ -43,6 +43,13 @@ public final class PrintJobInfo implements Parcelable {
|
||||
*/
|
||||
public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
|
||||
|
||||
/**
|
||||
* Constant for matching any active print job state.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int STATE_ANY_ACTIVE = -3;
|
||||
|
||||
/**
|
||||
* Print job state: The print job is being created but not yet
|
||||
* ready to be printed.
|
||||
@@ -55,7 +62,7 @@ public final class PrintJobInfo implements Parcelable {
|
||||
public static final int STATE_CREATED = 1;
|
||||
|
||||
/**
|
||||
* Print job status: The print jobs is created, it is ready
|
||||
* Print job state: The print jobs is created, it is ready
|
||||
* to be printed and should be processed.
|
||||
* <p>
|
||||
* Next valid states: {@link #STATE_STARTED}, {@link #STATE_FAILED},
|
||||
@@ -65,40 +72,49 @@ public final class PrintJobInfo implements Parcelable {
|
||||
public static final int STATE_QUEUED = 2;
|
||||
|
||||
/**
|
||||
* Print job status: The print job is being printed.
|
||||
* Print job state: The print job is being printed.
|
||||
* <p>
|
||||
* Next valid states: {@link #STATE_COMPLETED}, {@link #STATE_FAILED},
|
||||
* {@link #STATE_CANCELED}
|
||||
* {@link #STATE_CANCELED}, {@link #STATE_BLOCKED}
|
||||
* </p>
|
||||
*/
|
||||
public static final int STATE_STARTED = 3;
|
||||
|
||||
/**
|
||||
* Print job status: The print job was successfully printed.
|
||||
* This is a terminal state.
|
||||
* Print job state: The print job is blocked.
|
||||
* <p>
|
||||
* Next valid states: None
|
||||
* Next valid states: {@link #STATE_FAILED}, {@link #STATE_CANCELED},
|
||||
* {@link #STATE_STARTED}
|
||||
* </p>
|
||||
*/
|
||||
public static final int STATE_COMPLETED = 4;
|
||||
public static final int STATE_BLOCKED = 4;
|
||||
|
||||
/**
|
||||
* Print job status: The print job was printing but printing failed.
|
||||
* Print job state: The print job was successfully printed.
|
||||
* This is a terminal state.
|
||||
* <p>
|
||||
* Next valid states: None
|
||||
* </p>
|
||||
*/
|
||||
public static final int STATE_FAILED = 5;
|
||||
public static final int STATE_COMPLETED = 5;
|
||||
|
||||
/**
|
||||
* Print job status: The print job was canceled.
|
||||
* Print job state: The print job was printing but printing failed.
|
||||
* This is a terminal state.
|
||||
* <p>
|
||||
* Next valid states: None
|
||||
* </p>
|
||||
*/
|
||||
public static final int STATE_CANCELED = 6;
|
||||
public static final int STATE_FAILED = 6;
|
||||
|
||||
/**
|
||||
* Print job state: The print job was canceled.
|
||||
* This is a terminal state.
|
||||
* <p>
|
||||
* Next valid states: None
|
||||
* </p>
|
||||
*/
|
||||
public static final int STATE_CANCELED = 7;
|
||||
|
||||
/** The unique print job id. */
|
||||
private int mId;
|
||||
@@ -127,8 +143,8 @@ public final class PrintJobInfo implements Parcelable {
|
||||
/** How many copies to print. */
|
||||
private int mCopies;
|
||||
|
||||
/** Failure reason if this job failed. */
|
||||
private String mFailureReason;
|
||||
/** Reason for the print job being in its current state. */
|
||||
private String mStateReason;
|
||||
|
||||
/** The pages to print */
|
||||
private PageRange[] mPageRanges;
|
||||
@@ -155,7 +171,7 @@ public final class PrintJobInfo implements Parcelable {
|
||||
mUserId = other.mUserId;
|
||||
mTag = other.mTag;
|
||||
mCopies = other.mCopies;
|
||||
mFailureReason = other.mFailureReason;
|
||||
mStateReason = other.mStateReason;
|
||||
mPageRanges = other.mPageRanges;
|
||||
mAttributes = other.mAttributes;
|
||||
mDocumentInfo = other.mDocumentInfo;
|
||||
@@ -171,7 +187,7 @@ public final class PrintJobInfo implements Parcelable {
|
||||
mUserId = parcel.readInt();
|
||||
mTag = parcel.readString();
|
||||
mCopies = parcel.readInt();
|
||||
mFailureReason = parcel.readString();
|
||||
mStateReason = parcel.readString();
|
||||
if (parcel.readInt() == 1) {
|
||||
Parcelable[] parcelables = parcel.readParcelableArray(null);
|
||||
mPageRanges = new PageRange[parcelables.length];
|
||||
@@ -377,25 +393,27 @@ public final class PrintJobInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* The failure reason if this print job failed.
|
||||
* Gets the reason for the print job being in the current state.
|
||||
*
|
||||
* @return The failure reason.
|
||||
* @return The reason, or null if there is no reason or the
|
||||
* reason is unknown.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String getFailureReason() {
|
||||
return mFailureReason;
|
||||
public String getStateReason() {
|
||||
return mStateReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* The failure reason if this print job failed.
|
||||
* Sets the reason for the print job being in the current state.
|
||||
*
|
||||
* @param failureReason The failure reason.
|
||||
* @param stateReason The reason, or null if there is no reason
|
||||
* or the reason is unknown.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setFailureReason(String failureReason) {
|
||||
mFailureReason = failureReason;
|
||||
public void setStateReason(String stateReason) {
|
||||
mStateReason = stateReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,7 +494,7 @@ public final class PrintJobInfo implements Parcelable {
|
||||
parcel.writeInt(mUserId);
|
||||
parcel.writeString(mTag);
|
||||
parcel.writeInt(mCopies);
|
||||
parcel.writeString(mFailureReason);
|
||||
parcel.writeString(mStateReason);
|
||||
if (mPageRanges != null) {
|
||||
parcel.writeInt(1);
|
||||
parcel.writeParcelableArray(mPageRanges, flags);
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.android.internal.os.SomeArgs;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -163,7 +162,7 @@ public final class PrintManager {
|
||||
* @param pdfFile The PDF file to print.
|
||||
* @param documentInfo Information about the printed document.
|
||||
* @param attributes The default print job attributes.
|
||||
* @return The created print job.
|
||||
* @return The created print job on success or null on failure.
|
||||
*
|
||||
* @see PrintJob
|
||||
*/
|
||||
@@ -181,7 +180,7 @@ public final class PrintManager {
|
||||
* @param printJobName A name for the new print job.
|
||||
* @param documentAdapter An adapter that emits the document to print.
|
||||
* @param attributes The default print job attributes.
|
||||
* @return The created print job.
|
||||
* @return The created print job on success or null on failure.
|
||||
*
|
||||
* @see PrintJob
|
||||
*/
|
||||
@@ -279,7 +278,7 @@ public final class PrintManager {
|
||||
}
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = pages;
|
||||
args.arg2 = fd.getFileDescriptor();
|
||||
args.arg2 = fd;
|
||||
args.arg3 = callback;
|
||||
args.argi1 = sequence;
|
||||
mHandler.removeMessages(MyHandler.MSG_WRITE);
|
||||
@@ -342,7 +341,7 @@ public final class PrintManager {
|
||||
case MSG_WRITE: {
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
PageRange[] pages = (PageRange[]) args.arg1;
|
||||
FileDescriptor fd = (FileDescriptor) args.arg2;
|
||||
ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg2;
|
||||
IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
|
||||
final int sequence = args.argi1;
|
||||
args.recycle();
|
||||
@@ -428,12 +427,12 @@ public final class PrintManager {
|
||||
}
|
||||
|
||||
private final class MyWriteResultCallback extends WriteResultCallback {
|
||||
private FileDescriptor mFd;
|
||||
private ParcelFileDescriptor mFd;
|
||||
private int mSequence;
|
||||
private IWriteResultCallback mCallback;
|
||||
|
||||
public MyWriteResultCallback(IWriteResultCallback callback,
|
||||
FileDescriptor fd, int sequence) {
|
||||
ParcelFileDescriptor fd, int sequence) {
|
||||
mFd = fd;
|
||||
mSequence = sequence;
|
||||
mCallback = callback;
|
||||
|
||||
@@ -74,6 +74,7 @@ public final class PrinterDiscoverySession {
|
||||
public final void startPrinterDisovery(List<PrinterId> priorityList) {
|
||||
if (isDestroyed()) {
|
||||
Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
|
||||
return;
|
||||
}
|
||||
if (!mIsPrinterDiscoveryStarted) {
|
||||
mIsPrinterDiscoveryStarted = true;
|
||||
@@ -88,6 +89,7 @@ public final class PrinterDiscoverySession {
|
||||
public final void stopPrinterDiscovery() {
|
||||
if (isDestroyed()) {
|
||||
Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
|
||||
return;
|
||||
}
|
||||
if (mIsPrinterDiscoveryStarted) {
|
||||
mIsPrinterDiscoveryStarted = false;
|
||||
@@ -99,14 +101,39 @@ public final class PrinterDiscoverySession {
|
||||
}
|
||||
}
|
||||
|
||||
public final void requestPrinterUpdate(PrinterId printerId) {
|
||||
public final void startPrinterStateTracking(PrinterId printerId) {
|
||||
if (isDestroyed()) {
|
||||
Log.w(LOG_TAG, "Ignoring reqeust printer update - session destroyed");
|
||||
Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mPrintManager.requestPrinterUpdate(printerId, mUserId);
|
||||
mPrintManager.startPrinterStateTracking(printerId, mUserId);
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "Error requesting printer update", re);
|
||||
Log.e(LOG_TAG, "Error starting printer state tracking", re);
|
||||
}
|
||||
}
|
||||
|
||||
public final void stopPrinterStateTracking(PrinterId printerId) {
|
||||
if (isDestroyed()) {
|
||||
Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mPrintManager.stopPrinterStateTracking(printerId, mUserId);
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "Error stoping printer state tracking", re);
|
||||
}
|
||||
}
|
||||
|
||||
public final void validatePrinters(List<PrinterId> printerIds) {
|
||||
if (isDestroyed()) {
|
||||
Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mPrintManager.validatePrinters(printerIds, mUserId);
|
||||
} catch (RemoteException re) {
|
||||
Log.e(LOG_TAG, "Error validating printers", re);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,10 @@ public final class PrintedPdfDocument {
|
||||
* @see #finishPage(Page)
|
||||
*/
|
||||
public Page startPage(int pageNumber) {
|
||||
PageInfo pageInfo = new PageInfo.Builder(mPageSize, 0).create();
|
||||
PageInfo pageInfo = new PageInfo
|
||||
.Builder(mPageSize, 0)
|
||||
.setContentSize(mContentSize)
|
||||
.create();
|
||||
Page page = mDocument.startPage(pageInfo);
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ oneway interface IPrintService {
|
||||
void createPrinterDiscoverySession();
|
||||
void startPrinterDiscovery(in List<PrinterId> priorityList);
|
||||
void stopPrinterDiscovery();
|
||||
void requestPrinterUpdate(in PrinterId printerId);
|
||||
void validatePrinters(in List<PrinterId> printerIds);
|
||||
void startPrinterStateTracking(in PrinterId printerId);
|
||||
void stopPrinterStateTracking(in PrinterId printerId);
|
||||
void destroyPrinterDiscoverySession();
|
||||
}
|
||||
|
||||
@@ -21,12 +21,15 @@ import android.os.RemoteException;
|
||||
import android.print.PrintDocumentInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class represents a printed document from the perspective of a print
|
||||
* service. It exposes APIs to query the document and obtain its data.
|
||||
* <p>
|
||||
* <strong>Note: </strong> All methods of this class must be executed on the
|
||||
* main application thread.
|
||||
* </p>
|
||||
*/
|
||||
public final class PrintDocument {
|
||||
|
||||
@@ -51,6 +54,7 @@ public final class PrintDocument {
|
||||
* @return The document info.
|
||||
*/
|
||||
public PrintDocumentInfo getInfo() {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
@@ -64,7 +68,8 @@ public final class PrintDocument {
|
||||
*
|
||||
* @return A file descriptor for reading the data.
|
||||
*/
|
||||
public FileDescriptor getData() {
|
||||
public ParcelFileDescriptor getData() {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
ParcelFileDescriptor source = null;
|
||||
ParcelFileDescriptor sink = null;
|
||||
try {
|
||||
@@ -72,7 +77,7 @@ public final class PrintDocument {
|
||||
source = fds[0];
|
||||
sink = fds[1];
|
||||
mPrintServiceClient.writePrintJobData(sink, mPrintJobId);
|
||||
return source.getFileDescriptor();
|
||||
return source;
|
||||
} catch (IOException ioe) {
|
||||
Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
|
||||
} catch (RemoteException re) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.printservice;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.print.PrintJobInfo;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -122,6 +123,21 @@ public final class PrintJob {
|
||||
return getInfo().getState() == PrintJobInfo.STATE_STARTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this print job is blocked. Such a print job is halted
|
||||
* due to an abnormal condition and can be started or canceled or failed.
|
||||
*
|
||||
* @return Whether the print job is blocked.
|
||||
*
|
||||
* @see #start()
|
||||
* @see #cancel()
|
||||
* @see #fail(CharSequence)
|
||||
*/
|
||||
public boolean isBlocked() {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this print job is completed. Such a print job
|
||||
* is successfully printed. This is a final state.
|
||||
@@ -163,20 +179,48 @@ public final class PrintJob {
|
||||
|
||||
/**
|
||||
* Starts the print job. You should call this method if {@link
|
||||
* #isQueued()} returns true and you started printing.
|
||||
* #isQueued()} or {@link #isBlocked()} returns true and you started
|
||||
* resumed printing.
|
||||
*
|
||||
* @return Whether the job as started.
|
||||
* @return Whether the job was started.
|
||||
*
|
||||
* @see #isQueued()
|
||||
* @see #isBlocked()
|
||||
*/
|
||||
public boolean start() {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
if (isQueued()) {
|
||||
final int state = getInfo().getState();
|
||||
if (state == PrintJobInfo.STATE_QUEUED
|
||||
|| state == PrintJobInfo.STATE_BLOCKED) {
|
||||
return setState(PrintJobInfo.STATE_STARTED, null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the print job. You should call this method if {@link
|
||||
* #isStarted()} or {@link #isBlocked()} returns true and you need
|
||||
* to block the print job. For example, the user has to add some
|
||||
* paper to continue printing. To resume the print job call {@link
|
||||
* #start()}.
|
||||
*
|
||||
* @return Whether the job was blocked.
|
||||
*
|
||||
* @see #isStarted()
|
||||
* @see #isBlocked()
|
||||
*/
|
||||
public boolean block(String reason) {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
PrintJobInfo info = getInfo();
|
||||
final int state = info.getState();
|
||||
if (state == PrintJobInfo.STATE_STARTED
|
||||
|| (state == PrintJobInfo.STATE_BLOCKED
|
||||
&& !TextUtils.equals(info.getStateReason(), reason))) {
|
||||
return setState(PrintJobInfo.STATE_BLOCKED, reason);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the print job. You should call this method if {@link
|
||||
* #isStarted()} returns true and you are done printing.
|
||||
@@ -195,8 +239,8 @@ public final class PrintJob {
|
||||
|
||||
/**
|
||||
* Fails the print job. You should call this method if {@link
|
||||
* #isQueued()} or {@link #isStarted()} returns true you failed
|
||||
* while printing.
|
||||
* #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
|
||||
* returns true you failed while printing.
|
||||
*
|
||||
* @param error The human readable, short, and translated reason
|
||||
* for the failure.
|
||||
@@ -204,10 +248,11 @@ public final class PrintJob {
|
||||
*
|
||||
* @see #isQueued()
|
||||
* @see #isStarted()
|
||||
* @see #isBlocked()
|
||||
*/
|
||||
public boolean fail(String error) {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
if (isQueued() || isStarted()) {
|
||||
if (!isInImmutableState()) {
|
||||
return setState(PrintJobInfo.STATE_FAILED, error);
|
||||
}
|
||||
return false;
|
||||
@@ -215,18 +260,19 @@ public final class PrintJob {
|
||||
|
||||
/**
|
||||
* Cancels the print job. You should call this method if {@link
|
||||
* #isQueued()} or {@link #isStarted()} returns true and you canceled
|
||||
* the print job as a response to a call to {@link
|
||||
* PrintService#onRequestCancelPrintJob(PrintJob)}.
|
||||
* #isQueued()} or {@link #isStarted() or #isBlocked()} returns
|
||||
* true and you canceled the print job as a response to a call to
|
||||
* {@link PrintService#onRequestCancelPrintJob(PrintJob)}.
|
||||
*
|
||||
* @return Whether the job is canceled.
|
||||
*
|
||||
* @see #isStarted()
|
||||
* @see #isQueued()
|
||||
* @see #isBlocked()
|
||||
*/
|
||||
public boolean cancel() {
|
||||
PrintService.throwIfNotCalledOnMainThread();
|
||||
if (isQueued() || isStarted()) {
|
||||
if (!isInImmutableState()) {
|
||||
return setState(PrintJobInfo.STATE_CANCELED, null);
|
||||
}
|
||||
return false;
|
||||
@@ -277,7 +323,8 @@ public final class PrintJob {
|
||||
private boolean isInImmutableState() {
|
||||
final int state = mCachedInfo.getState();
|
||||
return state == PrintJobInfo.STATE_COMPLETED
|
||||
|| state == PrintJobInfo.STATE_CANCELED;
|
||||
|| state == PrintJobInfo.STATE_CANCELED
|
||||
|| state == PrintJobInfo.STATE_FAILED;
|
||||
}
|
||||
|
||||
private boolean setState(int state, String error) {
|
||||
@@ -287,7 +334,7 @@ public final class PrintJob {
|
||||
// we may not be able to re-fetch it later if the job gets
|
||||
// removed from the spooler as a result of the state change.
|
||||
mCachedInfo.setState(state);
|
||||
mCachedInfo.setFailureReason(error);
|
||||
mCachedInfo.setStateReason(error);
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
|
||||
@@ -314,8 +314,20 @@ public abstract class PrintService extends Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPrinterUpdate(PrinterId printerId) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_PRINTER_UPDATE,
|
||||
public void validatePrinters(List<PrinterId> printerIds) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
|
||||
printerIds).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPrinterStateTracking(PrinterId printerId) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
|
||||
printerId).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopPrinterStateTracking(PrinterId printerId) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
|
||||
printerId).sendToTarget();
|
||||
}
|
||||
|
||||
@@ -344,10 +356,12 @@ public abstract class PrintService extends Service {
|
||||
public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
|
||||
public static final int MSG_START_PRINTER_DISCOVERY = 3;
|
||||
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
|
||||
public static final int MSG_REQUEST_PRINTER_UPDATE = 5;
|
||||
public static final int MSG_ON_PRINTJOB_QUEUED = 6;
|
||||
public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 7;
|
||||
public static final int MSG_SET_CLEINT = 8;
|
||||
public static final int MSG_VALIDATE_PRINTERS = 5;
|
||||
public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
|
||||
public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
|
||||
public static final int MSG_ON_PRINTJOB_QUEUED = 8;
|
||||
public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
|
||||
public static final int MSG_SET_CLEINT = 10;
|
||||
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper, null, true);
|
||||
@@ -391,10 +405,24 @@ public abstract class PrintService extends Service {
|
||||
}
|
||||
} break;
|
||||
|
||||
case MSG_REQUEST_PRINTER_UPDATE: {
|
||||
case MSG_VALIDATE_PRINTERS: {
|
||||
if (mDiscoverySession != null) {
|
||||
List<PrinterId> printerIds = (List<PrinterId>) message.obj;
|
||||
mDiscoverySession.validatePrinters(printerIds);
|
||||
}
|
||||
} break;
|
||||
|
||||
case MSG_START_PRINTER_STATE_TRACKING: {
|
||||
if (mDiscoverySession != null) {
|
||||
PrinterId printerId = (PrinterId) message.obj;
|
||||
mDiscoverySession.requestPrinterUpdate(printerId);
|
||||
mDiscoverySession.startPrinterStateTracking(printerId);
|
||||
}
|
||||
} break;
|
||||
|
||||
case MSG_STOP_PRINTER_STATE_TRACKING: {
|
||||
if (mDiscoverySession != null) {
|
||||
PrinterId printerId = (PrinterId) message.obj;
|
||||
mDiscoverySession.stopPrinterStateTracking(printerId);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@@ -53,15 +53,23 @@ import java.util.List;
|
||||
* session. Printers are <strong>not</strong> persisted across sessions.
|
||||
* </p>
|
||||
* <p>
|
||||
* The system will make a call to
|
||||
* {@link PrinterDiscoverySession#onRequestPrinterUpdate(PrinterId)} if you
|
||||
* need to update a given printer. It is possible that you add a printer without
|
||||
* The system will make a call to {@link #onValidatePrinters(List)} if you
|
||||
* need to update some printers. It is possible that you add a printer without
|
||||
* specifying its capabilities. This enables you to avoid querying all discovered
|
||||
* printers for their capabilities, rather querying the capabilities of a printer
|
||||
* only if necessary. For example, the system will request that you update a printer
|
||||
* if it gets selected by the user. If you did not report the printer capabilities
|
||||
* when adding it, you must do so after the system requests a printer update.
|
||||
* Otherwise, the printer will be ignored.
|
||||
* if it gets selected by the user. When validating printers you do not need to
|
||||
* provide the printers' capabilities but may do so.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the system is interested in being constantly updated for the state of a
|
||||
* printer you will receive a call to {@link #onStartPrinterStateTracking(PrinterId)}
|
||||
* after which you will have to do a best effort to keep the system updated for
|
||||
* changes in the printer state and capabilities. You also <strong>must</strong>
|
||||
* update the printer capabilities if you did not provide them when adding it, or
|
||||
* the printer will be ignored. When the system is no longer interested in getting
|
||||
* updates for a printer you will receive a call to {@link #onStopPrinterStateTracking(
|
||||
* PrinterId)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note: </strong> All callbacks in this class are executed on the main
|
||||
@@ -115,7 +123,7 @@ public abstract class PrinterDiscoverySession {
|
||||
* the printer that was added but not removed.
|
||||
* <p>
|
||||
* <strong>Note: </strong> Calls to this method after the session is
|
||||
* destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
|
||||
* destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @return The printers.
|
||||
@@ -139,7 +147,7 @@ public abstract class PrinterDiscoverySession {
|
||||
* times during the life of this session. Duplicates will be ignored.
|
||||
* <p>
|
||||
* <strong>Note: </strong> Calls to this method after the session is
|
||||
* destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
|
||||
* destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param printers The printers to add.
|
||||
@@ -218,7 +226,7 @@ public abstract class PrinterDiscoverySession {
|
||||
* call this method multiple times during the lifetime of this session.
|
||||
* <p>
|
||||
* <strong>Note: </strong> Calls to this method after the session is
|
||||
* destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
|
||||
* destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param printerIds The ids of the removed printers.
|
||||
@@ -293,7 +301,7 @@ public abstract class PrinterDiscoverySession {
|
||||
* during the lifetime of this session.
|
||||
* <p>
|
||||
* <strong>Note: </strong> Calls to this method after the session is
|
||||
* destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
|
||||
* destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param printers The printers to update.
|
||||
@@ -441,7 +449,9 @@ public abstract class PrinterDiscoverySession {
|
||||
* <p>
|
||||
* <strong>Note: </strong>You are also given a list of printers whose availability
|
||||
* has to be checked first. For example, these printers could be the user's favorite
|
||||
* ones, therefore they have to be verified first.
|
||||
* ones, therefore they have to be verified first. You do <strong>not need</strong>
|
||||
* to provide the capabilities of the printers, rather verify whether they exist
|
||||
* similarly to {@link #onValidatePrinters(List)}.
|
||||
* </p>
|
||||
*
|
||||
* @param priorityList The list of printers to validate first. Never null.
|
||||
@@ -463,9 +473,28 @@ public abstract class PrinterDiscoverySession {
|
||||
public abstract void onStopPrinterDiscovery();
|
||||
|
||||
/**
|
||||
* Requests that you update a printer. You are responsible for updating
|
||||
* the printer by also reporting its capabilities via calling {@link
|
||||
* #updatePrinters(List)}.
|
||||
* Callback asking you to validate that the given printers are valid, that
|
||||
* is they exist. You are responsible for checking whether these printers
|
||||
* exist and for the ones that do exist notify the system via calling
|
||||
* {@link #updatePrinters(List)}.
|
||||
* <p>
|
||||
* <strong>Note: </strong> You are <strong>not required</strong> to provide
|
||||
* the printer capabilities when updating the printers that do exist.
|
||||
* <p>
|
||||
*
|
||||
* @param printerIds The printers to validate.
|
||||
*
|
||||
* @see #updatePrinters(List)
|
||||
* @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
|
||||
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
|
||||
*/
|
||||
public abstract void onValidatePrinters(List<PrinterId> printerIds);
|
||||
|
||||
/**
|
||||
* Callback asking you to start tracking the state of a printer. Tracking
|
||||
* the state means that you should do a best effort to observe the state
|
||||
* of this printer and notify the system if that state changes via calling
|
||||
* {@link #updatePrinters(List)}.
|
||||
* <p>
|
||||
* <strong>Note: </strong> A printer can be initially added without its
|
||||
* capabilities to avoid polling printers that the user will not select.
|
||||
@@ -473,18 +502,33 @@ public abstract class PrinterDiscoverySession {
|
||||
* printer <strong>including</strong> its capabilities. Otherwise, the
|
||||
* printer will be ignored.
|
||||
* <p>
|
||||
* A scenario when you may be requested to update a printer is if the user
|
||||
* selects it and the system has to present print options UI based on the
|
||||
* printer's capabilities.
|
||||
* <p>
|
||||
* A scenario when you may be requested to track a printer's state is if
|
||||
* the user selects that printer and the system has to present print
|
||||
* options UI based on the printer's capabilities. In this case the user
|
||||
* should be promptly informed if, for example, the printer becomes
|
||||
* unavailable.
|
||||
* </p>
|
||||
*
|
||||
* @param printerId The printer id.
|
||||
* @param printerId The printer to start tracking.
|
||||
*
|
||||
* @see #onStopPrinterStateTracking(PrinterId)
|
||||
* @see #updatePrinters(List)
|
||||
* @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
|
||||
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
|
||||
*/
|
||||
public abstract void onRequestPrinterUpdate(PrinterId printerId);
|
||||
public abstract void onStartPrinterStateTracking(PrinterId printerId);
|
||||
|
||||
/**
|
||||
* Callback asking you to stop tracking the state of a printer. The passed
|
||||
* in printer id is the one for which you received a call to {@link
|
||||
* #onStartPrinterStateTracking(PrinterId)}.
|
||||
*
|
||||
* @param printerId The printer to stop tracking.
|
||||
*
|
||||
* @see #onStartPrinterStateTracking(PrinterId)
|
||||
*/
|
||||
public abstract void onStopPrinterStateTracking(PrinterId printerId);
|
||||
|
||||
/**
|
||||
* Notifies you that the session is destroyed. After this callback is invoked
|
||||
@@ -538,9 +582,21 @@ public abstract class PrinterDiscoverySession {
|
||||
}
|
||||
}
|
||||
|
||||
void requestPrinterUpdate(PrinterId printerId) {
|
||||
if (!mIsDestroyed) {
|
||||
onRequestPrinterUpdate(printerId);
|
||||
void validatePrinters(List<PrinterId> printerIds) {
|
||||
if (!mIsDestroyed && mObserver != null) {
|
||||
onValidatePrinters(printerIds);
|
||||
}
|
||||
}
|
||||
|
||||
void startPrinterStateTracking(PrinterId printerId) {
|
||||
if (!mIsDestroyed && mObserver != null) {
|
||||
onStartPrinterStateTracking(printerId);
|
||||
}
|
||||
}
|
||||
|
||||
void stopPrinterStateTracking(PrinterId printerId) {
|
||||
if (!mIsDestroyed && mObserver != null) {
|
||||
onStopPrinterStateTracking(printerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1919,13 +1919,10 @@
|
||||
android:description="@string/permdesc_bindNfcService"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an application to call APIs that give it access to all print jobs
|
||||
on the device. Usually an app can access only the print jobts it created.
|
||||
This permission is not available to third party applications.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"
|
||||
android:label="@string/permlab_accessAllPrintJobs"
|
||||
android:description="@string/permdesc_accessAllPrintJobs"
|
||||
<!-- Must be required by the PrintSpooler to ensure that only the system can bind to it. -->
|
||||
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
|
||||
android:label="@string/permlab_bindPrintSpoolerService"
|
||||
android:description="@string/permdesc_bindPrintSpoolerService"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Must be required by a TextService (e.g. SpellCheckerService)
|
||||
|
||||
@@ -984,12 +984,13 @@
|
||||
<string name="permdesc_bindPrintService">Allows the holder to bind to the top-level
|
||||
interface of a print service. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_accessAllPrintJobs">access all print jobs</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs
|
||||
created by another app. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose
|
||||
whether they want to allow the application to do this. -->
|
||||
<string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string>
|
||||
<!-- Description of an application permission, listed so the user can
|
||||
choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_bindPrintSpoolerService">Allows the holder to bind to the top-level
|
||||
interface of a print spooler service. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_bindNfcService">bind to NFC service</string>
|
||||
@@ -4292,6 +4293,9 @@
|
||||
<!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
|
||||
<string name="write_fail_reason_cannot_write">Error writing content</string>
|
||||
|
||||
<!-- Print fail reason: unknown. [CHAR LIMIT=25] -->
|
||||
<string name="reason_unknown">unknown</string>
|
||||
|
||||
<!-- PIN entry dialog label/hint for PIN [CHAR LIMIT=none] -->
|
||||
<string name="restr_pin_enter_pin">Enter PIN</string>
|
||||
<!-- PIN entry dialog label/hint for old PIN [CHAR LIMIT=none] -->
|
||||
|
||||
@@ -869,6 +869,7 @@
|
||||
<java-symbol type="string" name="mediaSize_na_junior_legal" />
|
||||
<java-symbol type="string" name="mediaSize_na_ledger" />
|
||||
<java-symbol type="string" name="mediaSize_na_tabloid" />
|
||||
<java-symbol type="string" name="reason_unknown" />
|
||||
<java-symbol type="string" name="restr_pin_enter_pin" />
|
||||
<java-symbol type="string" name="write_fail_reason_cancelled" />
|
||||
<java-symbol type="string" name="write_fail_reason_cannot_write" />
|
||||
|
||||
@@ -24,8 +24,6 @@ LOCAL_PACKAGE_NAME := PrintSpooler
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := framework-base
|
||||
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
@@ -20,18 +20,22 @@
|
||||
package="com.android.printspooler"
|
||||
android:sharedUserId="android.uid.printspooler"
|
||||
android:versionName="1"
|
||||
android:versionCode="1"
|
||||
coreApp="true">
|
||||
android:versionCode="1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
|
||||
<!-- Allows an application to call APIs that give it access to all print jobs
|
||||
on the device. Usually an app can access only the print jobs it created.
|
||||
-->
|
||||
<permission
|
||||
android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"
|
||||
android:label="@string/permlab_accessAllPrintJobs"
|
||||
android:description="@string/permdesc_accessAllPrintJobs"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
|
||||
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
|
||||
android:label="@string/permlab_bindPrintSpoolerService"
|
||||
android:description="@string/permdesc_bindPrintSpoolerService"
|
||||
android:protectionLevel="signature" />
|
||||
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
|
||||
|
||||
<application
|
||||
android:allowClearUserData="false"
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
<!-- Template for the notificaiton label for a failed print job. [CHAR LIMIT=25] -->
|
||||
<string name="failed_notification_title_template">Printer error <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Template for the notificaiton label for a blocked print job. [CHAR LIMIT=25] -->
|
||||
<string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] -->
|
||||
<string name="cancel">Cancel</string>
|
||||
|
||||
@@ -103,6 +106,9 @@
|
||||
<!-- Message that there is no connection to a printer. [CHAR LIMIT=40] -->
|
||||
<string name="no_connection_to_printer">No connection to printer</string>
|
||||
|
||||
<!-- Label for an unknown reason for failed or blocked print job. [CHAR LIMIT=25] -->
|
||||
<string name="reason_unknown">unknown</string>
|
||||
|
||||
<!-- Arrays -->
|
||||
|
||||
<!-- Color mode labels. -->
|
||||
@@ -129,12 +135,14 @@
|
||||
<item>Range</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose
|
||||
whether they want to allow the application to do this. -->
|
||||
<string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string>
|
||||
<!-- Description of an application permission, listed so the user can
|
||||
choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_bindPrintSpoolerService">Allows the holder to bind to the top-level
|
||||
interface of a print spooler service. Should never be needed for normal apps.</string>
|
||||
<!-- Permissions -->
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want
|
||||
to allow the application to do this. -->
|
||||
<string name="permlab_accessAllPrintJobs">access all print jobs</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether
|
||||
they want to allow the application to do this. -->
|
||||
<string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs
|
||||
created by another app. Should never be needed for normal apps.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -75,6 +75,8 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
|
||||
|
||||
private List<PrinterInfo> mFavoritePrinters;
|
||||
|
||||
private PrinterId mTrackedPrinter;
|
||||
|
||||
public FusedPrintersProvider(Context context) {
|
||||
super(context);
|
||||
mPersistenceManager = new PersistenceManager(context);
|
||||
@@ -166,6 +168,10 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
|
||||
private boolean cancelInternal() {
|
||||
if (mDiscoverySession != null
|
||||
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
|
||||
if (mTrackedPrinter != null) {
|
||||
mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter);
|
||||
mTrackedPrinter = null;
|
||||
}
|
||||
mDiscoverySession.stopPrinterDiscovery();
|
||||
return true;
|
||||
} else if (mPersistenceManager.isReadHistoryInProgress()) {
|
||||
@@ -195,10 +201,14 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
|
||||
onStopLoading();
|
||||
}
|
||||
|
||||
public void refreshPrinter(PrinterId printerId) {
|
||||
public void setTrackedPrinter(PrinterId printerId) {
|
||||
if (isStarted() && mDiscoverySession != null
|
||||
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
|
||||
mDiscoverySession.requestPrinterUpdate(printerId);
|
||||
if (mTrackedPrinter != null) {
|
||||
mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter);
|
||||
}
|
||||
mTrackedPrinter = printerId;
|
||||
mDiscoverySession.startPrinterStateTracking(printerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.UserHandle;
|
||||
import android.print.IPrintManager;
|
||||
import android.print.PrintJobInfo;
|
||||
import android.print.PrintManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -64,22 +65,27 @@ public class NotificationController {
|
||||
+ " state:" + PrintJobInfo.stateToString(printJob.getState()));
|
||||
}
|
||||
switch (printJob.getState()) {
|
||||
case PrintJobInfo.STATE_QUEUED: {
|
||||
createPrintingNotificaiton(printJob);
|
||||
case PrintJobInfo.STATE_QUEUED:
|
||||
case PrintJobInfo.STATE_STARTED: {
|
||||
createPrintingNotification(printJob);
|
||||
} break;
|
||||
|
||||
case PrintJobInfo.STATE_FAILED: {
|
||||
createFailedNotificaiton(printJob);
|
||||
createFailedNotification(printJob);
|
||||
} break;
|
||||
|
||||
case PrintJobInfo.STATE_COMPLETED:
|
||||
case PrintJobInfo.STATE_CANCELED: {
|
||||
removeNotification(printJob.getId());
|
||||
} break;
|
||||
|
||||
case PrintJobInfo.STATE_BLOCKED: {
|
||||
createBlockedNotification(printJob);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
private void createPrintingNotificaiton(PrintJobInfo printJob) {
|
||||
private void createPrintingNotification(PrintJobInfo printJob) {
|
||||
Notification.Builder builder = new Notification.Builder(mContext)
|
||||
.setSmallIcon(R.drawable.stat_notify_print)
|
||||
.setContentTitle(mContext.getString(R.string.printing_notification_title_template,
|
||||
@@ -93,17 +99,36 @@ public class NotificationController {
|
||||
mNotificationManager.notify(printJob.getId(), builder.build());
|
||||
}
|
||||
|
||||
private void createFailedNotificaiton(PrintJobInfo printJob) {
|
||||
private void createFailedNotification(PrintJobInfo printJob) {
|
||||
String reason = !TextUtils.isEmpty(printJob.getStateReason())
|
||||
? printJob.getStateReason() : mContext.getString(R.string.reason_unknown);
|
||||
|
||||
Notification.Builder builder = new Notification.Builder(mContext)
|
||||
.setSmallIcon(R.drawable.stat_notify_error)
|
||||
.setContentTitle(mContext.getString(R.string.failed_notification_title_template,
|
||||
printJob.getLabel()))
|
||||
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
|
||||
createCancelIntent(printJob))
|
||||
// TODO: Use appropriate icon when assets are ready
|
||||
.addAction(android.R.drawable.ic_secure, mContext.getString(R.string.restart),
|
||||
createRestartIntent(printJob.getId()))
|
||||
.setContentText(printJob.getFailureReason())
|
||||
.setContentText(reason)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setOngoing(true)
|
||||
.setShowWhen(true);
|
||||
mNotificationManager.notify(printJob.getId(), builder.build());
|
||||
}
|
||||
|
||||
private void createBlockedNotification(PrintJobInfo printJob) {
|
||||
String reason = !TextUtils.isEmpty(printJob.getStateReason())
|
||||
? printJob.getStateReason() : mContext.getString(R.string.reason_unknown);
|
||||
|
||||
Notification.Builder builder = new Notification.Builder(mContext)
|
||||
.setSmallIcon(R.drawable.stat_notify_error)
|
||||
.setContentTitle(mContext.getString(R.string.blocked_notification_title_template,
|
||||
printJob.getLabel()))
|
||||
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
|
||||
createCancelIntent(printJob))
|
||||
.setContentText(reason)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setOngoing(true)
|
||||
.setShowWhen(true);
|
||||
|
||||
@@ -473,6 +473,11 @@ public class PrintJobConfigActivity extends Activity {
|
||||
|
||||
mControllerState = CONTROLLER_STATE_WRITE_COMPLETED;
|
||||
|
||||
// Update the document size.
|
||||
File file = PrintSpoolerService.peekInstance()
|
||||
.generateFileForPrintJob(mPrintJobId);
|
||||
mDocument.info.setDataSize(file.length());
|
||||
|
||||
// Update which pages we have fetched.
|
||||
mDocument.pages = PageRangeUtils.normalize(pages);
|
||||
|
||||
@@ -1117,7 +1122,7 @@ public class PrintJobConfigActivity extends Activity {
|
||||
(Loader<?>) getLoaderManager().getLoader(
|
||||
LOADER_ID_PRINTERS_LOADER);
|
||||
if (printersLoader != null) {
|
||||
printersLoader.refreshPrinter(printer.getId());
|
||||
printersLoader.setTrackedPrinter(printer.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1351,10 +1356,6 @@ public class PrintJobConfigActivity extends Activity {
|
||||
return mEditorState == EDITOR_STATE_CONFIRMED_PRINT;
|
||||
}
|
||||
|
||||
// public void confirmPreview() {
|
||||
// mEditorState = EDITOR_STATE_CONFIRMED_PREVIEW;
|
||||
// }
|
||||
|
||||
public PageRange[] getRequestedPages() {
|
||||
if (hasErrors()) {
|
||||
return null;
|
||||
@@ -1374,7 +1375,7 @@ public class PrintJobConfigActivity extends Activity {
|
||||
toIndex = Integer.parseInt(range.substring(
|
||||
dashIndex + 1, range.length())) - 1;
|
||||
} else {
|
||||
fromIndex = toIndex = Integer.parseInt(range);
|
||||
fromIndex = toIndex = Integer.parseInt(range) - 1;
|
||||
}
|
||||
|
||||
PageRange pageRange = new PageRange(fromIndex, toIndex);
|
||||
|
||||
@@ -335,7 +335,9 @@ public final class PrintSpoolerService extends Service {
|
||||
final boolean sameState = (state == printJob.getState())
|
||||
|| (state == PrintJobInfo.STATE_ANY)
|
||||
|| (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
|
||||
&& printJob.getState() > PrintJobInfo.STATE_CREATED);
|
||||
&& isStateVisibleToUser(printJob.getState()))
|
||||
|| (state == PrintJobInfo.STATE_ANY_ACTIVE
|
||||
&& isActiveState(printJob.getState()));
|
||||
if (sameComponent && sameAppId && sameState) {
|
||||
if (foundPrintJobs == null) {
|
||||
foundPrintJobs = new ArrayList<PrintJobInfo>();
|
||||
@@ -347,6 +349,11 @@ public final class PrintSpoolerService extends Service {
|
||||
return foundPrintJobs;
|
||||
}
|
||||
|
||||
private boolean isStateVisibleToUser(int state) {
|
||||
return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
|
||||
|| state == PrintJobInfo.STATE_COMPLETED|| state == PrintJobInfo.STATE_CANCELED));
|
||||
}
|
||||
|
||||
public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
|
||||
synchronized (mLock) {
|
||||
final int printJobCount = mPrintJobs.size();
|
||||
@@ -389,14 +396,12 @@ public final class PrintSpoolerService extends Service {
|
||||
|
||||
switch (printJob.getState()) {
|
||||
case PrintJobInfo.STATE_QUEUED:
|
||||
case PrintJobInfo.STATE_STARTED: {
|
||||
// We have a print job that was queued or started 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
|
||||
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));
|
||||
}
|
||||
@@ -501,7 +506,7 @@ public final class PrintSpoolerService extends Service {
|
||||
success = true;
|
||||
|
||||
printJob.setState(state);
|
||||
printJob.setFailureReason(error);
|
||||
printJob.setStateReason(error);
|
||||
mNotificationController.onPrintJobStateChanged(printJob);
|
||||
|
||||
if (DEBUG_PRINT_JOB_LIFECYCLE) {
|
||||
@@ -568,7 +573,8 @@ public final class PrintSpoolerService extends Service {
|
||||
private boolean isActiveState(int printJobState) {
|
||||
return printJobState == PrintJobInfo.STATE_CREATED
|
||||
|| printJobState == PrintJobInfo.STATE_QUEUED
|
||||
|| printJobState == PrintJobInfo.STATE_STARTED;
|
||||
|| printJobState == PrintJobInfo.STATE_STARTED
|
||||
|| printJobState == PrintJobInfo.STATE_BLOCKED;
|
||||
}
|
||||
|
||||
public boolean setPrintJobTag(int printJobId, String tag) {
|
||||
|
||||
@@ -254,7 +254,7 @@ public final class PrintManagerService extends IPrintManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPrinterUpdate(PrinterId printerId, int userId) {
|
||||
public void validatePrinters(List<PrinterId> printerIds, int userId) {
|
||||
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
|
||||
final UserState userState;
|
||||
synchronized (mLock) {
|
||||
@@ -262,7 +262,37 @@ public final class PrintManagerService extends IPrintManager.Stub {
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
userState.requestPrinterUpdate(printerId);
|
||||
userState.validatePrinters(printerIds);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPrinterStateTracking(PrinterId printerId, int userId) {
|
||||
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
|
||||
final UserState userState;
|
||||
synchronized (mLock) {
|
||||
userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
userState.startPrinterStateTracking(printerId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopPrinterStateTracking(PrinterId printerId, int userId) {
|
||||
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
|
||||
final UserState userState;
|
||||
synchronized (mLock) {
|
||||
userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
userState.stopPrinterStateTracking(printerId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
@@ -432,10 +462,12 @@ public final class PrintManagerService extends IPrintManager.Stub {
|
||||
if (appId == callingAppId) {
|
||||
return appId;
|
||||
}
|
||||
if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS)
|
||||
if (mContext.checkCallingPermission(
|
||||
"com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Call from app " + callingAppId + " as app "
|
||||
+ appId + " without permission ACCESS_ALL_PRINT_JOBS");
|
||||
+ appId + " without com.android.printspooler.permission"
|
||||
+ ".ACCESS_ALL_PRINT_JOBS");
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IBinder.DeathRecipient;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
@@ -38,6 +39,8 @@ import android.printservice.IPrintService;
|
||||
import android.printservice.IPrintServiceClient;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -121,6 +124,36 @@ final class RemotePrintService implements DeathRecipient {
|
||||
mHasPrinterDiscoverySession = false;
|
||||
mPendingCommands.clear();
|
||||
ensureUnbound();
|
||||
|
||||
// Makes sure all active print jobs are failed since the service
|
||||
// just died. Do this off the main thread since we do to allow
|
||||
// calls into the spooler on the main thread.
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
failAllActivePrintJobs();
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||
}
|
||||
|
||||
private void failAllActivePrintJobs() {
|
||||
List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName,
|
||||
PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
|
||||
if (printJobs == null) {
|
||||
return;
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final int printJobCount = printJobs.size();
|
||||
for (int i = 0; i < printJobCount; i++) {
|
||||
PrintJobInfo printJob = printJobs.get(i);
|
||||
mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
|
||||
mContext.getString(R.string.reason_unknown));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOnAllPrintJobsHandled() {
|
||||
@@ -308,29 +341,83 @@ final class RemotePrintService implements DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
public void requestPrinterUpdate(PrinterId printerId) {
|
||||
mHandler.obtainMessage(MyHandler.MSG_REQUEST_PRINTER_UPDATE,
|
||||
printerId).sendToTarget();
|
||||
public void validatePrinters(List<PrinterId> printerIds) {
|
||||
mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS,
|
||||
printerIds).sendToTarget();
|
||||
}
|
||||
|
||||
private void handleRequestPrinterUpdate(final PrinterId printerId) {
|
||||
private void handleValidatePrinters(final List<PrinterId> printerIds) {
|
||||
throwIfDestroyed();
|
||||
if (!isBound()) {
|
||||
ensureBound();
|
||||
mPendingCommands.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleRequestPrinterUpdate(printerId);
|
||||
handleValidatePrinters(printerIds);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "[user: " + mUserId + "] requestPrinterUpdate()");
|
||||
Slog.i(LOG_TAG, "[user: " + mUserId + "] handleValidatePrinters()");
|
||||
}
|
||||
try {
|
||||
mPrintService.requestPrinterUpdate(printerId);
|
||||
mPrintService.validatePrinters(printerIds);
|
||||
} catch (RemoteException re) {
|
||||
Slog.e(LOG_TAG, "Error requesting a printer update.", re);
|
||||
Slog.e(LOG_TAG, "Error requesting printers validation.", re);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startPrinterStateTracking(PrinterId printerId) {
|
||||
mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING,
|
||||
printerId).sendToTarget();
|
||||
}
|
||||
|
||||
private void handleStartPrinterStateTracking(final PrinterId printerId) {
|
||||
throwIfDestroyed();
|
||||
if (!isBound()) {
|
||||
ensureBound();
|
||||
mPendingCommands.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleStartPrinterStateTracking(printerId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStartPrinterTracking()");
|
||||
}
|
||||
try {
|
||||
mPrintService.startPrinterStateTracking(printerId);
|
||||
} catch (RemoteException re) {
|
||||
Slog.e(LOG_TAG, "Error requesting start printer tracking.", re);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopPrinterStateTracking(PrinterId printerId) {
|
||||
mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING,
|
||||
printerId).sendToTarget();
|
||||
}
|
||||
|
||||
private void handleStopPrinterStateTracking(final PrinterId printerId) {
|
||||
throwIfDestroyed();
|
||||
if (!isBound()) {
|
||||
ensureBound();
|
||||
mPendingCommands.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleStopPrinterStateTracking(printerId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStopPrinterTracking()");
|
||||
}
|
||||
try {
|
||||
mPrintService.stopPrinterStateTracking(printerId);
|
||||
} catch (RemoteException re) {
|
||||
Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,12 +504,14 @@ final class RemotePrintService implements DeathRecipient {
|
||||
public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
|
||||
public static final int MSG_START_PRINTER_DISCOVERY = 3;
|
||||
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
|
||||
public static final int MSG_REQUEST_PRINTER_UPDATE = 5;
|
||||
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 6;
|
||||
public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 7;
|
||||
public static final int MSG_ON_PRINT_JOB_QUEUED = 8;
|
||||
public static final int MSG_DESTROY = 9;
|
||||
public static final int MSG_BINDER_DIED = 10;
|
||||
public static final int MSG_VALIDATE_PRINTERS = 5;
|
||||
public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
|
||||
public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
|
||||
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 8;
|
||||
public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9;
|
||||
public static final int MSG_ON_PRINT_JOB_QUEUED = 10;
|
||||
public static final int MSG_DESTROY = 11;
|
||||
public static final int MSG_BINDER_DIED = 12;
|
||||
|
||||
public MyHandler(Looper looper) {
|
||||
super(looper, null, false);
|
||||
@@ -449,9 +538,19 @@ final class RemotePrintService implements DeathRecipient {
|
||||
handleStopPrinterDiscovery();
|
||||
} break;
|
||||
|
||||
case MSG_REQUEST_PRINTER_UPDATE: {
|
||||
case MSG_VALIDATE_PRINTERS: {
|
||||
List<PrinterId> printerIds = (List<PrinterId>) message.obj;
|
||||
handleValidatePrinters(printerIds);
|
||||
} break;
|
||||
|
||||
case MSG_START_PRINTER_STATE_TRACKING: {
|
||||
PrinterId printerId = (PrinterId) message.obj;
|
||||
handleRequestPrinterUpdate(printerId);
|
||||
handleStartPrinterStateTracking(printerId);
|
||||
} break;
|
||||
|
||||
case MSG_STOP_PRINTER_STATE_TRACKING: {
|
||||
PrinterId printerId = (PrinterId) message.obj;
|
||||
handleStopPrinterStateTracking(printerId);
|
||||
} break;
|
||||
|
||||
case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
|
||||
|
||||
@@ -19,8 +19,12 @@ package com.android.server.print;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -46,6 +50,7 @@ import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -63,6 +68,11 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
|
||||
private static final char COMPONENT_NAME_SEPARATOR = ':';
|
||||
|
||||
private static final String SHARED_PREFERENCES_FILE = "shared_prefs";
|
||||
|
||||
private static final String KEY_SYSTEM_PRINT_SERVICES_ENABLED =
|
||||
"KEY_SYSTEM_PRINT_SERVICES_ENABLED";
|
||||
|
||||
private final SimpleStringSplitter mStringColonSplitter =
|
||||
new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
|
||||
|
||||
@@ -95,6 +105,7 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
mUserId = userId;
|
||||
mLock = lock;
|
||||
mSpooler = new RemotePrintSpooler(context, userId, this);
|
||||
enableSystemPrintServicesOnce();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,7 +201,7 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
public void requestPrinterUpdate(PrinterId printerId) {
|
||||
public void validatePrinters(List<PrinterId> printerIds) {
|
||||
synchronized (mLock) {
|
||||
throwIfDestroyedLocked();
|
||||
// No services - nothing to do.
|
||||
@@ -202,7 +213,39 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
return;
|
||||
}
|
||||
// Request an updated.
|
||||
mPrinterDiscoverySession.requestPrinterUpdateLocked(printerId);
|
||||
mPrinterDiscoverySession.validatePrintersLocked(printerIds);
|
||||
}
|
||||
}
|
||||
|
||||
public void startPrinterStateTracking(PrinterId printerId) {
|
||||
synchronized (mLock) {
|
||||
throwIfDestroyedLocked();
|
||||
// No services - nothing to do.
|
||||
if (mActiveServices.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// No session - nothing to do.
|
||||
if (mPrinterDiscoverySession == null) {
|
||||
return;
|
||||
}
|
||||
// Request start tracking the printer.
|
||||
mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopPrinterStateTracking(PrinterId printerId) {
|
||||
synchronized (mLock) {
|
||||
throwIfDestroyedLocked();
|
||||
// No services - nothing to do.
|
||||
if (mActiveServices.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// No session - nothing to do.
|
||||
if (mPrinterDiscoverySession == null) {
|
||||
return;
|
||||
}
|
||||
// Request stop tracking the printer.
|
||||
mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,6 +408,36 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void enableSystemPrintServicesOnce() {
|
||||
SharedPreferences preferences = mContext.getSharedPreferences(
|
||||
SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE);
|
||||
if (preferences.getInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 0) == 0) {
|
||||
Editor editor = preferences.edit();
|
||||
editor.putInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 1);
|
||||
editor.commit();
|
||||
|
||||
readInstalledPrintServicesLocked();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
final int serviceCount = mInstalledServices.size();
|
||||
for (int i = 0; i < serviceCount; i++) {
|
||||
ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo;
|
||||
if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
||||
ComponentName serviceName = new ComponentName(
|
||||
serviceInfo.packageName, serviceInfo.name);
|
||||
if (builder.length() > 0) {
|
||||
builder.append(":");
|
||||
}
|
||||
builder.append(serviceName.flattenToString());
|
||||
}
|
||||
}
|
||||
|
||||
Settings.Secure.putStringForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.ENABLED_PRINT_SERVICES, builder.toString(), mUserId);
|
||||
}
|
||||
}
|
||||
|
||||
private void onConfigurationChangedLocked() {
|
||||
final int installedCount = mInstalledServices.size();
|
||||
for (int i = 0; i < installedCount; i++) {
|
||||
@@ -415,6 +488,8 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
|
||||
private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>();
|
||||
|
||||
private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
|
||||
|
||||
private final Handler mHandler;
|
||||
|
||||
private boolean mIsDestroyed;
|
||||
@@ -461,14 +536,10 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
}
|
||||
|
||||
// If printer discovery is ongoing and the start request has a list
|
||||
// of printer to be checked, then we just request refreshing each of
|
||||
// them rather making another start discovery request.
|
||||
// of printer to be checked, then we just request validating them.
|
||||
if (!mStartedPrinterDiscoveryTokens.isEmpty()
|
||||
&& priorityList != null && !priorityList.isEmpty()) {
|
||||
final int priorityIdCount = priorityList.size();
|
||||
for (int i = 0; i < priorityIdCount; i++) {
|
||||
requestPrinterUpdate(priorityList.get(i));
|
||||
}
|
||||
validatePrinters(priorityList);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -508,22 +579,99 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
public void requestPrinterUpdateLocked(PrinterId printerId) {
|
||||
public void validatePrintersLocked(List<PrinterId> printerIds) {
|
||||
if (mIsDestroyed) {
|
||||
Log.w(LOG_TAG, "Not updating pritner - session destroyed");
|
||||
Log.w(LOG_TAG, "Not validating pritners - session destroyed");
|
||||
return;
|
||||
}
|
||||
RemotePrintService service = mActiveServices.get(printerId.getServiceName());
|
||||
if (service != null) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = service;
|
||||
args.arg2 = printerId;
|
||||
mHandler.obtainMessage(SessionHandler
|
||||
.MSG_REQUEST_PRINTER_UPDATE, args)
|
||||
.sendToTarget();
|
||||
|
||||
List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds);
|
||||
while (!remainingList.isEmpty()) {
|
||||
Iterator<PrinterId> iterator = remainingList.iterator();
|
||||
// Gather the printers per service and request a validation.
|
||||
List<PrinterId> updateList = new ArrayList<PrinterId>();
|
||||
ComponentName serviceName = null;
|
||||
while (iterator.hasNext()) {
|
||||
PrinterId printerId = iterator.next();
|
||||
if (updateList.isEmpty()) {
|
||||
updateList.add(printerId);
|
||||
serviceName = printerId.getServiceName();
|
||||
iterator.remove();
|
||||
} else if (printerId.getServiceName().equals(serviceName)) {
|
||||
updateList.add(printerId);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
// Schedule a notification of the service.
|
||||
RemotePrintService service = mActiveServices.get(serviceName);
|
||||
if (service != null) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = service;
|
||||
args.arg2 = updateList;
|
||||
mHandler.obtainMessage(SessionHandler
|
||||
.MSG_VALIDATE_PRINTERS, args)
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void startPrinterStateTrackingLocked(PrinterId printerId) {
|
||||
if (mIsDestroyed) {
|
||||
Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
|
||||
return;
|
||||
}
|
||||
// If printer discovery is not started - nothing to do.
|
||||
if (mStartedPrinterDiscoveryTokens.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId);
|
||||
// Keep track of the number of requests to track this one.
|
||||
mStateTrackedPrinters.add(printerId);
|
||||
// If we were tracking this printer - nothing to do.
|
||||
if (containedPrinterId) {
|
||||
return;
|
||||
}
|
||||
// No service - nothing to do.
|
||||
RemotePrintService service = mActiveServices.get(printerId.getServiceName());
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
// Ask the service to start tracking.
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = service;
|
||||
args.arg2 = printerId;
|
||||
mHandler.obtainMessage(SessionHandler
|
||||
.MSG_START_PRINTER_STATE_TRACKING, args)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
public final void stopPrinterStateTrackingLocked(PrinterId printerId) {
|
||||
if (mIsDestroyed) {
|
||||
Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed");
|
||||
return;
|
||||
}
|
||||
// If printer discovery is not started - nothing to do.
|
||||
if (mStartedPrinterDiscoveryTokens.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// If we did not track this printer - nothing to do.
|
||||
if (!mStateTrackedPrinters.remove(printerId)) {
|
||||
return;
|
||||
}
|
||||
// No service - nothing to do.
|
||||
RemotePrintService service = mActiveServices.get(printerId.getServiceName());
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
// Ask the service to start tracking.
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = service;
|
||||
args.arg2 = printerId;
|
||||
mHandler.obtainMessage(SessionHandler
|
||||
.MSG_STOP_PRINTER_STATE_TRACKING, args)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
public void onDestroyed() {
|
||||
/* do nothing */
|
||||
}
|
||||
@@ -533,6 +681,12 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
Log.w(LOG_TAG, "Not destroying - session destroyed");
|
||||
return;
|
||||
}
|
||||
// Make sure printer tracking is stopped.
|
||||
final int printerCount = mStateTrackedPrinters.size();
|
||||
for (int i = 0; i < printerCount; i++) {
|
||||
PrinterId printerId = mStateTrackedPrinters.get(i);
|
||||
stopPrinterStateTracking(printerId);
|
||||
}
|
||||
// Make sure discovery is stopped.
|
||||
final int observerCount = mStartedPrinterDiscoveryTokens.size();
|
||||
for (int i = 0; i < observerCount; i++) {
|
||||
@@ -744,9 +898,19 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRequestPrinterUpdate(RemotePrintService service,
|
||||
private void handleValidatePrinters(RemotePrintService service,
|
||||
List<PrinterId> printerIds) {
|
||||
service.validatePrinters(printerIds);
|
||||
}
|
||||
|
||||
private void handleStartPrinterStateTracking(RemotePrintService service,
|
||||
PrinterId printerId) {
|
||||
service.requestPrinterUpdate(printerId);
|
||||
service.startPrinterStateTracking(printerId);
|
||||
}
|
||||
|
||||
private void handleStopPrinterStateTracking(RemotePrintService service,
|
||||
PrinterId printerId) {
|
||||
service.stopPrinterStateTracking(printerId);
|
||||
}
|
||||
|
||||
private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
|
||||
@@ -804,7 +968,9 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 9;
|
||||
public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 10;
|
||||
public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 11;
|
||||
public static final int MSG_REQUEST_PRINTER_UPDATE = 12;
|
||||
public static final int MSG_VALIDATE_PRINTERS = 12;
|
||||
public static final int MSG_START_PRINTER_STATE_TRACKING = 13;
|
||||
public static final int MSG_STOP_PRINTER_STATE_TRACKING = 14;
|
||||
|
||||
SessionHandler(Looper looper) {
|
||||
super(looper, null, false);
|
||||
@@ -878,13 +1044,29 @@ final class UserState implements PrintSpoolerCallbacks {
|
||||
handleDispatchStopPrinterDiscovery(services);
|
||||
} break;
|
||||
|
||||
case MSG_REQUEST_PRINTER_UPDATE: {
|
||||
case MSG_VALIDATE_PRINTERS: {
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
RemotePrintService service = (RemotePrintService) args.arg1;
|
||||
List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
|
||||
args.recycle();
|
||||
handleValidatePrinters(service, printerIds);
|
||||
} break;
|
||||
|
||||
case MSG_START_PRINTER_STATE_TRACKING: {
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
RemotePrintService service = (RemotePrintService) args.arg1;
|
||||
PrinterId printerId = (PrinterId) args.arg2;
|
||||
args.recycle();
|
||||
handleRequestPrinterUpdate(service, printerId);
|
||||
handleStartPrinterStateTracking(service, printerId);
|
||||
} break;
|
||||
|
||||
case MSG_STOP_PRINTER_STATE_TRACKING: {
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
RemotePrintService service = (RemotePrintService) args.arg1;
|
||||
PrinterId printerId = (PrinterId) args.arg2;
|
||||
args.recycle();
|
||||
handleStopPrinterStateTracking(service, printerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user