diff options
| author | 2013-10-10 17:10:59 +0000 | |
|---|---|---|
| committer | 2013-10-10 17:10:59 +0000 | |
| commit | 0ea16e9e763b5815707971f503d5408dc1b66c10 (patch) | |
| tree | 9de82aacbaa54a00b982792d733884033ffac23b | |
| parent | 94ba89763e2bd660662fbcf293968d3e8423ef68 (diff) | |
| parent | a18661d5922e5ae24ccce8e815aeba437a2fba82 (diff) | |
Merge "Coalescing multiple print job notifications." into klp-dev
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; |