Loading core/java/android/print/IPrintSpooler.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -48,4 +48,5 @@ oneway interface IPrintSpooler { int sequence); int sequence); void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId); void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId); void setClient(IPrintSpoolerClient client); void setClient(IPrintSpoolerClient client); void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling); } } core/java/android/print/PrintJobInfo.java +29 −0 Original line number Original line Diff line number Diff line Loading @@ -153,6 +153,9 @@ public final class PrintJobInfo implements Parcelable { /** Information about the printed document. */ /** Information about the printed document. */ private PrintDocumentInfo mDocumentInfo; private PrintDocumentInfo mDocumentInfo; /** Whether we are trying to cancel this print job. */ private boolean mCanceling; /** @hide*/ /** @hide*/ public PrintJobInfo() { public PrintJobInfo() { /* do nothing */ /* do nothing */ Loading @@ -174,6 +177,7 @@ public final class PrintJobInfo implements Parcelable { mPageRanges = other.mPageRanges; mPageRanges = other.mPageRanges; mAttributes = other.mAttributes; mAttributes = other.mAttributes; mDocumentInfo = other.mDocumentInfo; mDocumentInfo = other.mDocumentInfo; mCanceling = other.mCanceling; } } private PrintJobInfo(Parcel parcel) { private PrintJobInfo(Parcel parcel) { Loading Loading @@ -201,6 +205,7 @@ public final class PrintJobInfo implements Parcelable { if (parcel.readInt() == 1) { if (parcel.readInt() == 1) { mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); } } mCanceling = (parcel.readInt() == 1); } } /** /** Loading Loading @@ -503,6 +508,28 @@ public final class PrintJobInfo implements Parcelable { mDocumentInfo = info; 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 @Override public int describeContents() { public int describeContents() { return 0; return 0; Loading Loading @@ -539,6 +566,7 @@ public final class PrintJobInfo implements Parcelable { } else { } else { parcel.writeInt(0); parcel.writeInt(0); } } parcel.writeInt(mCanceling ? 1 : 0); } } @Override @Override Loading @@ -556,6 +584,7 @@ public final class PrintJobInfo implements Parcelable { ? mAttributes.toString() : null)); ? mAttributes.toString() : null)); builder.append(", documentInfo: " + (mDocumentInfo != null builder.append(", documentInfo: " + (mDocumentInfo != null ? mDocumentInfo.toString() : null)); ? mDocumentInfo.toString() : null)); builder.append(", cancelling: " + mCanceling); builder.append(", pages: " + (mPageRanges != null builder.append(", pages: " + (mPageRanges != null ? Arrays.toString(mPageRanges) : null)); ? Arrays.toString(mPageRanges) : null)); builder.append("}"); builder.append("}"); Loading core/java/android/print/PrintManager.java +68 −42 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import java.util.Map; * <p> * <p> * To obtain a handle to the print manager do the following: * To obtain a handle to the print manager do the following: * </p> * </p> * * <pre> * <pre> * PrintManager printManager = * PrintManager printManager = * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); Loading @@ -59,6 +60,9 @@ public final class PrintManager { private static final boolean DEBUG = false; 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 */ /** @hide */ public static final int APP_ID_ANY = -2; public static final int APP_ID_ANY = -2; Loading @@ -84,7 +88,7 @@ public final class PrintManager { * * * @param printJobId The print job id. * @param printJobId The print job id. */ */ public void onPrintJobsStateChanged(PrintJobId printJobId); public void onPrintJobStateChanged(PrintJobId printJobId); } } /** /** Loading @@ -92,7 +96,6 @@ public final class PrintManager { * * * @param context The current context in which to operate. * @param context The current context in which to operate. * @param service The backing system service. * @param service The backing system service. * * @hide * @hide */ */ public PrintManager(Context context, IPrintManager service, int userId, int appId) { public PrintManager(Context context, IPrintManager service, int userId, int appId) { Loading @@ -104,6 +107,8 @@ public final class PrintManager { mHandler = new Handler(context.getMainLooper(), null, false) { mHandler = new Handler(context.getMainLooper(), null, false) { @Override @Override public void handleMessage(Message message) { public void handleMessage(Message message) { switch (message.what) { case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: { SomeArgs args = (SomeArgs) message.obj; SomeArgs args = (SomeArgs) message.obj; Context context = (Context) args.arg1; Context context = (Context) args.arg1; IntentSender intent = (IntentSender) args.arg2; IntentSender intent = (IntentSender) args.arg2; Loading @@ -114,6 +119,19 @@ public final class PrintManager { Log.e(LOG_TAG, "Couldn't start print job config activity.", 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; } } }; }; } } Loading @@ -121,8 +139,8 @@ public final class PrintManager { * Creates an instance that can access all print jobs. * Creates an instance that can access all print jobs. * * * @param userId The user id for which to get 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 * @return An instance if the caller has the permission to access all print * all print jobs, null otherwise. * jobs, null otherwise. * @hide * @hide */ */ public PrintManager getGlobalPrintManagerForUser(int userId) { public PrintManager getGlobalPrintManagerForUser(int userId) { Loading @@ -142,7 +160,6 @@ public final class PrintManager { * Adds a listener for observing the state of print jobs. * Adds a listener for observing the state of print jobs. * * * @param listener The listener to add. * @param listener The listener to add. * * @hide * @hide */ */ public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) { public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) { Loading @@ -151,7 +168,7 @@ public final class PrintManager { PrintJobStateChangeListenerWrapper>(); PrintJobStateChangeListenerWrapper>(); } } PrintJobStateChangeListenerWrapper wrappedListener = PrintJobStateChangeListenerWrapper wrappedListener = new PrintJobStateChangeListenerWrapper(listener); new PrintJobStateChangeListenerWrapper(listener, mHandler); try { try { mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId); mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId); mPrintJobStateChangeListeners.put(listener, wrappedListener); mPrintJobStateChangeListeners.put(listener, wrappedListener); Loading @@ -164,7 +181,6 @@ public final class PrintManager { * Removes a listener for observing the state of print jobs. * Removes a listener for observing the state of print jobs. * * * @param listener The listener to remove. * @param listener The listener to remove. * * @hide * @hide */ */ public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) { public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) { Loading @@ -190,9 +206,7 @@ public final class PrintManager { * Gets a print job given its id. * Gets a print job given its id. * * * @return The print job list. * @return The print job list. * * @see PrintJob * @see PrintJob * * @hide * @hide */ */ public PrintJob getPrintJob(PrintJobId printJobId) { public PrintJob getPrintJob(PrintJobId printJobId) { Loading @@ -211,7 +225,6 @@ public final class PrintManager { * Gets the print jobs for this application. * Gets the print jobs for this application. * * * @return The print job list. * @return The print job list. * * @see PrintJob * @see PrintJob */ */ public List<PrintJob> getPrintJobs() { public List<PrintJob> getPrintJobs() { Loading Loading @@ -249,8 +262,8 @@ public final class PrintManager { } } /** /** * Creates a print job for printing a {@link PrintDocumentAdapter} with default print * Creates a print job for printing a {@link PrintDocumentAdapter} with * attributes. * default print attributes. * * * @param printJobName A name for the new print job. * @param printJobName A name for the new print job. * @param documentAdapter An adapter that emits the document to print. * @param documentAdapter An adapter that emits the document to print. Loading Loading @@ -281,7 +294,6 @@ public final class PrintManager { * Gets the list of enabled print services. * Gets the list of enabled print services. * * * @return The enabled service list or an empty list. * @return The enabled service list or an empty list. * * @hide * @hide */ */ public List<PrintServiceInfo> getEnabledPrintServices() { public List<PrintServiceInfo> getEnabledPrintServices() { Loading @@ -300,7 +312,6 @@ public final class PrintManager { * Gets the list of installed print services. * Gets the list of installed print services. * * * @return The installed service list or an empty list. * @return The installed service list or an empty list. * * @hide * @hide */ */ public List<PrintServiceInfo> getInstalledPrintServices() { public List<PrintServiceInfo> getInstalledPrintServices() { Loading Loading @@ -337,7 +348,8 @@ public final class PrintManager { SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain(); args.arg1 = manager.mContext; args.arg1 = manager.mContext; args.arg2 = intent; args.arg2 = intent; manager.mHandler.obtainMessage(0, args).sendToTarget(); manager.mHandler.obtainMessage(MSG_START_PRINT_JOB_CONFIG_ACTIVITY, args).sendToTarget(); } } } } } } Loading @@ -348,7 +360,8 @@ public final class PrintManager { private CancellationSignal mLayoutOrWriteCancellation; 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() private Handler mHandler; // Strong reference OK - cleared in finish() Loading Loading @@ -537,7 +550,8 @@ public final class PrintManager { switch (message.what) { switch (message.what) { case MSG_START: { case MSG_START: { mDocumentAdapter.onStart(); mDocumentAdapter.onStart(); } break; } break; case MSG_LAYOUT: { case MSG_LAYOUT: { final CancellationSignal cancellation; final CancellationSignal cancellation; Loading @@ -559,7 +573,8 @@ public final class PrintManager { new MyLayoutResultCallback(layoutSpec.callback, new MyLayoutResultCallback(layoutSpec.callback, layoutSpec.sequence), layoutSpec.metadata); layoutSpec.sequence), layoutSpec.metadata); } } } break; } break; case MSG_WRITE: { case MSG_WRITE: { final CancellationSignal cancellation; final CancellationSignal cancellation; Loading @@ -580,7 +595,8 @@ public final class PrintManager { cancellation, new MyWriteResultCallback(writeSpec.callback, cancellation, new MyWriteResultCallback(writeSpec.callback, writeSpec.fd, writeSpec.sequence)); writeSpec.fd, writeSpec.sequence)); } } } break; } break; case MSG_FINISH: { case MSG_FINISH: { if (DEBUG) { if (DEBUG) { Loading @@ -588,7 +604,8 @@ public final class PrintManager { } } mDocumentAdapter.onFinish(); mDocumentAdapter.onFinish(); doFinish(); doFinish(); } break; } break; default: { default: { throw new IllegalArgumentException("Unknown message: " throw new IllegalArgumentException("Unknown message: " Loading Loading @@ -727,17 +744,26 @@ public final class PrintManager { private static final class PrintJobStateChangeListenerWrapper extends private static final class PrintJobStateChangeListenerWrapper extends IPrintJobStateChangeListener.Stub { IPrintJobStateChangeListener.Stub { private final WeakReference<PrintJobStateChangeListener> mWeakListener; 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); mWeakListener = new WeakReference<PrintJobStateChangeListener>(listener); mWeakHandler = new WeakReference<Handler>(handler); } } @Override @Override public void onPrintJobStateChanged(PrintJobId printJobId) { public void onPrintJobStateChanged(PrintJobId printJobId) { Handler handler = mWeakHandler.get(); PrintJobStateChangeListener listener = mWeakListener.get(); PrintJobStateChangeListener listener = mWeakListener.get(); if (listener != null) { if (handler != null && listener != null) { listener.onPrintJobsStateChanged(printJobId); SomeArgs args = SomeArgs.obtain(); args.arg1 = listener; args.arg2 = printJobId; handler.obtainMessage(MSG_NOTIFY_PRINT_JOB_STATE_CHANGED, args).sendToTarget(); } } } } } } } } packages/PrintSpooler/res/values/strings.xml +6 −0 Original line number Original line Diff line number Diff line Loading @@ -121,6 +121,12 @@ <!-- Template for the notificaiton label for a blocked print job. [CHAR LIMIT=25] --> <!-- 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> <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] --> <!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] --> <string name="cancel">Cancel</string> <string name="cancel">Cancel</string> Loading packages/PrintSpooler/src/com/android/printspooler/NotificationController.java +165 −47 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,14 @@ package com.android.printspooler; package com.android.printspooler; import android.app.Notification; import android.app.Notification; import android.app.Notification.InboxStyle; import android.app.NotificationManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.AsyncTask; import android.os.PowerManager; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock; Loading @@ -35,6 +38,9 @@ import android.print.PrintManager; import android.provider.Settings; import android.provider.Settings; import android.util.Log; import android.util.Log; import java.util.ArrayList; import java.util.List; /** /** * This class is responsible for updating the print notifications * This class is responsible for updating the print notifications * based on print job state transitions. * based on print job state transitions. Loading @@ -60,29 +66,50 @@ public class NotificationController { mContext.getSystemService(Context.NOTIFICATION_SERVICE); mContext.getSystemService(Context.NOTIFICATION_SERVICE); } } public void onPrintJobStateChanged(PrintJobInfo printJob) { public void onUpdateNotifications(List<PrintJobInfo> printJobs) { if (DEBUG) { List<PrintJobInfo> notifyPrintJobs = new ArrayList<PrintJobInfo>(); Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: " + printJob.getId().flattenToString() + " state:" final int printJobCount = printJobs.size(); + PrintJobInfo.stateToString(printJob.getState())); for (int i = 0; i < printJobCount; i++) { PrintJobInfo printJob = printJobs.get(i); if (shouldNotifyForState(printJob.getState())) { notifyPrintJobs.add(printJob); } } updateNotification(notifyPrintJobs); } } switch (printJob.getState()) { case PrintJobInfo.STATE_QUEUED: case PrintJobInfo.STATE_STARTED: { createPrintingNotification(printJob); } break; 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: { case PrintJobInfo.STATE_FAILED: { createFailedNotification(printJob); createFailedNotification(printJob); } break; } break; case PrintJobInfo.STATE_COMPLETED: case PrintJobInfo.STATE_CANCELED: { removeNotification(printJob.getId()); } break; case PrintJobInfo.STATE_BLOCKED: { case PrintJobInfo.STATE_BLOCKED: { if (!printJob.isCancelling()) { createBlockedNotification(printJob); createBlockedNotification(printJob); } else { createCancellingNotification(printJob); } } break; default: { if (!printJob.isCancelling()) { createPrintingNotification(printJob); } else { createCancellingNotification(printJob); } } break; } break; } } } } Loading @@ -90,24 +117,22 @@ public class NotificationController { private void createPrintingNotification(PrintJobInfo printJob) { private void createPrintingNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.printing_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .setContentText(printJob.getPrinterName()) .setContentText(printJob.getPrinterName()) .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } } private void createFailedNotification(PrintJobInfo printJob) { private void createFailedNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print_error) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.failed_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .addAction(R.drawable.ic_restart, mContext.getString(R.string.restart), .addAction(R.drawable.ic_restart, mContext.getString(R.string.restart), Loading @@ -116,32 +141,109 @@ public class NotificationController { .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } } private void createBlockedNotification(PrintJobInfo printJob) { private void createBlockedNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print_error) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.blocked_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .setContentText(printJob.getPrinterName()) .setContentText(printJob.getPrinterName()) .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } 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 removeNotification(PrintJobId printJobId) { private void createStackedNotification(List<PrintJobInfo> printJobs) { mNotificationManager.cancel(printJobId.flattenToString(), 0); 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) { private PendingIntent createContentIntent(PrintJobId printJobId) { Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); if (printJobId != null) { intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString()); intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString()); return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); intent.setData(Uri.fromParts("printjob", printJobId.flattenToString(), null)); } return PendingIntent.getActivity(mContext, 0, intent, 0); } } private PendingIntent createCancelIntent(PrintJobInfo printJob) { private PendingIntent createCancelIntent(PrintJobInfo printJob) { Loading @@ -160,6 +262,36 @@ public class NotificationController { return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); 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 { public static final class NotificationBroadcastReceiver extends BroadcastReceiver { private static final String LOG_TAG = "NotificationBroadcastReceiver"; private static final String LOG_TAG = "NotificationBroadcastReceiver"; Loading @@ -183,20 +315,6 @@ public class NotificationController { Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId); 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 // Call into the print manager service off the main thread since // the print manager service may end up binding to the print spooler // the print manager service may end up binding to the print spooler // service which binding is handled on the main thread. // service which binding is handled on the main thread. Loading Loading
core/java/android/print/IPrintSpooler.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -48,4 +48,5 @@ oneway interface IPrintSpooler { int sequence); int sequence); void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId); void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId); void setClient(IPrintSpoolerClient client); void setClient(IPrintSpoolerClient client); void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling); } }
core/java/android/print/PrintJobInfo.java +29 −0 Original line number Original line Diff line number Diff line Loading @@ -153,6 +153,9 @@ public final class PrintJobInfo implements Parcelable { /** Information about the printed document. */ /** Information about the printed document. */ private PrintDocumentInfo mDocumentInfo; private PrintDocumentInfo mDocumentInfo; /** Whether we are trying to cancel this print job. */ private boolean mCanceling; /** @hide*/ /** @hide*/ public PrintJobInfo() { public PrintJobInfo() { /* do nothing */ /* do nothing */ Loading @@ -174,6 +177,7 @@ public final class PrintJobInfo implements Parcelable { mPageRanges = other.mPageRanges; mPageRanges = other.mPageRanges; mAttributes = other.mAttributes; mAttributes = other.mAttributes; mDocumentInfo = other.mDocumentInfo; mDocumentInfo = other.mDocumentInfo; mCanceling = other.mCanceling; } } private PrintJobInfo(Parcel parcel) { private PrintJobInfo(Parcel parcel) { Loading Loading @@ -201,6 +205,7 @@ public final class PrintJobInfo implements Parcelable { if (parcel.readInt() == 1) { if (parcel.readInt() == 1) { mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); } } mCanceling = (parcel.readInt() == 1); } } /** /** Loading Loading @@ -503,6 +508,28 @@ public final class PrintJobInfo implements Parcelable { mDocumentInfo = info; 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 @Override public int describeContents() { public int describeContents() { return 0; return 0; Loading Loading @@ -539,6 +566,7 @@ public final class PrintJobInfo implements Parcelable { } else { } else { parcel.writeInt(0); parcel.writeInt(0); } } parcel.writeInt(mCanceling ? 1 : 0); } } @Override @Override Loading @@ -556,6 +584,7 @@ public final class PrintJobInfo implements Parcelable { ? mAttributes.toString() : null)); ? mAttributes.toString() : null)); builder.append(", documentInfo: " + (mDocumentInfo != null builder.append(", documentInfo: " + (mDocumentInfo != null ? mDocumentInfo.toString() : null)); ? mDocumentInfo.toString() : null)); builder.append(", cancelling: " + mCanceling); builder.append(", pages: " + (mPageRanges != null builder.append(", pages: " + (mPageRanges != null ? Arrays.toString(mPageRanges) : null)); ? Arrays.toString(mPageRanges) : null)); builder.append("}"); builder.append("}"); Loading
core/java/android/print/PrintManager.java +68 −42 Original line number Original line Diff line number Diff line Loading @@ -48,6 +48,7 @@ import java.util.Map; * <p> * <p> * To obtain a handle to the print manager do the following: * To obtain a handle to the print manager do the following: * </p> * </p> * * <pre> * <pre> * PrintManager printManager = * PrintManager printManager = * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); Loading @@ -59,6 +60,9 @@ public final class PrintManager { private static final boolean DEBUG = false; 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 */ /** @hide */ public static final int APP_ID_ANY = -2; public static final int APP_ID_ANY = -2; Loading @@ -84,7 +88,7 @@ public final class PrintManager { * * * @param printJobId The print job id. * @param printJobId The print job id. */ */ public void onPrintJobsStateChanged(PrintJobId printJobId); public void onPrintJobStateChanged(PrintJobId printJobId); } } /** /** Loading @@ -92,7 +96,6 @@ public final class PrintManager { * * * @param context The current context in which to operate. * @param context The current context in which to operate. * @param service The backing system service. * @param service The backing system service. * * @hide * @hide */ */ public PrintManager(Context context, IPrintManager service, int userId, int appId) { public PrintManager(Context context, IPrintManager service, int userId, int appId) { Loading @@ -104,6 +107,8 @@ public final class PrintManager { mHandler = new Handler(context.getMainLooper(), null, false) { mHandler = new Handler(context.getMainLooper(), null, false) { @Override @Override public void handleMessage(Message message) { public void handleMessage(Message message) { switch (message.what) { case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: { SomeArgs args = (SomeArgs) message.obj; SomeArgs args = (SomeArgs) message.obj; Context context = (Context) args.arg1; Context context = (Context) args.arg1; IntentSender intent = (IntentSender) args.arg2; IntentSender intent = (IntentSender) args.arg2; Loading @@ -114,6 +119,19 @@ public final class PrintManager { Log.e(LOG_TAG, "Couldn't start print job config activity.", 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; } } }; }; } } Loading @@ -121,8 +139,8 @@ public final class PrintManager { * Creates an instance that can access all print jobs. * Creates an instance that can access all print jobs. * * * @param userId The user id for which to get 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 * @return An instance if the caller has the permission to access all print * all print jobs, null otherwise. * jobs, null otherwise. * @hide * @hide */ */ public PrintManager getGlobalPrintManagerForUser(int userId) { public PrintManager getGlobalPrintManagerForUser(int userId) { Loading @@ -142,7 +160,6 @@ public final class PrintManager { * Adds a listener for observing the state of print jobs. * Adds a listener for observing the state of print jobs. * * * @param listener The listener to add. * @param listener The listener to add. * * @hide * @hide */ */ public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) { public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) { Loading @@ -151,7 +168,7 @@ public final class PrintManager { PrintJobStateChangeListenerWrapper>(); PrintJobStateChangeListenerWrapper>(); } } PrintJobStateChangeListenerWrapper wrappedListener = PrintJobStateChangeListenerWrapper wrappedListener = new PrintJobStateChangeListenerWrapper(listener); new PrintJobStateChangeListenerWrapper(listener, mHandler); try { try { mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId); mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId); mPrintJobStateChangeListeners.put(listener, wrappedListener); mPrintJobStateChangeListeners.put(listener, wrappedListener); Loading @@ -164,7 +181,6 @@ public final class PrintManager { * Removes a listener for observing the state of print jobs. * Removes a listener for observing the state of print jobs. * * * @param listener The listener to remove. * @param listener The listener to remove. * * @hide * @hide */ */ public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) { public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) { Loading @@ -190,9 +206,7 @@ public final class PrintManager { * Gets a print job given its id. * Gets a print job given its id. * * * @return The print job list. * @return The print job list. * * @see PrintJob * @see PrintJob * * @hide * @hide */ */ public PrintJob getPrintJob(PrintJobId printJobId) { public PrintJob getPrintJob(PrintJobId printJobId) { Loading @@ -211,7 +225,6 @@ public final class PrintManager { * Gets the print jobs for this application. * Gets the print jobs for this application. * * * @return The print job list. * @return The print job list. * * @see PrintJob * @see PrintJob */ */ public List<PrintJob> getPrintJobs() { public List<PrintJob> getPrintJobs() { Loading Loading @@ -249,8 +262,8 @@ public final class PrintManager { } } /** /** * Creates a print job for printing a {@link PrintDocumentAdapter} with default print * Creates a print job for printing a {@link PrintDocumentAdapter} with * attributes. * default print attributes. * * * @param printJobName A name for the new print job. * @param printJobName A name for the new print job. * @param documentAdapter An adapter that emits the document to print. * @param documentAdapter An adapter that emits the document to print. Loading Loading @@ -281,7 +294,6 @@ public final class PrintManager { * Gets the list of enabled print services. * Gets the list of enabled print services. * * * @return The enabled service list or an empty list. * @return The enabled service list or an empty list. * * @hide * @hide */ */ public List<PrintServiceInfo> getEnabledPrintServices() { public List<PrintServiceInfo> getEnabledPrintServices() { Loading @@ -300,7 +312,6 @@ public final class PrintManager { * Gets the list of installed print services. * Gets the list of installed print services. * * * @return The installed service list or an empty list. * @return The installed service list or an empty list. * * @hide * @hide */ */ public List<PrintServiceInfo> getInstalledPrintServices() { public List<PrintServiceInfo> getInstalledPrintServices() { Loading Loading @@ -337,7 +348,8 @@ public final class PrintManager { SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain(); args.arg1 = manager.mContext; args.arg1 = manager.mContext; args.arg2 = intent; args.arg2 = intent; manager.mHandler.obtainMessage(0, args).sendToTarget(); manager.mHandler.obtainMessage(MSG_START_PRINT_JOB_CONFIG_ACTIVITY, args).sendToTarget(); } } } } } } Loading @@ -348,7 +360,8 @@ public final class PrintManager { private CancellationSignal mLayoutOrWriteCancellation; 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() private Handler mHandler; // Strong reference OK - cleared in finish() Loading Loading @@ -537,7 +550,8 @@ public final class PrintManager { switch (message.what) { switch (message.what) { case MSG_START: { case MSG_START: { mDocumentAdapter.onStart(); mDocumentAdapter.onStart(); } break; } break; case MSG_LAYOUT: { case MSG_LAYOUT: { final CancellationSignal cancellation; final CancellationSignal cancellation; Loading @@ -559,7 +573,8 @@ public final class PrintManager { new MyLayoutResultCallback(layoutSpec.callback, new MyLayoutResultCallback(layoutSpec.callback, layoutSpec.sequence), layoutSpec.metadata); layoutSpec.sequence), layoutSpec.metadata); } } } break; } break; case MSG_WRITE: { case MSG_WRITE: { final CancellationSignal cancellation; final CancellationSignal cancellation; Loading @@ -580,7 +595,8 @@ public final class PrintManager { cancellation, new MyWriteResultCallback(writeSpec.callback, cancellation, new MyWriteResultCallback(writeSpec.callback, writeSpec.fd, writeSpec.sequence)); writeSpec.fd, writeSpec.sequence)); } } } break; } break; case MSG_FINISH: { case MSG_FINISH: { if (DEBUG) { if (DEBUG) { Loading @@ -588,7 +604,8 @@ public final class PrintManager { } } mDocumentAdapter.onFinish(); mDocumentAdapter.onFinish(); doFinish(); doFinish(); } break; } break; default: { default: { throw new IllegalArgumentException("Unknown message: " throw new IllegalArgumentException("Unknown message: " Loading Loading @@ -727,17 +744,26 @@ public final class PrintManager { private static final class PrintJobStateChangeListenerWrapper extends private static final class PrintJobStateChangeListenerWrapper extends IPrintJobStateChangeListener.Stub { IPrintJobStateChangeListener.Stub { private final WeakReference<PrintJobStateChangeListener> mWeakListener; 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); mWeakListener = new WeakReference<PrintJobStateChangeListener>(listener); mWeakHandler = new WeakReference<Handler>(handler); } } @Override @Override public void onPrintJobStateChanged(PrintJobId printJobId) { public void onPrintJobStateChanged(PrintJobId printJobId) { Handler handler = mWeakHandler.get(); PrintJobStateChangeListener listener = mWeakListener.get(); PrintJobStateChangeListener listener = mWeakListener.get(); if (listener != null) { if (handler != null && listener != null) { listener.onPrintJobsStateChanged(printJobId); SomeArgs args = SomeArgs.obtain(); args.arg1 = listener; args.arg2 = printJobId; handler.obtainMessage(MSG_NOTIFY_PRINT_JOB_STATE_CHANGED, args).sendToTarget(); } } } } } } } }
packages/PrintSpooler/res/values/strings.xml +6 −0 Original line number Original line Diff line number Diff line Loading @@ -121,6 +121,12 @@ <!-- Template for the notificaiton label for a blocked print job. [CHAR LIMIT=25] --> <!-- 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> <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] --> <!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] --> <string name="cancel">Cancel</string> <string name="cancel">Cancel</string> Loading
packages/PrintSpooler/src/com/android/printspooler/NotificationController.java +165 −47 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,14 @@ package com.android.printspooler; package com.android.printspooler; import android.app.Notification; import android.app.Notification; import android.app.Notification.InboxStyle; import android.app.NotificationManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.AsyncTask; import android.os.PowerManager; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock; Loading @@ -35,6 +38,9 @@ import android.print.PrintManager; import android.provider.Settings; import android.provider.Settings; import android.util.Log; import android.util.Log; import java.util.ArrayList; import java.util.List; /** /** * This class is responsible for updating the print notifications * This class is responsible for updating the print notifications * based on print job state transitions. * based on print job state transitions. Loading @@ -60,29 +66,50 @@ public class NotificationController { mContext.getSystemService(Context.NOTIFICATION_SERVICE); mContext.getSystemService(Context.NOTIFICATION_SERVICE); } } public void onPrintJobStateChanged(PrintJobInfo printJob) { public void onUpdateNotifications(List<PrintJobInfo> printJobs) { if (DEBUG) { List<PrintJobInfo> notifyPrintJobs = new ArrayList<PrintJobInfo>(); Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: " + printJob.getId().flattenToString() + " state:" final int printJobCount = printJobs.size(); + PrintJobInfo.stateToString(printJob.getState())); for (int i = 0; i < printJobCount; i++) { PrintJobInfo printJob = printJobs.get(i); if (shouldNotifyForState(printJob.getState())) { notifyPrintJobs.add(printJob); } } updateNotification(notifyPrintJobs); } } switch (printJob.getState()) { case PrintJobInfo.STATE_QUEUED: case PrintJobInfo.STATE_STARTED: { createPrintingNotification(printJob); } break; 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: { case PrintJobInfo.STATE_FAILED: { createFailedNotification(printJob); createFailedNotification(printJob); } break; } break; case PrintJobInfo.STATE_COMPLETED: case PrintJobInfo.STATE_CANCELED: { removeNotification(printJob.getId()); } break; case PrintJobInfo.STATE_BLOCKED: { case PrintJobInfo.STATE_BLOCKED: { if (!printJob.isCancelling()) { createBlockedNotification(printJob); createBlockedNotification(printJob); } else { createCancellingNotification(printJob); } } break; default: { if (!printJob.isCancelling()) { createPrintingNotification(printJob); } else { createCancellingNotification(printJob); } } break; } break; } } } } Loading @@ -90,24 +117,22 @@ public class NotificationController { private void createPrintingNotification(PrintJobInfo printJob) { private void createPrintingNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.printing_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .setContentText(printJob.getPrinterName()) .setContentText(printJob.getPrinterName()) .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } } private void createFailedNotification(PrintJobInfo printJob) { private void createFailedNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print_error) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.failed_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .addAction(R.drawable.ic_restart, mContext.getString(R.string.restart), .addAction(R.drawable.ic_restart, mContext.getString(R.string.restart), Loading @@ -116,32 +141,109 @@ public class NotificationController { .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } } private void createBlockedNotification(PrintJobInfo printJob) { private void createBlockedNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) Notification.Builder builder = new Notification.Builder(mContext) .setContentIntent(createContentIntent(printJob.getId())) .setContentIntent(createContentIntent(printJob.getId())) .setSmallIcon(com.android.internal.R.drawable.ic_print_error) .setSmallIcon(computeNotificationIcon(printJob)) .setContentTitle(mContext.getString(R.string.blocked_notification_title_template, .setContentTitle(computeNotificationTitle(printJob)) printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) createCancelIntent(printJob)) .setContentText(printJob.getPrinterName()) .setContentText(printJob.getPrinterName()) .setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setOngoing(true) .setShowWhen(true); .setShowWhen(true); mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); mNotificationManager.notify(0, builder.build()); } 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 removeNotification(PrintJobId printJobId) { private void createStackedNotification(List<PrintJobInfo> printJobs) { mNotificationManager.cancel(printJobId.flattenToString(), 0); 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) { private PendingIntent createContentIntent(PrintJobId printJobId) { Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); if (printJobId != null) { intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString()); intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString()); return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); intent.setData(Uri.fromParts("printjob", printJobId.flattenToString(), null)); } return PendingIntent.getActivity(mContext, 0, intent, 0); } } private PendingIntent createCancelIntent(PrintJobInfo printJob) { private PendingIntent createCancelIntent(PrintJobInfo printJob) { Loading @@ -160,6 +262,36 @@ public class NotificationController { return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); 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 { public static final class NotificationBroadcastReceiver extends BroadcastReceiver { private static final String LOG_TAG = "NotificationBroadcastReceiver"; private static final String LOG_TAG = "NotificationBroadcastReceiver"; Loading @@ -183,20 +315,6 @@ public class NotificationController { Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId); 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 // Call into the print manager service off the main thread since // the print manager service may end up binding to the print spooler // the print manager service may end up binding to the print spooler // service which binding is handled on the main thread. // service which binding is handled on the main thread. Loading