summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Svetoslav Ganov <svetoslavganov@google.com> 2013-10-10 17:10:59 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2013-10-10 17:10:59 +0000
commit0ea16e9e763b5815707971f503d5408dc1b66c10 (patch)
tree9de82aacbaa54a00b982792d733884033ffac23b
parent94ba89763e2bd660662fbcf293968d3e8423ef68 (diff)
parenta18661d5922e5ae24ccce8e815aeba437a2fba82 (diff)
Merge "Coalescing multiple print job notifications." into klp-dev
-rw-r--r--core/java/android/print/IPrintSpooler.aidl1
-rw-r--r--core/java/android/print/PrintJobInfo.java29
-rw-r--r--core/java/android/print/PrintManager.java110
-rw-r--r--packages/PrintSpooler/res/values/strings.xml6
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/NotificationController.java212
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java40
-rw-r--r--services/java/com/android/server/print/RemotePrintSpooler.java25
-rw-r--r--services/java/com/android/server/print/UserState.java4
8 files changed, 335 insertions, 92 deletions
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 96b168d3908a..5f06b834ade1 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -48,4 +48,5 @@ oneway interface IPrintSpooler {
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
void setClient(IPrintSpoolerClient client);
+ void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling);
}
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index ccb4f440df05..92bda4042c92 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -153,6 +153,9 @@ public final class PrintJobInfo implements Parcelable {
/** Information about the printed document. */
private PrintDocumentInfo mDocumentInfo;
+ /** Whether we are trying to cancel this print job. */
+ private boolean mCanceling;
+
/** @hide*/
public PrintJobInfo() {
/* do nothing */
@@ -174,6 +177,7 @@ public final class PrintJobInfo implements Parcelable {
mPageRanges = other.mPageRanges;
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
+ mCanceling = other.mCanceling;
}
private PrintJobInfo(Parcel parcel) {
@@ -201,6 +205,7 @@ public final class PrintJobInfo implements Parcelable {
if (parcel.readInt() == 1) {
mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel);
}
+ mCanceling = (parcel.readInt() == 1);
}
/**
@@ -503,6 +508,28 @@ public final class PrintJobInfo implements Parcelable {
mDocumentInfo = info;
}
+ /**
+ * Gets whether this print is being cancelled.
+ *
+ * @return True if the print job is being cancelled.
+ *
+ * @hide
+ */
+ public boolean isCancelling() {
+ return mCanceling;
+ }
+
+ /**
+ * Sets whether this print is being cancelled.
+ *
+ * @param cancelling True if the print job is being cancelled.
+ *
+ * @hide
+ */
+ public void setCancelling(boolean cancelling) {
+ mCanceling = cancelling;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -539,6 +566,7 @@ public final class PrintJobInfo implements Parcelable {
} else {
parcel.writeInt(0);
}
+ parcel.writeInt(mCanceling ? 1 : 0);
}
@Override
@@ -556,6 +584,7 @@ public final class PrintJobInfo implements Parcelable {
? mAttributes.toString() : null));
builder.append(", documentInfo: " + (mDocumentInfo != null
? mDocumentInfo.toString() : null));
+ builder.append(", cancelling: " + mCanceling);
builder.append(", pages: " + (mPageRanges != null
? Arrays.toString(mPageRanges) : null));
builder.append("}");
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 9c7c1feb474f..1cb4e8d6e651 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -48,6 +48,7 @@ import java.util.Map;
* <p>
* To obtain a handle to the print manager do the following:
* </p>
+ *
* <pre>
* PrintManager printManager =
* (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
@@ -59,6 +60,9 @@ public final class PrintManager {
private static final boolean DEBUG = false;
+ private static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 1;
+ private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 2;
+
/** @hide */
public static final int APP_ID_ANY = -2;
@@ -81,18 +85,17 @@ public final class PrintManager {
/**
* Callback notifying that a print job state changed.
- *
+ *
* @param printJobId The print job id.
*/
- public void onPrintJobsStateChanged(PrintJobId printJobId);
+ public void onPrintJobStateChanged(PrintJobId printJobId);
}
/**
* Creates a new instance.
- *
+ *
* @param context The current context in which to operate.
* @param service The backing system service.
- *
* @hide
*/
public PrintManager(Context context, IPrintManager service, int userId, int appId) {
@@ -104,14 +107,29 @@ public final class PrintManager {
mHandler = new Handler(context.getMainLooper(), null, false) {
@Override
public void handleMessage(Message message) {
- SomeArgs args = (SomeArgs) message.obj;
- Context context = (Context) args.arg1;
- IntentSender intent = (IntentSender) args.arg2;
- args.recycle();
- try {
- context.startIntentSender(intent, null, 0, 0, 0);
- } catch (SendIntentException sie) {
- Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
+ switch (message.what) {
+ case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: {
+ SomeArgs args = (SomeArgs) message.obj;
+ Context context = (Context) args.arg1;
+ IntentSender intent = (IntentSender) args.arg2;
+ args.recycle();
+ try {
+ context.startIntentSender(intent, null, 0, 0, 0);
+ } catch (SendIntentException sie) {
+ Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
+ }
+ }
+ break;
+
+ case MSG_NOTIFY_PRINT_JOB_STATE_CHANGED: {
+ SomeArgs args = (SomeArgs) message.obj;
+ PrintJobStateChangeListener listener =
+ (PrintJobStateChangeListener) args.arg1;
+ PrintJobId printJobId = (PrintJobId) args.arg2;
+ args.recycle();
+ listener.onPrintJobStateChanged(printJobId);
+ }
+ break;
}
}
};
@@ -119,10 +137,10 @@ public final class PrintManager {
/**
* Creates an instance that can access all print jobs.
- *
+ *
* @param userId The user id for which to get all print jobs.
- * @return An instance if the caller has the permission to access
- * all print jobs, null otherwise.
+ * @return An instance if the caller has the permission to access all print
+ * jobs, null otherwise.
* @hide
*/
public PrintManager getGlobalPrintManagerForUser(int userId) {
@@ -140,9 +158,8 @@ public final class PrintManager {
/**
* Adds a listener for observing the state of print jobs.
- *
+ *
* @param listener The listener to add.
- *
* @hide
*/
public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
@@ -151,7 +168,7 @@ public final class PrintManager {
PrintJobStateChangeListenerWrapper>();
}
PrintJobStateChangeListenerWrapper wrappedListener =
- new PrintJobStateChangeListenerWrapper(listener);
+ new PrintJobStateChangeListenerWrapper(listener, mHandler);
try {
mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId);
mPrintJobStateChangeListeners.put(listener, wrappedListener);
@@ -162,9 +179,8 @@ public final class PrintManager {
/**
* Removes a listener for observing the state of print jobs.
- *
+ *
* @param listener The listener to remove.
- *
* @hide
*/
public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
@@ -188,11 +204,9 @@ public final class PrintManager {
/**
* Gets a print job given its id.
- *
+ *
* @return The print job list.
- *
* @see PrintJob
- *
* @hide
*/
public PrintJob getPrintJob(PrintJobId printJobId) {
@@ -209,9 +223,8 @@ public final class PrintManager {
/**
* Gets the print jobs for this application.
- *
+ *
* @return The print job list.
- *
* @see PrintJob
*/
public List<PrintJob> getPrintJobs() {
@@ -249,9 +262,9 @@ public final class PrintManager {
}
/**
- * Creates a print job for printing a {@link PrintDocumentAdapter} with default print
- * attributes.
- *
+ * Creates a print job for printing a {@link PrintDocumentAdapter} with
+ * default print attributes.
+ *
* @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.
@@ -279,9 +292,8 @@ public final class PrintManager {
/**
* Gets the list of enabled print services.
- *
+ *
* @return The enabled service list or an empty list.
- *
* @hide
*/
public List<PrintServiceInfo> getEnabledPrintServices() {
@@ -298,9 +310,8 @@ public final class PrintManager {
/**
* Gets the list of installed print services.
- *
+ *
* @return The installed service list or an empty list.
- *
* @hide
*/
public List<PrintServiceInfo> getInstalledPrintServices() {
@@ -337,7 +348,8 @@ public final class PrintManager {
SomeArgs args = SomeArgs.obtain();
args.arg1 = manager.mContext;
args.arg2 = intent;
- manager.mHandler.obtainMessage(0, args).sendToTarget();
+ manager.mHandler.obtainMessage(MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
+ args).sendToTarget();
}
}
}
@@ -348,7 +360,8 @@ public final class PrintManager {
private CancellationSignal mLayoutOrWriteCancellation;
- private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish()
+ private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK -
+ // cleared in finish()
private Handler mHandler; // Strong reference OK - cleared in finish()
@@ -537,7 +550,8 @@ public final class PrintManager {
switch (message.what) {
case MSG_START: {
mDocumentAdapter.onStart();
- } break;
+ }
+ break;
case MSG_LAYOUT: {
final CancellationSignal cancellation;
@@ -559,14 +573,15 @@ public final class PrintManager {
new MyLayoutResultCallback(layoutSpec.callback,
layoutSpec.sequence), layoutSpec.metadata);
}
- } break;
+ }
+ break;
case MSG_WRITE: {
final CancellationSignal cancellation;
final WriteSpec writeSpec;
synchronized (mLock) {
- writeSpec= mLastWriteSpec;
+ writeSpec = mLastWriteSpec;
mLastWriteSpec = null;
cancellation = new CancellationSignal();
mLayoutOrWriteCancellation = cancellation;
@@ -580,7 +595,8 @@ public final class PrintManager {
cancellation, new MyWriteResultCallback(writeSpec.callback,
writeSpec.fd, writeSpec.sequence));
}
- } break;
+ }
+ break;
case MSG_FINISH: {
if (DEBUG) {
@@ -588,7 +604,8 @@ public final class PrintManager {
}
mDocumentAdapter.onFinish();
doFinish();
- } break;
+ }
+ break;
default: {
throw new IllegalArgumentException("Unknown message: "
@@ -727,17 +744,26 @@ public final class PrintManager {
private static final class PrintJobStateChangeListenerWrapper extends
IPrintJobStateChangeListener.Stub {
private final WeakReference<PrintJobStateChangeListener> mWeakListener;
+ private final WeakReference<Handler> mWeakHandler;
- public PrintJobStateChangeListenerWrapper(PrintJobStateChangeListener listener) {
+ public PrintJobStateChangeListenerWrapper(PrintJobStateChangeListener listener,
+ Handler handler) {
mWeakListener = new WeakReference<PrintJobStateChangeListener>(listener);
+ mWeakHandler = new WeakReference<Handler>(handler);
}
@Override
public void onPrintJobStateChanged(PrintJobId printJobId) {
+ Handler handler = mWeakHandler.get();
PrintJobStateChangeListener listener = mWeakListener.get();
- if (listener != null) {
- listener.onPrintJobsStateChanged(printJobId);
+ if (handler != null && listener != null) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = listener;
+ args.arg2 = printJobId;
+ handler.obtainMessage(MSG_NOTIFY_PRINT_JOB_STATE_CHANGED,
+ args).sendToTarget();
}
}
}
+
}
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index c82a20ee3497..67c455d730f3 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -121,6 +121,12 @@
<!-- 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>
+ <!-- Template for the notificaiton label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] -->
+ <plurals name="composite_notification_title_template">
+ <item quantity="one"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print job</item>
+ <item quantity="other"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print jobs</item>
+ </plurals>
+
<!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] -->
<string name="cancel">Cancel</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
index 2bd0443dd9e8..4aa86863b4b2 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -17,11 +17,14 @@
package com.android.printspooler;
import android.app.Notification;
+import android.app.Notification.InboxStyle;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -35,6 +38,9 @@ import android.print.PrintManager;
import android.provider.Settings;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This class is responsible for updating the print notifications
* based on print job state transitions.
@@ -60,29 +66,50 @@ public class NotificationController {
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
- public void onPrintJobStateChanged(PrintJobInfo printJob) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: "
- + printJob.getId().flattenToString() + " state:"
- + PrintJobInfo.stateToString(printJob.getState()));
+ public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
+ List<PrintJobInfo> notifyPrintJobs = new ArrayList<PrintJobInfo>();
+
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ if (shouldNotifyForState(printJob.getState())) {
+ notifyPrintJobs.add(printJob);
+ }
}
- switch (printJob.getState()) {
- case PrintJobInfo.STATE_QUEUED:
- case PrintJobInfo.STATE_STARTED: {
- createPrintingNotification(printJob);
- } break;
+ updateNotification(notifyPrintJobs);
+ }
+
+ private void updateNotification(List<PrintJobInfo> printJobs) {
+ if (printJobs.size() <= 0) {
+ removeNotification();
+ } else if (printJobs.size() == 1) {
+ createSimpleNotification(printJobs.get(0));
+ } else {
+ createStackedNotification(printJobs);
+ }
+ }
+
+ private void createSimpleNotification(PrintJobInfo printJob) {
+ switch (printJob.getState()) {
case PrintJobInfo.STATE_FAILED: {
createFailedNotification(printJob);
} break;
- case PrintJobInfo.STATE_COMPLETED:
- case PrintJobInfo.STATE_CANCELED: {
- removeNotification(printJob.getId());
+ case PrintJobInfo.STATE_BLOCKED: {
+ if (!printJob.isCancelling()) {
+ createBlockedNotification(printJob);
+ } else {
+ createCancellingNotification(printJob);
+ }
} break;
- case PrintJobInfo.STATE_BLOCKED: {
- createBlockedNotification(printJob);
+ default: {
+ if (!printJob.isCancelling()) {
+ createPrintingNotification(printJob);
+ } else {
+ createCancellingNotification(printJob);
+ }
} break;
}
}
@@ -90,24 +117,22 @@ public class NotificationController {
private void createPrintingNotification(PrintJobInfo printJob) {
Notification.Builder builder = new Notification.Builder(mContext)
.setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(com.android.internal.R.drawable.ic_print)
- .setContentTitle(mContext.getString(R.string.printing_notification_title_template,
- printJob.getLabel()))
+ .setSmallIcon(computeNotificationIcon(printJob))
+ .setContentTitle(computeNotificationTitle(printJob))
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
createCancelIntent(printJob))
.setContentText(printJob.getPrinterName())
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+ mNotificationManager.notify(0, builder.build());
}
private void createFailedNotification(PrintJobInfo printJob) {
Notification.Builder builder = new Notification.Builder(mContext)
.setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
- .setContentTitle(mContext.getString(R.string.failed_notification_title_template,
- printJob.getLabel()))
+ .setSmallIcon(computeNotificationIcon(printJob))
+ .setContentTitle(computeNotificationTitle(printJob))
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
createCancelIntent(printJob))
.addAction(R.drawable.ic_restart, mContext.getString(R.string.restart),
@@ -116,32 +141,109 @@ public class NotificationController {
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+ mNotificationManager.notify(0, builder.build());
}
private void createBlockedNotification(PrintJobInfo printJob) {
Notification.Builder builder = new Notification.Builder(mContext)
.setContentIntent(createContentIntent(printJob.getId()))
- .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
- .setContentTitle(mContext.getString(R.string.blocked_notification_title_template,
- printJob.getLabel()))
+ .setSmallIcon(computeNotificationIcon(printJob))
+ .setContentTitle(computeNotificationTitle(printJob))
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
createCancelIntent(printJob))
.setContentText(printJob.getPrinterName())
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
+ mNotificationManager.notify(0, builder.build());
}
- private void removeNotification(PrintJobId printJobId) {
- mNotificationManager.cancel(printJobId.flattenToString(), 0);
+ private void createCancellingNotification(PrintJobInfo printJob) {
+ Notification.Builder builder = new Notification.Builder(mContext)
+ .setContentIntent(createContentIntent(printJob.getId()))
+ .setSmallIcon(computeNotificationIcon(printJob))
+ .setContentTitle(computeNotificationTitle(printJob))
+ .setContentText(printJob.getPrinterName())
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setShowWhen(true);
+ mNotificationManager.notify(0, builder.build());
+ }
+
+ private void createStackedNotification(List<PrintJobInfo> printJobs) {
+ Notification.Builder builder = new Notification.Builder(mContext)
+ .setContentIntent(createContentIntent(null))
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setShowWhen(true);
+
+ final int printJobCount = printJobs.size();
+
+ InboxStyle inboxStyle = new InboxStyle();
+ inboxStyle.setBigContentTitle(String.format(mContext.getResources().getQuantityText(
+ R.plurals.composite_notification_title_template,
+ printJobCount).toString(), printJobCount));
+
+ for (int i = printJobCount - 1; i>= 0; i--) {
+ PrintJobInfo printJob = printJobs.get(i);
+ if (i == printJobCount - 1) {
+ builder.setLargeIcon(((BitmapDrawable) mContext.getResources().getDrawable(
+ computeNotificationIcon(printJob))).getBitmap());
+ builder.setSmallIcon(com.android.internal.R.drawable.ic_print);
+ builder.setContentTitle(computeNotificationTitle(printJob));
+ builder.setContentText(printJob.getPrinterName());
+ }
+ inboxStyle.addLine(computeNotificationTitle(printJob));
+ }
+
+ builder.setNumber(printJobCount);
+ builder.setStyle(inboxStyle);
+
+ mNotificationManager.notify(0, builder.build());
+ }
+
+ private String computeNotificationTitle(PrintJobInfo printJob) {
+ switch (printJob.getState()) {
+ case PrintJobInfo.STATE_FAILED: {
+ return mContext.getString(R.string.failed_notification_title_template,
+ printJob.getLabel());
+ }
+
+ case PrintJobInfo.STATE_BLOCKED: {
+ if (!printJob.isCancelling()) {
+ return mContext.getString(R.string.blocked_notification_title_template,
+ printJob.getLabel());
+ } else {
+ return mContext.getString(
+ R.string.cancelling_notification_title_template,
+ printJob.getLabel());
+ }
+ }
+
+ default: {
+ if (!printJob.isCancelling()) {
+ return mContext.getString(R.string.printing_notification_title_template,
+ printJob.getLabel());
+ } else {
+ return mContext.getString(
+ R.string.cancelling_notification_title_template,
+ printJob.getLabel());
+ }
+ }
+ }
+ }
+
+ private void removeNotification() {
+ mNotificationManager.cancel(0);
}
private PendingIntent createContentIntent(PrintJobId printJobId) {
Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
- intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString());
- return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+ if (printJobId != null) {
+ intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString());
+ intent.setData(Uri.fromParts("printjob", printJobId.flattenToString(), null));
+ }
+ return PendingIntent.getActivity(mContext, 0, intent, 0);
}
private PendingIntent createCancelIntent(PrintJobInfo printJob) {
@@ -160,6 +262,36 @@ public class NotificationController {
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
+ private static boolean shouldNotifyForState(int state) {
+ switch (state) {
+ case PrintJobInfo.STATE_QUEUED:
+ case PrintJobInfo.STATE_STARTED:
+ case PrintJobInfo.STATE_FAILED:
+ case PrintJobInfo.STATE_COMPLETED:
+ case PrintJobInfo.STATE_CANCELED:
+ case PrintJobInfo.STATE_BLOCKED: {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int computeNotificationIcon(PrintJobInfo printJob) {
+ switch (printJob.getState()) {
+ case PrintJobInfo.STATE_FAILED:
+ case PrintJobInfo.STATE_BLOCKED: {
+ return com.android.internal.R.drawable.ic_print_error;
+ }
+ default: {
+ if (!printJob.isCancelling()) {
+ return com.android.internal.R.drawable.ic_print;
+ } else {
+ return R.drawable.stat_notify_cancelling;
+ }
+ }
+ }
+ }
+
public static final class NotificationBroadcastReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "NotificationBroadcastReceiver";
@@ -183,20 +315,6 @@ public class NotificationController {
Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
}
- // Put up a notification that we are trying to cancel.
- NotificationManager notificationManager = (NotificationManager)
- context.getSystemService(Context.NOTIFICATION_SERVICE);
- Notification.Builder builder = new Notification.Builder(context)
- .setSmallIcon(R.drawable.stat_notify_cancelling)
- .setContentTitle(context.getString(
- R.string.cancelling_notification_title_template,
- printJobLabel))
- .setContentText(printerName)
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true);
- 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
// service which binding is handled on the main thread.
@@ -217,8 +335,8 @@ public class NotificationController {
// done on another thread and until it finishes the spooler has
// to be kept around.
try {
- IPrintManager printManager = IPrintManager.Stub.asInterface(
- ServiceManager.getService(Context.PRINT_SERVICE));
+ IPrintManager printManager = IPrintManager.Stub.asInterface(
+ ServiceManager.getService(Context.PRINT_SERVICE));
printManager.cancelPrintJob(printJobId, PrintManager.APP_ID_ANY,
UserHandle.myUserId());
} catch (RemoteException re) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index d1b42bccc5fb..e1ddb4011fab 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -230,6 +230,11 @@ public final class PrintSpoolerService extends Service {
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
PrintSpoolerService.this.dump(fd, writer, args);
}
+
+ @Override
+ public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
+ PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
+ }
};
}
@@ -459,8 +464,6 @@ public final class PrintSpoolerService extends Service {
fileForJobMap.remove(printJob.getId());
}
- // Update the notification.
- mNotificationController.onPrintJobStateChanged(printJob);
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED:
@@ -475,6 +478,11 @@ public final class PrintSpoolerService extends Service {
}
}
+ if (!mPrintJobs.isEmpty()) {
+ // Update the notification.
+ mNotificationController.onUpdateNotifications(mPrintJobs);
+ }
+
// Delete the orphan files.
if (fileForJobMap != null) {
final int orphanFileCount = fileForJobMap.size();
@@ -586,7 +594,7 @@ public final class PrintSpoolerService extends Service {
printJob.setState(state);
printJob.setStateReason(error);
- mNotificationController.onPrintJobStateChanged(printJob);
+ printJob.setCancelling(false);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
@@ -626,6 +634,8 @@ public final class PrintSpoolerService extends Service {
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
+
+ mNotificationController.onUpdateNotifications(mPrintJobs);
}
}
@@ -694,6 +704,24 @@ public final class PrintSpoolerService extends Service {
return false;
}
+ public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
+ synchronized (mLock) {
+ PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+ if (printJob != null) {
+ printJob.setCancelling(cancelling);
+ if (shouldPersistPrintJob(printJob)) {
+ mPersistanceManager.writeStateLocked();
+ }
+ mNotificationController.onUpdateNotifications(mPrintJobs);
+
+ Message message = mHandlerCaller.obtainMessageO(
+ HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
+ printJob);
+ mHandlerCaller.executeOrSendMessage(message);
+ }
+ }
+ }
+
public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
@@ -783,6 +811,7 @@ public final class PrintSpoolerService extends Service {
private static final String ATTR_COPIES = "copies";
private static final String ATTR_PRINTER_NAME = "printerName";
private static final String ATTR_STATE_REASON = "stateReason";
+ private static final String ATTR_CANCELLING = "cancelling";
private static final String TAG_MEDIA_SIZE = "mediaSize";
private static final String TAG_RESOLUTION = "resolution";
@@ -881,6 +910,8 @@ public final class PrintSpoolerService extends Service {
if (!TextUtils.isEmpty(stateReason)) {
serializer.attribute(null, ATTR_STATE_REASON, stateReason);
}
+ serializer.attribute(null, ATTR_CANCELLING, String.valueOf(
+ printJob.isCancelling()));
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
@@ -1073,6 +1104,9 @@ public final class PrintSpoolerService extends Service {
printJob.setPrinterName(printerName);
String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
printJob.setStateReason(stateReason);
+ String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
+ printJob.setCancelling(!TextUtils.isEmpty(cancelling)
+ ? Boolean.parseBoolean(cancelling) : false);
parser.next();
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 798cea36caaf..4866f5792c38 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -255,6 +255,31 @@ final class RemotePrintSpooler {
return false;
}
+ public final void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().setPrintJobCancelling(printJobId,
+ cancelling);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error setting print job cancelling.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error setting print job cancelling.", te);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] setPrintJobCancelling()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
public final void removeObsoletePrintJobs() {
throwIfCalledOnMainThread();
synchronized (mLock) {
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index b3f003639c1b..b6c7853c1f01 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -240,6 +240,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
if (printJobInfo == null) {
return;
}
+
+ // Take a note that we are trying to cancel the job.
+ mSpooler.setPrintJobCancelling(printJobId, true);
+
if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
RemotePrintService printService = null;