Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ea16e9e authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android (Google) Code Review
Browse files

Merge "Coalescing multiple print job notifications." into klp-dev

parents 94ba8976 a18661d5
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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);
}
}
+29 −0
Original line number Original line Diff line number Diff line
@@ -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 */
@@ -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) {
@@ -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);
    }
    }


    /**
    /**
@@ -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;
@@ -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
@@ -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("}");
+68 −42
Original line number Original line Diff line number Diff line
@@ -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);
@@ -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;


@@ -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);
    }
    }


    /**
    /**
@@ -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) {
@@ -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;
@@ -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;
                }
            }
        };
        };
    }
    }


@@ -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) {
@@ -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) {
@@ -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);
@@ -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) {
@@ -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) {
@@ -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() {
@@ -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.
@@ -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() {
@@ -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() {
@@ -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();
            }
            }
        }
        }
    }
    }
@@ -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()


@@ -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;
@@ -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;
@@ -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) {
@@ -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: "
@@ -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();
            }
            }
        }
        }
    }
    }

}
}
+6 −0
Original line number Original line Diff line number Diff line
@@ -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>


+165 −47
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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.
@@ -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;
        }
        }
    }
    }
@@ -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),
@@ -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) {
@@ -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";


@@ -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