summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2013-09-16 17:53:51 -0700
committerSvetoslav <svetoslavganov@google.com>2013-09-16 17:55:14 -0700
commit2fbd2a7f070f246ddafd9de94efa9a98861e9136 (patch)
tree2a918b4226106a2350277ae8fa73a9e2ce79d697
parent3fb53d8238c0ccec275237cf4f4962f2a00eab7e (diff)
downloadframeworks_base-2fbd2a7f070f246ddafd9de94efa9a98861e9136.zip
frameworks_base-2fbd2a7f070f246ddafd9de94efa9a98861e9136.tar.gz
frameworks_base-2fbd2a7f070f246ddafd9de94efa9a98861e9136.tar.bz2
App UI freezes when printing. API clean up.
1. The UI of a printing app was freezing a little when calling the print method since the print manager service was waiting for it to bind to the print spooler which generated the print job id (and the initial print job info really). Now the print manager service is responsible for job id generation and does not not wait for the print spooler to spin. Hence, the app UI is not blocked at all. Note that the print manager initiates the binding to the spooler and as soon as it completes the spooler shows the print UI which is hosted in its process. It is not possible to show the print UI before the system is bound to the spooler since during this binding the system passes a callback to the spooler so the latter can talk to the system. 2. Changed the print job id to be an opaque class allowing us to vary the way we generate print job ids in the future. 3. The queued print job state was hidden but the print job returned by the print method of the print manager is in that state. Now now hidden. 4. We were incorrecly removing print job infos if they are completed or cancelled. Doing that is problematic since the print job returned by the print method allows the app to query for the job info after the job has been say completed. Hence, an app can initiate printing and get a print job whose state is "created" and hold onto it until after the job is completed, now if the app asks for the print job info it will get an info in "created" state even though the job is "completed" since the spooler was not retaining the completed jobs. Now the spooler removes the PDF files for the completed and cancelled print jobs but keeps around the infos (also persisting them to disc) so it can answer questions about them. On first boot or switch to a user we purge the persisted print jobs in completed/cancelled state since they are obsolete - no app can have a handle to them. 5. Removed the print method that takes a file since we have a public PrintDocumentAdapter implementation for printing files. Once can instantiate a PrintFileDocumentAdapter and pass it to the print method. This class also allows overriding of the finish method to know when the data is spooled and deleted the file if desired, etc. 6. Replaced the wrong code to slice a large list of parcelables to use ParceledListSlice class. bug:10748093 Change-Id: I1ebeeb47576e88fce550851cdd3e401fcede6e2b
-rw-r--r--api/current.txt14
-rw-r--r--core/java/android/print/IPrintManager.aidl7
-rw-r--r--core/java/android/print/IPrintSpooler.aidl17
-rw-r--r--core/java/android/print/IPrintSpoolerCallbacks.aidl1
-rw-r--r--core/java/android/print/IPrinterDiscoveryObserver.aidl5
-rw-r--r--core/java/android/print/PrintJob.java15
-rw-r--r--core/java/android/print/PrintJobId.aidl19
-rw-r--r--core/java/android/print/PrintJobId.java122
-rw-r--r--core/java/android/print/PrintJobInfo.java12
-rw-r--r--core/java/android/print/PrintManager.java23
-rw-r--r--core/java/android/print/PrinterDiscoverySession.java11
-rw-r--r--core/java/android/printservice/IPrintServiceClient.aidl14
-rw-r--r--core/java/android/printservice/PrintDocument.java5
-rw-r--r--core/java/android/printservice/PrintJob.java7
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java75
-rw-r--r--packages/PrintSpooler/AndroidManifest.xml2
-rw-r--r--packages/PrintSpooler/res/values/strings.xml14
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/NotificationController.java36
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java15
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java219
-rw-r--r--services/java/com/android/server/print/PrintManagerService.java83
-rw-r--r--services/java/com/android/server/print/RemotePrintService.java26
-rw-r--r--services/java/com/android/server/print/RemotePrintSpooler.java99
-rw-r--r--services/java/com/android/server/print/UserState.java185
24 files changed, 622 insertions, 404 deletions
diff --git a/api/current.txt b/api/current.txt
index a574237..7fc59d8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19174,15 +19174,21 @@ package android.print {
public final class PrintJob {
method public void cancel();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
}
+ public final class PrintJobId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public java.lang.String getLabel();
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
@@ -19194,6 +19200,7 @@ package android.print {
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_CREATED = 1; // 0x1
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
@@ -19201,7 +19208,6 @@ package android.print {
public final class PrintManager {
method public java.util.List<android.print.PrintJob> getPrintJobs();
- method public android.print.PrintJob print(java.lang.String, java.io.File, android.print.PrintDocumentInfo, android.print.PrintAttributes);
method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
}
@@ -19312,7 +19318,7 @@ package android.printservice {
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.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
method public boolean isBlocked();
method public boolean isCancelled();
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index d2ae5e6..4e839c6 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -19,6 +19,7 @@ package android.print;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
+import android.print.PrintJobId;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -31,12 +32,12 @@ import android.printservice.PrintServiceInfo;
*/
interface IPrintManager {
List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
- PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId, int appId, int userId);
PrintJobInfo print(String printJobName, in IPrintClient client,
in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
int appId, int userId);
- void cancelPrintJob(int printJobId, int appId, int userId);
- void restartPrintJob(int printJobId, int appId, int userId);
+ void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
+ void restartPrintJob(in PrintJobId printJobId, int appId, int userId);
List<PrintServiceInfo> getEnabledPrintServices(int userId);
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 0a77dab..291e81f 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -24,6 +24,8 @@ import android.print.IPrintSpoolerClient;
import android.print.IPrintSpoolerCallbacks;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
/**
* Interface for communication with the print spooler service.
@@ -33,17 +35,18 @@ import android.print.PrintAttributes;
* @hide
*/
oneway interface IPrintSpooler {
+ void removeObsoletePrintJobs();
+ void forgetPrintJobs(in List<PrintJobId> printJob);
void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
int state, int appId, int sequence);
- void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
- void createPrintJob(String printJobName, in IPrintClient client,
- in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence);
- void setPrintJobState(int printJobId, int status, String error,
+ void createPrintJob(in PrintJobInfo printJob, in IPrintClient client,
+ in IPrintDocumentAdapter printAdapter);
+ void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
IPrintSpoolerCallbacks callback, int sequence);
- void setPrintJobTag(int printJobId, String tag, IPrintSpoolerCallbacks callback,
+ void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
- void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
void setClient(IPrintSpoolerClient client);
}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 51b5439..45c5332 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -28,7 +28,6 @@ import java.util.List;
*/
oneway interface IPrintSpoolerCallbacks {
void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence);
- void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence);
void onCancelPrintJobResult(boolean canceled, int sequence);
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
index b558011..2be7b6b 100644
--- a/core/java/android/print/IPrinterDiscoveryObserver.aidl
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -18,6 +18,7 @@ package android.print;
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.content.pm.ParceledListSlice;
/**
* Interface for observing discovered printers by a discovery session.
@@ -25,6 +26,6 @@ import android.print.PrinterInfo;
* @hide
*/
oneway interface IPrinterDiscoveryObserver {
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 42bea6d..00ade07 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -22,8 +22,6 @@ package android.print;
*/
public final class PrintJob {
- private final int mId;
-
private final PrintManager mPrintManager;
private PrintJobInfo mCachedInfo;
@@ -31,7 +29,6 @@ public final class PrintJob {
PrintJob(PrintJobInfo info, PrintManager printManager) {
mCachedInfo = info;
mPrintManager = printManager;
- mId = info.getId();
}
/**
@@ -39,8 +36,8 @@ public final class PrintJob {
*
* @return The id.
*/
- public int getId() {
- return mId;
+ public PrintJobId getId() {
+ return mCachedInfo.getId();
}
/**
@@ -57,7 +54,7 @@ public final class PrintJob {
if (isInImmutableState()) {
return mCachedInfo;
}
- PrintJobInfo info = mPrintManager.getPrintJobInfo(mId);
+ PrintJobInfo info = mPrintManager.getPrintJobInfo(mCachedInfo.getId());
if (info != null) {
mCachedInfo = info;
}
@@ -69,7 +66,7 @@ public final class PrintJob {
*/
public void cancel() {
if (!isInImmutableState()) {
- mPrintManager.cancelPrintJob(mId);
+ mPrintManager.cancelPrintJob(mCachedInfo.getId());
}
}
@@ -91,11 +88,11 @@ public final class PrintJob {
return false;
}
PrintJob other = (PrintJob) obj;
- return mId == other.mId;
+ return mCachedInfo.getId().equals(other.mCachedInfo.getId());
}
@Override
public int hashCode() {
- return mId;
+ return mCachedInfo.getId().hashCode();
}
}
diff --git a/core/java/android/print/PrintJobId.aidl b/core/java/android/print/PrintJobId.aidl
new file mode 100644
index 0000000..759f25f
--- /dev/null
+++ b/core/java/android/print/PrintJobId.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+parcelable PrintJobId;
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
new file mode 100644
index 0000000..01550e2
--- /dev/null
+++ b/core/java/android/print/PrintJobId.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.UUID;
+
+/**
+ * This class represents the id of a print job.
+ */
+public final class PrintJobId implements Parcelable {
+ private final String mValue;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
+ public PrintJobId() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param value The internal value.
+ *
+ * @hide
+ */
+ public PrintJobId(String value) {
+ mValue = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrintJobId other = (PrintJobId) obj;
+ if (!TextUtils.equals(mValue, other.mValue)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flattens this id to a string.
+ *
+ * @return The flattened id.
+ *
+ * @hide
+ */
+ public String flattenToString() {
+ return mValue;
+ }
+
+ /**
+ * Unflattens a print job id from a string.
+ *
+ * @string The string.
+ * @return The unflattened id, or null if the string is malformed.
+ *
+ * @hide
+ */
+ public static PrintJobId unflattenFromString(String string) {
+ return new PrintJobId(string);
+ }
+
+ public static final Parcelable.Creator<PrintJobId> CREATOR =
+ new Parcelable.Creator<PrintJobId>() {
+ @Override
+ public PrintJobId createFromParcel(Parcel parcel) {
+ return new PrintJobId(parcel.readString());
+ }
+
+ @Override
+ public PrintJobId[] newArray(int size) {
+ return new PrintJobId[size];
+ }
+ };
+}
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index b919ad6..502a9f2 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -56,8 +56,6 @@ public final class PrintJobInfo implements Parcelable {
* <p>
* Next valid states: {@link #STATE_QUEUED}
* </p>
- *
- * @hide
*/
public static final int STATE_CREATED = 1;
@@ -117,7 +115,7 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_CANCELED = 7;
/** The unique print job id. */
- private int mId;
+ private PrintJobId mId;
/** The human readable print job label. */
private String mLabel;
@@ -178,7 +176,7 @@ public final class PrintJobInfo implements Parcelable {
}
private PrintJobInfo(Parcel parcel) {
- mId = parcel.readInt();
+ mId = parcel.readParcelable(null);
mLabel = parcel.readString();
mPrinterId = parcel.readParcelable(null);
mPrinterName = parcel.readString();
@@ -208,7 +206,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
return mId;
}
@@ -219,7 +217,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public void setId(int id) {
+ public void setId(PrintJobId id) {
this.mId = id;
}
@@ -485,7 +483,7 @@ public final class PrintJobInfo implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(mId);
+ parcel.writeParcelable(mId, flags);
parcel.writeString(mLabel);
parcel.writeParcelable(mPrinterId, flags);
parcel.writeString(mPrinterName);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 10cc771..5429155 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,7 +36,6 @@ import com.android.internal.os.SomeArgs;
import libcore.io.IoUtils;
-import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -114,7 +113,7 @@ public final class PrintManager {
return new PrintManager(mContext, mService, userId, APP_ID_ANY);
}
- PrintJobInfo getPrintJobInfo(int printJobId) {
+ PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
try {
return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -148,7 +147,7 @@ public final class PrintManager {
return Collections.emptyList();
}
- void cancelPrintJob(int printJobId) {
+ void cancelPrintJob(PrintJobId printJobId) {
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -157,24 +156,6 @@ public final class PrintManager {
}
/**
- * Creates a print job for printing a file with default print attributes.
- *
- * @param printJobName A name for the new print job.
- * @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 on success or null on failure.
- *
- * @see PrintJob
- */
- public PrintJob print(String printJobName, File pdfFile, PrintDocumentInfo documentInfo,
- PrintAttributes attributes) {
- PrintFileDocumentAdapter documentAdapter = new PrintFileDocumentAdapter(
- mContext, pdfFile, documentInfo);
- return print(printJobName, documentAdapter, attributes);
- }
-
- /**
* Creates a print job for printing a {@link PrintDocumentAdapter} with default print
* attributes.
*
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 64249b4..c6dbc16 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -17,6 +17,7 @@
package android.print;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -270,20 +271,22 @@ public final class PrinterDiscoverySession {
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersAdded(ParceledListSlice printers) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
- printers).sendToTarget();
+ printers.getList()).sendToTarget();
}
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
- printerIds).sendToTarget();
+ printerIds.getList()).sendToTarget();
}
}
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index ad3c04f..c2dfc30 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -20,6 +20,8 @@ import android.os.ParcelFileDescriptor;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.print.PrintJobId;
+import android.content.pm.ParceledListSlice;
/**
* The top-level interface from a print service to the system.
@@ -28,11 +30,11 @@ import android.print.PrinterInfo;
*/
interface IPrintServiceClient {
List<PrintJobInfo> getPrintJobInfos();
- PrintJobInfo getPrintJobInfo(int printJobId);
- boolean setPrintJobState(int printJobId, int state, String error);
- boolean setPrintJobTag(int printJobId, String tag);
- oneway void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId);
+ boolean setPrintJobState(in PrintJobId printJobId, int state, String error);
+ boolean setPrintJobTag(in PrintJobId printJobId, String tag);
+ oneway void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index 8292cfb..e43f2a8 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -19,6 +19,7 @@ package android.printservice;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.util.Log;
import java.io.IOException;
@@ -35,13 +36,13 @@ public final class PrintDocument {
private static final String LOG_TAG = "PrintDocument";
- private final int mPrintJobId;
+ private final PrintJobId mPrintJobId;
private final IPrintServiceClient mPrintServiceClient;
private final PrintDocumentInfo mInfo;
- PrintDocument(int printJobId, IPrintServiceClient printServiceClient,
+ PrintDocument(PrintJobId printJobId, IPrintServiceClient printServiceClient,
PrintDocumentInfo info) {
mPrintJobId = printJobId;
mPrintServiceClient = printServiceClient;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 4ff7f0c..2fcae6b 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -17,6 +17,7 @@
package android.printservice;
import android.os.RemoteException;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -52,7 +53,7 @@ public final class PrintJob {
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
PrintService.throwIfNotCalledOnMainThread();
return mCachedInfo.getId();
}
@@ -312,12 +313,12 @@ public final class PrintJob {
return false;
}
PrintJob other = (PrintJob) obj;
- return (mCachedInfo.getId() == other.mCachedInfo.getId());
+ return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
}
@Override
public int hashCode() {
- return mCachedInfo.getId();
+ return mCachedInfo.getId().hashCode();
}
private boolean isInImmutableState() {
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index b0bf3da..17cb68f 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
@@ -80,8 +81,6 @@ import java.util.List;
public abstract class PrinterDiscoverySession {
private static final String LOG_TAG = "PrinterDiscoverySession";
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
-
private static int sIdCounter = 0;
private final int mId;
@@ -112,7 +111,11 @@ public abstract class PrinterDiscoverySession {
// If some printers were added in the method that
// created the session, send them over.
if (!mPrinters.isEmpty()) {
- sendAddedPrinters(mObserver, getPrinters());
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(getPrinters()));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
}
@@ -184,7 +187,11 @@ public abstract class PrinterDiscoverySession {
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -203,27 +210,6 @@ public abstract class PrinterDiscoverySession {
}
}
- private static void sendAddedPrinters(IPrintServiceClient observer,
- List<PrinterInfo> printers) {
- try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
- }
- }
-
/**
* Removes added printers. Removing an already removed or never added
* printer has no effect. Removed printers can be added again. You can
@@ -261,7 +247,12 @@ public abstract class PrinterDiscoverySession {
// Send the removed printers, if such.
if (!removedPrinterIds.isEmpty()) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(
+ removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -278,26 +269,6 @@ public abstract class PrinterDiscoverySession {
}
}
- private static void sendRemovedPrinters(IPrintServiceClient observer,
- List<PrinterId> printerIds) {
- try {
- final int printerIdCount = printerIds.size();
- if (printerIdCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- final int transactionCount = (printerIdCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerIdCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending removed printers", re);
- }
- }
-
private void sendOutOfDiscoveryPeriodPrinterChanges() {
// Noting changed since the last discovery period - nothing to do.
if (mLastSentPrinters == null || mLastSentPrinters.isEmpty()) {
@@ -319,7 +290,11 @@ public abstract class PrinterDiscoverySession {
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
// Determine the removed printers.
@@ -335,7 +310,11 @@ public abstract class PrinterDiscoverySession {
// Send the removed printers, if such.
if (removedPrinterIds != null) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
mLastSentPrinters = null;
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 9319025..1e6954e 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -44,7 +44,7 @@
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
<application
- android:allowClearUserData="false"
+ android:allowClearUserData="true"
android:label="@string/app_label"
android:allowBackup= "false"
android:supportsRtl="true">
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 21a4867..543c425 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -139,18 +139,20 @@
<!-- 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>
+ <string name="permlab_accessAllPrintJobs" translatable="false">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>
+ <string name="permdesc_accessAllPrintJobs" translatable="false">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_startPrintServiceConfigActivity">start print service configuration activities</string>
+ <string name="permlab_startPrintServiceConfigActivity" translatable="false">start print
+ service configuration activities</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_startPrintServiceConfigActivity">Allows the holder to start the
- configuration activities of a print service. Should never be needed for normal apps.</string>
+ <string name="permdesc_startPrintServiceConfigActivity" translatable="false">Allows the
+ holder to start the configuration activities of a print service. Should never be needed
+ for normal apps.</string>
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
index 43a751c..829fb06 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -23,13 +23,13 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.print.IPrintManager;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.text.TextUtils;
@@ -40,12 +40,13 @@ import android.util.Log;
* based on print job state transitions.
*/
public class NotificationController {
- public static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG = false;
public static final String LOG_TAG = "NotificationController";
private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
+
private static final String INTENT_EXTRA_PRINTJOB_ID = "INTENT_EXTRA_PRINTJOB_ID";
private static final String INTENT_EXTRA_PRINTJOB_LABEL = "INTENT_EXTRA_PRINTJOB_LABEL";
private static final String INTENT_EXTRA_PRINTER_NAME = "INTENT_EXTRA_PRINTER_NAME";
@@ -61,8 +62,9 @@ public class NotificationController {
public void onPrintJobStateChanged(PrintJobInfo printJob) {
if (DEBUG) {
- Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: " + printJob.getId()
- + " state:" + PrintJobInfo.stateToString(printJob.getState()));
+ Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: "
+ + printJob.getId().flattenToString() + " state:"
+ + PrintJobInfo.stateToString(printJob.getState()));
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
@@ -96,7 +98,7 @@ public class NotificationController {
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createFailedNotification(PrintJobInfo printJob) {
@@ -115,7 +117,7 @@ public class NotificationController {
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createBlockedNotification(PrintJobInfo printJob) {
@@ -132,25 +134,25 @@ public class NotificationController {
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
- private void removeNotification(int printJobId) {
- mNotificationManager.cancel(printJobId);
+ private void removeNotification(PrintJobId printJobId) {
+ mNotificationManager.cancel(printJobId.flattenToString(), 0);
}
private PendingIntent createCancelIntent(PrintJobInfo printJob) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + String.valueOf(printJob.getId()));
+ intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJob.getId());
intent.putExtra(INTENT_EXTRA_PRINTJOB_LABEL, printJob.getLabel());
intent.putExtra(INTENT_EXTRA_PRINTER_NAME, printJob.getPrinterName());
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
- private PendingIntent createRestartIntent(int printJobId) {
+ private PendingIntent createRestartIntent(PrintJobId printJobId) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + String.valueOf(printJobId));
+ intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJobId);
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
@@ -162,17 +164,17 @@ public class NotificationController {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
String printJobLabel = intent.getExtras().getString(INTENT_EXTRA_PRINTJOB_LABEL);
String printerName = intent.getExtras().getString(INTENT_EXTRA_PRINTER_NAME);
handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
} else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
handleRestartPrintJob(context, printJobId);
}
}
- private void handleCancelPrintJob(final Context context, final int printJobId,
+ private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
final String printJobLabel, final String printerName) {
if (DEBUG) {
Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
@@ -190,7 +192,7 @@ public class NotificationController {
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- notificationManager.notify(printJobId, builder.build());
+ notificationManager.notify(printJobId.flattenToString(), 0, builder.build());
// Call into the print manager service off the main thread since
// the print manager service may end up binding to the print spooler
@@ -226,7 +228,7 @@ public class NotificationController {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- private void handleRestartPrintJob(final Context context, final int printJobId) {
+ private void handleRestartPrintJob(final Context context, final PrintJobId printJobId) {
if (DEBUG) {
Log.i(LOG_TAG, "handleRestartPrintJob() printJobId:" + printJobId);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 14f60f1..4333aea 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -47,6 +47,7 @@ import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterCapabilitiesInfo;
@@ -104,8 +105,7 @@ public class PrintJobConfigActivity extends Activity {
private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
public static final String EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
- public static final String EXTRA_PRINT_ATTRIBUTES = "printAttributes";
- public static final String EXTRA_PRINT_JOB_ID = "printJobId";
+ public static final String EXTRA_PRINT_JOB = "printJob";
public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
@@ -163,7 +163,7 @@ public class PrintJobConfigActivity extends Activity {
private Document mDocument;
private PrintController mController;
- private int mPrintJobId;
+ private PrintJobId mPrintJobId;
private IBinder mIPrintDocumentAdapter;
@@ -175,17 +175,18 @@ public class PrintJobConfigActivity extends Activity {
Bundle extras = getIntent().getExtras();
- mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
- if (mPrintJobId < 0) {
- throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+ PrintJobInfo printJob = extras.getParcelable(EXTRA_PRINT_JOB);
+ if (printJob == null) {
+ throw new IllegalArgumentException("printJob cannot be null");
}
+ mPrintJobId = printJob.getId();
mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
if (mIPrintDocumentAdapter == null) {
throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
}
- PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_PRINT_ATTRIBUTES);
+ PrintAttributes attributes = printJob.getAttributes();
if (attributes != null) {
mCurrPrintAttributes.copyFrom(attributes);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 8580fcd..a6353f7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -37,6 +37,7 @@ import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -51,6 +52,8 @@ import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.FastXmlSerializer;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -63,8 +66,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-
/**
* Service for exposing some of the {@link PrintSpooler} functionality to
* another process.
@@ -73,7 +74,7 @@ public final class PrintSpoolerService extends Service {
private static final String LOG_TAG = "PrintSpoolerService";
- private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
+ private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
private static final boolean DEBUG_PERSISTENCE = false;
@@ -91,10 +92,6 @@ public final class PrintSpoolerService extends Service {
private static PrintSpoolerService sInstance;
- private static int sPrintJobIdCounter;
-
- private Intent mStartPrintJobConfigActivityIntent;
-
private IPrintSpoolerClient mClient;
private HandlerCaller mHandlerCaller;
@@ -112,8 +109,6 @@ public final class PrintSpoolerService extends Service {
@Override
public void onCreate() {
super.onCreate();
- mStartPrintJobConfigActivityIntent = new Intent(PrintSpoolerService.this,
- PrintJobConfigActivity.class);
mHandlerCaller = new HandlerCaller(this, getMainLooper(),
new HandlerCallerCallback(), false);
@@ -147,7 +142,7 @@ public final class PrintSpoolerService extends Service {
}
@Override
- public void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
@@ -159,38 +154,28 @@ public final class PrintSpoolerService extends Service {
@SuppressWarnings("deprecation")
@Override
- public void createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter printAdapter, PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence)
- throws RemoteException {
- PrintJobInfo printJob = null;
- try {
- printJob = PrintSpoolerService.this.createPrintJob(
- printJobName, client, attributes, appId);
- if (printJob != null) {
- Intent intent = mStartPrintJobConfigActivityIntent;
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
- printAdapter.asBinder());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB_ID,
- printJob.getId());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_ATTRIBUTES, attributes);
-
- IntentSender sender = PendingIntent.getActivity(
- PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
-
- Message message = mHandlerCaller.obtainMessageOO(
- HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
- client, sender);
- mHandlerCaller.executeOrSendMessage(message);
- }
- } finally {
- callback.onCreatePrintJobResult(printJob, sequence);
- }
+ public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter printAdapter) throws RemoteException {
+ PrintSpoolerService.this.createPrintJob(printJob);
+
+ Intent intent = new Intent(printJob.getId().flattenToString());
+ intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
+ printAdapter.asBinder());
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
+
+ IntentSender sender = PendingIntent.getActivity(
+ PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+
+ Message message = mHandlerCaller.obtainMessageOO(
+ HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
+ client, sender);
+ mHandlerCaller.executeOrSendMessage(message);
}
@Override
- public void setPrintJobState(int printJobId, int state, String error,
+ public void setPrintJobState(PrintJobId printJobId, int state, String error,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -202,7 +187,7 @@ public final class PrintSpoolerService extends Service {
}
@Override
- public void setPrintJobTag(int printJobId, String tag,
+ public void setPrintJobTag(PrintJobId printJobId, String tag,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -213,7 +198,7 @@ public final class PrintSpoolerService extends Service {
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
PrintSpoolerService.this.writePrintJobData(fd, printJobId);
}
@@ -223,6 +208,16 @@ public final class PrintSpoolerService extends Service {
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
+
+ @Override
+ public void removeObsoletePrintJobs() {
+ PrintSpoolerService.this.removeObsoletePrintJobs();
+ }
+
+ @Override
+ public void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ PrintSpoolerService.this.forgetPrintJobs(printJobIds);
+ }
};
}
@@ -351,15 +346,16 @@ public final class PrintSpoolerService extends Service {
private boolean isStateVisibleToUser(int state) {
return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
- || state == PrintJobInfo.STATE_COMPLETED|| state == PrintJobInfo.STATE_CANCELED));
+ || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
+ || state == PrintJobInfo.STATE_BLOCKED));
}
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public PrintJobInfo getPrintJobInfo(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() == printJobId
+ if (printJob.getId().equals(printJobId)
&& (appId == PrintManager.APP_ID_ANY
|| appId == printJob.getAppId())) {
return printJob;
@@ -369,20 +365,9 @@ public final class PrintSpoolerService extends Service {
}
}
- public PrintJobInfo createPrintJob(String label, IPrintClient client,
- PrintAttributes attributes, int appId) {
+ public void createPrintJob(PrintJobInfo printJob) {
synchronized (mLock) {
- final int printJobId = generatePrintJobIdLocked();
- PrintJobInfo printJob = new PrintJobInfo();
- printJob.setId(printJobId);
- printJob.setAppId(appId);
- printJob.setLabel(label);
- printJob.setAttributes(attributes);
- printJob.setState(PrintJobInfo.STATE_CREATED);
-
addPrintJobLocked(printJob);
-
- return printJob;
}
}
@@ -404,8 +389,7 @@ public final class PrintSpoolerService extends Service {
// decide whether to restart the job or just cancel it.
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
getString(R.string.no_connection_to_printer));
- }
- break;
+ } break;
}
}
}
@@ -418,26 +402,7 @@ public final class PrintSpoolerService extends Service {
}
}
- private int generatePrintJobIdLocked() {
- int printJobId = sPrintJobIdCounter++;
- while (isDuplicatePrintJobId(printJobId)) {
- printJobId = sPrintJobIdCounter++;
- }
- return printJobId;
- }
-
- private boolean isDuplicatePrintJobId(int printJobId) {
- final int printJobCount = mPrintJobs.size();
- for (int j = 0; j < printJobCount; j++) {
- PrintJobInfo printJob = mPrintJobs.get(j);
- if (printJob.getId() == printJobId) {
- return true;
- }
- }
- return false;
- }
-
- public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) {
+ public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
final PrintJobInfo printJob;
synchronized (mLock) {
printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
@@ -476,9 +441,9 @@ public final class PrintSpoolerService extends Service {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- public File generateFileForPrintJob(int printJobId) {
+ public File generateFileForPrintJob(PrintJobId printJobId) {
return new File(getFilesDir(), "print_job_"
- + printJobId + "." + PRINT_FILE_EXTENSION);
+ + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
}
private void addPrintJobLocked(PrintJobInfo printJob) {
@@ -488,16 +453,59 @@ public final class PrintSpoolerService extends Service {
}
}
- private void removePrintJobLocked(PrintJobInfo printJob) {
- if (mPrintJobs.remove(printJob)) {
- generateFileForPrintJob(printJob.getId()).delete();
+ private void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ synchronized (mLock) {
+ boolean printJobsRemoved = false;
+ final int removedPrintJobCount = printJobIds.size();
+ for (int i = 0; i < removedPrintJobCount; i++) {
+ PrintJobId removedPrintJobId = printJobIds.get(i);
+ final int printJobCount = mPrintJobs.size();
+ for (int j = printJobCount - 1; j >= 0; j--) {
+ PrintJobInfo printJob = mPrintJobs.get(j);
+ if (removedPrintJobId.equals(printJob.getId())) {
+ mPrintJobs.remove(j);
+ printJobsRemoved = true;
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[FORGOT] " + printJob.getId().flattenToString());
+ }
+ removePrintJobFileLocked(printJob.getId());
+ }
+ }
+ }
+ if (printJobsRemoved) {
+ mPersistanceManager.writeStateLocked();
+ }
+ }
+ }
+
+ private void removeObsoletePrintJobs() {
+ synchronized (mLock) {
+ 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());
+ }
+ }
+ mPersistanceManager.writeStateLocked();
+ }
+ }
+
+ private void removePrintJobFileLocked(PrintJobId printJobId) {
+ File file = generateFileForPrintJob(printJobId);
+ if (file.exists()) {
+ file.delete();
if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[REMOVE] " + printJob);
+ Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId.flattenToString());
}
}
}
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
boolean success = false;
synchronized (mLock) {
@@ -516,7 +524,11 @@ public final class PrintSpoolerService extends Service {
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED:
- removePrintJobLocked(printJob);
+ // Just remove the file but keep the print job info since
+ // the app that created it may be holding onto the PrintJob
+ // instance and query it for its most recent state. We will
+ // remove the info for this job when told so by the system.
+ removePrintJobFileLocked(printJob.getId());
// $fall-through$
case PrintJobInfo.STATE_FAILED: {
@@ -570,6 +582,11 @@ public final class PrintSpoolerService extends Service {
return false;
}
+ private boolean isObsoleteState(int printJobState) {
+ return (isTeminalState(printJobState)
+ || printJobState == PrintJobInfo.STATE_QUEUED);
+ }
+
private boolean isActiveState(int printJobState) {
return printJobState == PrintJobInfo.STATE_CREATED
|| printJobState == PrintJobInfo.STATE_QUEUED
@@ -577,7 +594,12 @@ public final class PrintSpoolerService extends Service {
|| printJobState == PrintJobInfo.STATE_BLOCKED;
}
- public boolean setPrintJobTag(int printJobId, String tag) {
+ private boolean isTeminalState(int printJobState) {
+ return printJobState == PrintJobInfo.STATE_COMPLETED
+ || printJobState == PrintJobInfo.STATE_CANCELED;
+ }
+
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -599,7 +621,7 @@ public final class PrintSpoolerService extends Service {
return false;
}
- public void setPrintJobCopiesNoPersistence(int printJobId, int copies) {
+ public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -608,7 +630,8 @@ public final class PrintSpoolerService extends Service {
}
}
- public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) {
+ public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId,
+ PrintDocumentInfo info) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -617,7 +640,8 @@ public final class PrintSpoolerService extends Service {
}
}
- public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) {
+ public void setPrintJobAttributesNoPersistence(PrintJobId printJobId,
+ PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -626,7 +650,7 @@ public final class PrintSpoolerService extends Service {
}
}
- public void setPrintJobPrinterNoPersistence(int printJobId, PrinterInfo printer) {
+ public void setPrintJobPrinterNoPersistence(PrintJobId printJobId, PrinterInfo printer) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -636,7 +660,7 @@ public final class PrintSpoolerService extends Service {
}
}
- public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) {
+ public void setPrintJobPagesNoPersistence(PrintJobId printJobId, PageRange[] pages) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -759,15 +783,9 @@ public final class PrintSpoolerService extends Service {
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = printJobs.get(j);
- final int state = printJob.getState();
- if (state < PrintJobInfo.STATE_QUEUED
- || state > PrintJobInfo.STATE_CANCELED) {
- continue;
- }
-
serializer.startTag(null, TAG_JOB);
- serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId()));
+ serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
@@ -948,7 +966,8 @@ public final class PrintSpoolerService extends Service {
PrintJobInfo printJob = new PrintJobInfo();
- final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID));
+ PrintJobId printJobId = PrintJobId.unflattenFromString(
+ parser.getAttributeValue(null, ATTR_ID));
printJob.setId(printJobId);
String label = parser.getAttributeValue(null, ATTR_LABEL);
printJob.setLabel(label);
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index c33bfb7..ddc5046 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -33,6 +33,7 @@ import android.print.IPrintDocumentAdapter;
import android.print.IPrintManager;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
@@ -70,30 +71,32 @@ public final class PrintManagerService extends IPrintManager.Stub {
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
+ final UserState userState;
synchronized (mLock) {
- UserState userState = getCurrentUserStateLocked();
+ userState = getCurrentUserStateLocked();
userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
});
}
@Override
- public PrintJobInfo print(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId,
- int userId) {
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.createPrintJob(printJobName, client, documentAdapter,
+ return userState.print(printJobName, client, documentAdapter,
attributes, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -105,95 +108,65 @@ public final class PrintManagerService extends IPrintManager.Stub {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY,
- resolvedAppId);
+ return userState.getPrintJobInfos(resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfo(printJobId, resolvedAppId);
+ return userState.getPrintJobInfo(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void cancelPrintJob(int printJobId, int appId, int userId) {
+ public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = spooler.getPrintJobInfo(printJobId, resolvedAppId);
- if (printJobInfo == null) {
- return;
- }
- if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
- RemotePrintService printService = null;
- synchronized (mLock) {
- printService = userState.getActiveServicesLocked().get(printServiceName);
- }
- if (printService == null) {
- return;
- }
- printService.onRequestCancelPrintJob(printJobInfo);
- } else {
- // If the print job is failed we do not need cooperation
- // from the print service.
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
- }
+ userState.cancelPrintJob(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void restartPrintJob(int printJobId, int appId, int userId) {
+ public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
- final RemotePrintSpooler spooler;
+ final UserState userState;
synchronized (mLock) {
- spooler = getOrCreateUserStateLocked(resolvedUserId).getSpoolerLocked();
+ userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
- if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- return;
- }
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ userState.restartPrintJob(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
-
@Override
public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
@@ -443,6 +416,7 @@ public final class PrintManagerService extends IPrintManager.Stub {
// user changes
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -471,15 +445,24 @@ public final class PrintManagerService extends IPrintManager.Stub {
}
private void switchUser(int newUserId) {
+ UserState userState;
synchronized (mLock) {
if (newUserId == mCurrentUserId) {
return;
}
mCurrentUserId = newUserId;
- UserState userState = getCurrentUserStateLocked();
- userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
+ userState = mUserStates.get(mCurrentUserId);
+ if (userState == null) {
+ userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
+ } else {
+ userState.updateIfNeededLocked();
+ }
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
private void removeUser(int removedUserId) {
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index 8869cbe..a20973e 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -29,6 +30,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -690,7 +692,7 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -705,7 +707,7 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -719,7 +721,7 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public boolean setPrintJobTag(int printJobId, String tag) {
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -733,7 +735,7 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -746,13 +748,15 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersAdded(ParceledListSlice printers) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
+ List<PrinterInfo> addedPrinters = (List<PrinterInfo>) printers.getList();
+ throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, addedPrinters);
final long identity = Binder.clearCallingIdentity();
try {
- service.mCallbacks.onPrintersAdded(printers);
+ service.mCallbacks.onPrintersAdded(addedPrinters);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -760,13 +764,15 @@ final class RemotePrintService implements DeathRecipient {
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsTampered(service.mComponentName, printerIds);
+ List<PrinterId> removedPrinterIds = (List<PrinterId>) printerIds.getList();
+ throwIfPrinterIdsTampered(service.mComponentName, removedPrinterIds);
final long identity = Binder.clearCallingIdentity();
try {
- service.mCallbacks.onPrintersRemoved(printerIds);
+ service.mCallbacks.onPrintersRemoved(removedPrinterIds);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 45469ac..1bde6d7 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -31,20 +31,20 @@ import android.print.IPrintDocumentAdapter;
import android.print.IPrintSpooler;
import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
-import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.util.Slog;
import android.util.TimedRemoteCaller;
-import libcore.io.IoUtils;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.TimeoutException;
+import libcore.io.IoUtils;
+
/**
* This represents the remote print spooler as a local object to the
* PrintManagerSerivce. It is responsible to connecting to the remote
@@ -64,8 +64,6 @@ final class RemotePrintSpooler {
private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
- private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller();
-
private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
@@ -132,16 +130,15 @@ final class RemotePrintSpooler {
return null;
}
- public final PrintJobInfo createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId) {
+ public final void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter documentAdapter) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- return mCreatePrintJobCaller.createPrintJob(getRemoteInstanceLazy(),
- printJobName, client, documentAdapter, attributes, appId);
+ getRemoteInstanceLazy().createPrintJob(printJob, client, documentAdapter);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating print job.", re);
} catch (TimeoutException te) {
@@ -155,10 +152,9 @@ final class RemotePrintSpooler {
mLock.notifyAll();
}
}
- return null;
}
- public final void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -184,7 +180,7 @@ final class RemotePrintSpooler {
}
}
- public final PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -209,7 +205,7 @@ final class RemotePrintSpooler {
return null;
}
- public final boolean setPrintJobState(int printJobId, int state, String error) {
+ public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -234,7 +230,7 @@ final class RemotePrintSpooler {
return false;
}
- public final boolean setPrintJobTag(int printJobId, String tag) {
+ public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -259,19 +255,46 @@ final class RemotePrintSpooler {
return false;
}
- public final void start() {
+ public final void removeObsoletePrintJobs() {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().removeObsoletePrintJobs();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] removeObsoletePrintJobs()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ public final void forgetPrintJobs(List<PrintJobId> printJobIds) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- getRemoteInstanceLazy();
+ getRemoteInstanceLazy().forgetPrintJobs(printJobIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error forgeting print jobs", re);
} catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error starting the spooler.", te);
+ Slog.e(LOG_TAG, "Error forgeting print jobs", te);
} finally {
if (DEBUG) {
- Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] start()");
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] forgetPrintJobs()");
}
synchronized (mLock) {
mCanUnbind = true;
@@ -333,6 +356,9 @@ final class RemotePrintSpooler {
}
private void bindLocked() throws TimeoutException {
+ if (mRemoteInstance != null) {
+ return;
+ }
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
}
@@ -362,6 +388,9 @@ final class RemotePrintSpooler {
}
private void unbindLocked() {
+ if (mRemoteInstance == null) {
+ return;
+ }
while (true) {
if (mCanUnbind) {
if (DEBUG) {
@@ -452,29 +481,6 @@ final class RemotePrintSpooler {
}
}
- private static final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
- private final IPrintSpoolerCallbacks mCallback;
-
- public CreatePrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- onRemoteMethodResult(printJob, sequence);
- }
- };
- }
-
- public PrintJobInfo createPrintJob(IPrintSpooler target, String printJobName,
- IPrintClient client, IPrintDocumentAdapter documentAdapter,
- PrintAttributes attributes, int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.createPrintJob(printJobName, client, documentAdapter, attributes,
- mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
private final IPrintSpoolerCallbacks mCallback;
@@ -488,7 +494,7 @@ final class RemotePrintSpooler {
};
}
- public PrintJobInfo getPrintJobInfo(IPrintSpooler target, int printJobId,
+ public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
int appId) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
@@ -509,7 +515,7 @@ final class RemotePrintSpooler {
};
}
- public boolean setPrintJobState(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
int status, String error) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobState(printJobId, status, error, mCallback, sequence);
@@ -530,7 +536,7 @@ final class RemotePrintSpooler {
};
}
- public boolean setPrintJobTag(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
String tag) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobTag(printJobId, tag, mCallback, sequence);
@@ -551,11 +557,6 @@ final class RemotePrintSpooler {
}
@Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- /* do nothing */
- }
-
- @Override
public void onCancelPrintJobResult(boolean canceled, int sequence) {
/* do nothing */
}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 7a56e6b..fd4a3a4 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -21,17 +21,24 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserManager;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -46,6 +53,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
@@ -56,7 +64,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -68,8 +75,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private static final boolean DEBUG = false;
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
-
private static final char COMPONENT_NAME_SEPARATOR = ':';
private final SimpleStringSplitter mStringColonSplitter =
@@ -87,6 +92,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private final Set<ComponentName> mEnabledServices =
new ArraySet<ComponentName>();
+ private final CreatedPrintJobTracker mCreatedPrintJobTracker =
+ new CreatedPrintJobTracker();
+
private final Object mLock;
private final Context mContext;
@@ -134,6 +142,79 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
+ public void removeObsoletePrintJobs() {
+ mSpooler.removeObsoletePrintJobs();
+ }
+
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId) {
+ PrintJobId printJobId = new PrintJobId();
+
+ // Track this job so we can forget it when the creator dies.
+ if (!mCreatedPrintJobTracker.onPrintJobCreatedLocked(client.asBinder(), printJobId)) {
+ // Not adding a print job means the client is dead - done.
+ return null;
+ }
+
+ // Create print job place holder.
+ final PrintJobInfo printJob = new PrintJobInfo();
+ printJob.setId(printJobId);
+ printJob.setAppId(appId);
+ printJob.setLabel(printJobName);
+ printJob.setAttributes(attributes);
+ printJob.setState(PrintJobInfo.STATE_CREATED);
+
+ // Spin the spooler to add the job and show the config UI.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ mSpooler.createPrintJob(printJob, client, documentAdapter);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+
+ return printJob;
+ }
+
+ public List<PrintJobInfo> getPrintJobInfos(int appId) {
+ return mSpooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, appId);
+ }
+
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ return mSpooler.getPrintJobInfo(printJobId, appId);
+ }
+
+ public void cancelPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null) {
+ return;
+ }
+ if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
+ RemotePrintService printService = null;
+ synchronized (mLock) {
+ printService = mActiveServices.get(printServiceName);
+ }
+ if (printService == null) {
+ return;
+ }
+ printService.onRequestCancelPrintJob(printJobInfo);
+ } else {
+ // If the print job is failed we do not need cooperation
+ // from the print service.
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
+ }
+ }
+
+ public void restartPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ return;
+ }
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ }
+
public List<PrintServiceInfo> getEnabledPrintServices() {
synchronized (mLock) {
List<PrintServiceInfo> enabledServices = null;
@@ -328,18 +409,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public RemotePrintSpooler getSpoolerLocked() {
- throwIfDestroyedLocked();
- return mSpooler;
- }
-
- public Map<ComponentName, RemotePrintService> getActiveServicesLocked() {
- synchronized(mLock) {
- throwIfDestroyedLocked();
- return mActiveServices;
- }
- }
-
public Set<ComponentName> getEnabledServices() {
synchronized(mLock) {
throwIfDestroyedLocked();
@@ -593,13 +662,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
// just died. Do this off the main thread since we do to allow
// calls into the spooler on the main thread.
if (Looper.getMainLooper().isCurrentThread()) {
- new AsyncTask<Void, Void, Void>() {
+ BackgroundThread.getHandler().post(new Runnable() {
@Override
- protected Void doInBackground(Void... params) {
+ public void run() {
failActivePrintJobsForServiceInternal(serviceName);
- return null;
}
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ });
} else {
failActivePrintJobsForServiceInternal(serviceName);
}
@@ -1088,19 +1156,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
List<PrinterInfo> printers) {
try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
+ observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers));
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error sending added printers", re);
}
@@ -1109,21 +1165,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
List<PrinterId> printerIds) {
try {
- final int printerCount = printerIds.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
+ observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds));
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
+ Log.e(LOG_TAG, "Error sending removed printers", re);
}
}
@@ -1255,4 +1299,51 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
}
-} \ No newline at end of file
+
+ private final class CreatedPrintJobTracker {
+ private final ArrayMap<IBinder, List<PrintJobId>> mCreatedPrintJobs =
+ new ArrayMap<IBinder, List<PrintJobId>>();
+
+ public boolean onPrintJobCreatedLocked(final IBinder creator, PrintJobId printJobId) {
+ try {
+ creator.linkToDeath(new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ creator.unlinkToDeath(this, 0);
+ UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ // If the death is a result of the user being removed, then
+ // do nothing since the spooler data for this user will be
+ // wiped and we cannot bind to the spooler at this point.
+ if (userManager.getUserInfo(mUserId) == null) {
+ return;
+ }
+ List<PrintJobId> printJobIds = null;
+ synchronized (mLock) {
+ printJobIds = mCreatedPrintJobs.remove(creator);
+ if (printJobIds == null) {
+ return;
+ }
+ printJobIds = new ArrayList<PrintJobId>(printJobIds);
+ }
+ if (printJobIds != null) {
+ mSpooler.forgetPrintJobs(printJobIds);
+ }
+ }
+ }, 0);
+ } catch (RemoteException re) {
+ /* The process is already dead - we just failed. */
+ return false;
+ }
+ synchronized (mLock) {
+ List<PrintJobId> printJobIds = mCreatedPrintJobs.get(creator);
+ if (printJobIds == null) {
+ printJobIds = new ArrayList<PrintJobId>();
+ mCreatedPrintJobs.put(creator, printJobIds);
+ }
+ printJobIds.add(printJobId);
+ }
+ return true;
+ }
+ }
+}