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