Merge "Adding hidden APIs for observing the print jobs state." into klp-dev

This commit is contained in:
Svetoslav Ganov
2013-09-26 19:22:19 +00:00
committed by Android (Google) Code Review
20 changed files with 556 additions and 60 deletions

View File

@@ -166,6 +166,7 @@ LOCAL_SRC_FILES += \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
core/java/android/print/IPrintClient.aidl \
core/java/android/print/IPrintJobStateChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \
core/java/android/print/IPrintSpoolerCallbacks.aidl \

View File

@@ -19372,6 +19372,13 @@ package android.print {
method public void cancel();
method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
method public boolean isBlocked();
method public boolean isCancelled();
method public boolean isCompleted();
method public boolean isFailed();
method public boolean isQueued();
method public boolean isStarted();
method public void restart();
}
public final class PrintJobId implements android.os.Parcelable {
@@ -19384,6 +19391,7 @@ package android.print {
method public int describeContents();
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
method public long getCreationTime();
method public android.print.PrintJobId getId();
method public java.lang.String getLabel();
method public android.print.PageRange[] getPages();

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.print;
import android.print.PrintJobId;
/**
* Interface for observing print job state changes.
*
* @hide
*/
oneway interface IPrintJobStateChangeListener {
void onPrintJobStateChanged(in PrintJobId printJobId);
}

View File

@@ -20,6 +20,7 @@ import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -39,6 +40,11 @@ interface IPrintManager {
void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
void restartPrintJob(in PrintJobId printJobId, int appId, int userId);
void addPrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
int appId, int userId);
void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
int userId);
List<PrintServiceInfo> getEnabledPrintServices(int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);

View File

@@ -18,7 +18,7 @@ package android.print;
import android.content.ComponentName;
import android.print.PrintJobInfo;
import android.print.PrintJobId;
/**
* Interface for receiving interesting state updates from the print spooler.
@@ -29,4 +29,5 @@ oneway interface IPrintSpoolerClient {
void onPrintJobQueued(in PrintJobInfo printJob);
void onAllPrintJobsForServiceHandled(in ComponentName printService);
void onAllPrintJobsHandled();
void onPrintJobStateChanged(in PrintJobId printJobId, int appId);
}

View File

@@ -62,14 +62,110 @@ public final class PrintJob {
}
/**
* Cancels this print job.
* Cancels this print job. You can request cancellation of a
* queued, started, blocked, or failed print job.
*
* @see #isQueued()
* @see #isStarted()
* @see #isBlocked()
* @see #isFailed()
*/
public void cancel() {
if (!isInImmutableState()) {
final int state = getInfo().getState();
if (state == PrintJobInfo.STATE_QUEUED
|| state == PrintJobInfo.STATE_STARTED
|| state == PrintJobInfo.STATE_BLOCKED
|| state == PrintJobInfo.STATE_FAILED) {
mPrintManager.cancelPrintJob(mCachedInfo.getId());
}
}
/**
* Restarts this print job. You can request restart of a failed
* print job.
*
* @see #isFailed()
*/
public void restart() {
if (isFailed()) {
mPrintManager.restartPrintJob(mCachedInfo.getId());
}
}
/**
* Gets whether this print job is queued. Such a print job is
* ready to be printed. You can request a cancellation via
* {@link #cancel()}.
*
* @return Whether the print job is queued.
*
* @see #cancel()
*/
public boolean isQueued() {
return getInfo().getState() == PrintJobInfo.STATE_QUEUED;
}
/**
* Gets whether this print job is started. Such a print job is
* being printed. You can request a cancellation via
* {@link #cancel()}.
*
* @return Whether the print job is started.
*
* @see #cancel()
*/
public boolean isStarted() {
return getInfo().getState() == PrintJobInfo.STATE_STARTED;
}
/**
* Gets whether this print job is blocked. Such a print job is halted
* due to an abnormal condition. You can request a cancellation via
* {@link #cancel()}.
*
* @return Whether the print job is blocked.
*
* @see #cancel()
*/
public boolean isBlocked() {
return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
}
/**
* Gets whether this print job is completed. Such a print job
* is successfully printed. You can neither cancel nor restart
* such a print job.
*
* @return Whether the print job is completed.
*/
public boolean isCompleted() {
return getInfo().getState() == PrintJobInfo.STATE_COMPLETED;
}
/**
* Gets whether this print job is failed. Such a print job is
* not successfully printed due to an error. You can request
* a restart via {@link #restart()}.
*
* @return Whether the print job is failed.
*
* @see #restart()
*/
public boolean isFailed() {
return getInfo().getState() == PrintJobInfo.STATE_FAILED;
}
/**
* Gets whether this print job is cancelled. Such a print job was
* cancelled as a result of a user request. This is a final state.
* You cannot restart such a print job.
*
* @return Whether the print job is cancelled.
*/
public boolean isCancelled() {
return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
}
private boolean isInImmutableState() {
final int state = mCachedInfo.getState();
return state == PrintJobInfo.STATE_COMPLETED

View File

@@ -138,6 +138,9 @@ public final class PrintJobInfo implements Parcelable {
/** Optional tag assigned by a print service.*/
private String mTag;
/** The wall time when the print job was created. */
private long mCreationTime;
/** How many copies to print. */
private int mCopies;
@@ -168,6 +171,7 @@ public final class PrintJobInfo implements Parcelable {
mAppId = other.mAppId;
mUserId = other.mUserId;
mTag = other.mTag;
mCreationTime = other.mCreationTime;
mCopies = other.mCopies;
mStateReason = other.mStateReason;
mPageRanges = other.mPageRanges;
@@ -184,6 +188,7 @@ public final class PrintJobInfo implements Parcelable {
mAppId = parcel.readInt();
mUserId = parcel.readInt();
mTag = parcel.readString();
mCreationTime = parcel.readLong();
mCopies = parcel.readInt();
mStateReason = parcel.readString();
if (parcel.readInt() == 1) {
@@ -367,6 +372,29 @@ public final class PrintJobInfo implements Parcelable {
mTag = tag;
}
/**
* Gets the wall time in millisecond when this print job was created.
*
* @return The creation time in milliseconds.
*/
public long getCreationTime() {
return mCreationTime;
}
/**
* Sets the wall time in milliseconds when this print job was created.
*
* @param creationTime The creation time in milliseconds.
*
* @hide
*/
public void setCreationTime(long creationTime) {
if (creationTime < 0) {
throw new IllegalArgumentException("creationTime must be non-negative.");
}
mCreationTime = creationTime;
}
/**
* Gets the number of copies.
*
@@ -491,6 +519,7 @@ public final class PrintJobInfo implements Parcelable {
parcel.writeInt(mAppId);
parcel.writeInt(mUserId);
parcel.writeString(mTag);
parcel.writeLong(mCreationTime);
parcel.writeInt(mCopies);
parcel.writeString(mStateReason);
if (mPageRanges != null) {
@@ -522,6 +551,7 @@ public final class PrintJobInfo implements Parcelable {
builder.append(", status: ").append(stateToString(mState));
builder.append(", printer: " + mPrinterId);
builder.append(", tag: ").append(mTag);
builder.append(", creationTime: " + mCreationTime);
builder.append(", copies: ").append(mCopies);
builder.append(", attributes: " + (mAttributes != null
? mAttributes.toString() : null));
@@ -537,7 +567,7 @@ public final class PrintJobInfo implements Parcelable {
public static String stateToString(int state) {
switch (state) {
case STATE_CREATED: {
return "STATUS_CREATED";
return "STATE_CREATED";
}
case STATE_QUEUED: {
return "STATE_QUEUED";
@@ -546,21 +576,20 @@ public final class PrintJobInfo implements Parcelable {
return "STATE_STARTED";
}
case STATE_FAILED: {
return "STATUS_FAILED";
return "STATE_FAILED";
}
case STATE_COMPLETED: {
return "STATUS_COMPLETED";
return "STATE_COMPLETED";
}
case STATE_CANCELED: {
return "STATUS_CANCELED";
return "STATE_CANCELED";
}
default: {
return "STATUS_UNKNOWN";
return "STATE_UNKNOWN";
}
}
}
public static final Parcelable.Creator<PrintJobInfo> CREATOR =
new Creator<PrintJobInfo>() {
@Override

View File

@@ -30,6 +30,7 @@ import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.printservice.PrintServiceInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.os.SomeArgs;
@@ -40,6 +41,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* System level service for accessing the printing capabilities of the platform.
@@ -70,6 +72,19 @@ public final class PrintManager {
private final Handler mHandler;
private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper> mPrintJobStateChangeListeners;
/** @hide */
public interface PrintJobStateChangeListener {
/**
* Callback notifying that a print job state changed.
*
* @param printJobId The print job id.
*/
public void onPrintJobsStateChanged(PrintJobId printJobId);
}
/**
* Creates a new instance.
*
@@ -106,7 +121,6 @@ public final class PrintManager {
* @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.
*
* @hide
*/
public PrintManager getGlobalPrintManagerForUser(int userId) {
@@ -122,6 +136,75 @@ public final class PrintManager {
return null;
}
/**
* Adds a listener for observing the state of print jobs.
*
* @param listener The listener to add.
*
* @hide
*/
public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
if (mPrintJobStateChangeListeners == null) {
mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
PrintJobStateChangeListenerWrapper>();
}
PrintJobStateChangeListenerWrapper wrappedListener =
new PrintJobStateChangeListenerWrapper(listener);
try {
mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId);
mPrintJobStateChangeListeners.put(listener, wrappedListener);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error adding print job state change listener", re);
}
}
/**
* Removes a listener for observing the state of print jobs.
*
* @param listener The listener to remove.
*
* @hide
*/
public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
if (mPrintJobStateChangeListeners == null) {
return;
}
PrintJobStateChangeListenerWrapper wrappedListener =
mPrintJobStateChangeListeners.remove(listener);
if (wrappedListener == null) {
return;
}
if (mPrintJobStateChangeListeners.isEmpty()) {
mPrintJobStateChangeListeners = null;
}
try {
mService.removePrintJobStateChangeListener(wrappedListener, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error removing print job state change listener", re);
}
}
/**
* Gets a print job given its id.
*
* @return The print job list.
*
* @see PrintJob
*
* @hide
*/
public PrintJob getPrintJob(PrintJobId printJobId) {
try {
PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId);
if (printJob != null) {
return new PrintJob(printJob, this);
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error getting print job", re);
}
return null;
}
/**
* Gets the print jobs for this application.
*
@@ -155,6 +238,14 @@ public final class PrintManager {
}
}
void restartPrintJob(PrintJobId printJobId) {
try {
mService.restartPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error restarting a print job: " + printJobId, re);
}
}
/**
* Creates a print job for printing a {@link PrintDocumentAdapter} with default print
* attributes.
@@ -163,7 +254,6 @@ public final class PrintManager {
* @param documentAdapter An adapter that emits the document to print.
* @param attributes The default print job attributes.
* @return The created print job on success or null on failure.
*
* @see PrintJob
*/
public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
@@ -220,11 +310,11 @@ public final class PrintManager {
}
@Override
public void startPrintJobConfigActivity(IntentSender intent) {
public void startPrintJobConfigActivity(IntentSender intent) {
PrintManager manager = mWeakPrintManager.get();
if (manager != null) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = manager.mContext;
args.arg1 = manager.mContext;
args.arg2 = intent;
manager.mHandler.obtainMessage(0, args).sendToTarget();
}
@@ -271,7 +361,7 @@ public final class PrintManager {
@Override
public void write(PageRange[] pages, ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence) {
IWriteResultCallback callback, int sequence) {
synchronized (mLock) {
if (mLayoutOrWriteCancellation != null) {
mLayoutOrWriteCancellation.cancel();
@@ -492,4 +582,21 @@ public final class PrintManager {
}
}
}
private static final class PrintJobStateChangeListenerWrapper extends
IPrintJobStateChangeListener.Stub {
private final WeakReference<PrintJobStateChangeListener> mWeakListener;
public PrintJobStateChangeListenerWrapper(PrintJobStateChangeListener listener) {
mWeakListener = new WeakReference<PrintJobStateChangeListener>(listener);
}
@Override
public void onPrintJobStateChanged(PrintJobId printJobId) {
PrintJobStateChangeListener listener = mWeakListener.get();
if (listener != null) {
listener.onPrintJobsStateChanged(printJobId);
}
}
}
}

View File

@@ -302,7 +302,7 @@ public final class PrinterInfo implements Parcelable {
private boolean isValidStatus(int status) {
return (status == STATUS_IDLE
|| status == STATUS_IDLE
|| status == STATUS_BUSY
|| status == STATUS_UNAVAILABLE);
}
}

View File

@@ -175,7 +175,7 @@ public final class PrintJob {
*/
public boolean isCancelled() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getState() == PrintJobInfo.STATE_FAILED;
return getInfo().getState() == PrintJobInfo.STATE_CANCELED;
}
/**

View File

Before

Width:  |  Height:  |  Size: 852 B

After

Width:  |  Height:  |  Size: 852 B

View File

Before

Width:  |  Height:  |  Size: 658 B

After

Width:  |  Height:  |  Size: 658 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1037,6 +1037,7 @@
<java-symbol type="drawable" name="ic_media_stop" />
<java-symbol type="drawable" name="ic_text_dot" />
<java-symbol type="drawable" name="ic_print" />
<java-symbol type="drawable" name="ic_print_error" />
<java-symbol type="drawable" name="indicator_code_lock_drag_direction_green_up" />
<java-symbol type="drawable" name="indicator_code_lock_drag_direction_red_up" />
<java-symbol type="drawable" name="indicator_code_lock_point_area_default_holo" />

View File

@@ -45,7 +45,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
android:textColor="@color/item_text_color"
android:textColor="@color/print_option_title"
android:duplicateParentState="true">
</TextView>

View File

@@ -32,7 +32,7 @@ import android.print.IPrintManager;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.text.TextUtils;
import android.provider.Settings;
import android.util.Log;
/**
@@ -47,9 +47,9 @@ public class NotificationController {
private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
private static final String INTENT_EXTRA_PRINTJOB_ID = "INTENT_EXTRA_PRINTJOB_ID";
private static final String INTENT_EXTRA_PRINTJOB_LABEL = "INTENT_EXTRA_PRINTJOB_LABEL";
private static final String INTENT_EXTRA_PRINTER_NAME = "INTENT_EXTRA_PRINTER_NAME";
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
private static final String EXTRA_PRINTJOB_LABEL = "EXTRA_PRINTJOB_LABEL";
private static final String EXTRA_PRINTER_NAME = "EXTRA_PRINTER_NAME";
private final Context mContext;
private final NotificationManager mNotificationManager;
@@ -89,6 +89,7 @@ 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()))
@@ -102,18 +103,16 @@ public class NotificationController {
}
private void createFailedNotification(PrintJobInfo printJob) {
String reason = !TextUtils.isEmpty(printJob.getStateReason())
? printJob.getStateReason() : mContext.getString(R.string.reason_unknown);
Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.stat_notify_error)
.setContentIntent(createContentIntent(printJob.getId()))
.setSmallIcon(com.android.internal.R.drawable.ic_print_error)
.setContentTitle(mContext.getString(R.string.failed_notification_title_template,
printJob.getLabel()))
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
createCancelIntent(printJob))
.addAction(android.R.drawable.ic_secure, mContext.getString(R.string.restart),
createRestartIntent(printJob.getId()))
.setContentText(reason)
.setContentText(printJob.getPrinterName())
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
@@ -121,16 +120,14 @@ public class NotificationController {
}
private void createBlockedNotification(PrintJobInfo printJob) {
String reason = !TextUtils.isEmpty(printJob.getStateReason())
? printJob.getStateReason() : mContext.getString(R.string.reason_unknown);
Notification.Builder builder = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.stat_notify_error)
.setContentIntent(createContentIntent(printJob.getId()))
.setSmallIcon(com.android.internal.R.drawable.ic_print_error)
.setContentTitle(mContext.getString(R.string.blocked_notification_title_template,
printJob.getLabel()))
.addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
createCancelIntent(printJob))
.setContentText(reason)
.setContentText(printJob.getPrinterName())
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
@@ -141,19 +138,25 @@ public class NotificationController {
mNotificationManager.cancel(printJobId.flattenToString(), 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);
}
private PendingIntent createCancelIntent(PrintJobInfo printJob) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJob.getId());
intent.putExtra(INTENT_EXTRA_PRINTJOB_LABEL, printJob.getLabel());
intent.putExtra(INTENT_EXTRA_PRINTER_NAME, printJob.getPrinterName());
intent.putExtra(EXTRA_PRINT_JOB_ID, printJob.getId());
intent.putExtra(EXTRA_PRINTJOB_LABEL, printJob.getLabel());
intent.putExtra(EXTRA_PRINTER_NAME, printJob.getPrinterName());
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
private PendingIntent createRestartIntent(PrintJobId printJobId) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJobId);
intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId);
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
@@ -164,12 +167,12 @@ public class NotificationController {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
String printJobLabel = intent.getExtras().getString(INTENT_EXTRA_PRINTJOB_LABEL);
String printerName = intent.getExtras().getString(INTENT_EXTRA_PRINTER_NAME);
PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
String printJobLabel = intent.getExtras().getString(EXTRA_PRINTJOB_LABEL);
String printerName = intent.getExtras().getString(EXTRA_PRINTER_NAME);
handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
} else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
handleRestartPrintJob(context, printJobId);
}
}

View File

@@ -155,23 +155,33 @@ public final class PrintSpoolerService extends Service {
@SuppressWarnings("deprecation")
@Override
public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
IPrintDocumentAdapter printAdapter) throws RemoteException {
PrintSpoolerService.this.createPrintJob(printJob);
IPrintDocumentAdapter printAdapter) throws RemoteException {
PrintSpoolerService.this.createPrintJob(printJob);
Intent intent = new Intent(printJob.getId().flattenToString());
intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
printAdapter.asBinder());
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
Intent intent = new Intent(printJob.getId().flattenToString());
intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
printAdapter.asBinder());
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
IntentSender sender = PendingIntent.getActivity(
PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
IntentSender sender = PendingIntent.getActivity(
PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
Message message = mHandlerCaller.obtainMessageOO(
HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
client, sender);
mHandlerCaller.executeOrSendMessage(message);
Message message = mHandlerCaller.obtainMessageIIO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob.getAppId(), 0, printJob.getId());
mHandlerCaller.executeOrSendMessage(message);
message = mHandlerCaller.obtainMessageOO(
HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
client, sender);
mHandlerCaller.executeOrSendMessage(message);
printJob.setCreationTime(System.currentTimeMillis());
synchronized (mLock) {
mPersistanceManager.writeStateLocked();
}
}
@Override
@@ -240,12 +250,13 @@ public final class PrintSpoolerService extends Service {
}
private final class HandlerCallerCallback implements HandlerCaller.Callback {
public static final int MSG_SET_CLIENT = 9;
public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 10;
public static final int MSG_ON_PRINT_JOB_QUEUED = 11;
public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 12;
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 13;
public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 14;
public static final int MSG_SET_CLIENT = 1;
public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 2;
public static final int MSG_ON_PRINT_JOB_QUEUED = 3;
public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 4;
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 5;
public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 6;
public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 7;
@Override
public void executeMessage(Message message) {
@@ -310,6 +321,18 @@ public final class PrintSpoolerService extends Service {
case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
checkAllPrintJobsHandled();
} break;
case MSG_ON_PRINT_JOB_STATE_CHANGED: {
if (mClient != null) {
PrintJobId printJobId = (PrintJobId) message.obj;
final int appId = message.arg1;
try {
mClient.onPrintJobStateChanged(printJobId, appId);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error notify for print job state change.", re);
}
}
} break;
}
}
}
@@ -511,6 +534,11 @@ public final class PrintSpoolerService extends Service {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
final int oldState = printJob.getState();
if (oldState == state) {
return false;
}
success = true;
printJob.setState(state);
@@ -553,6 +581,11 @@ public final class PrintSpoolerService extends Service {
if (!hasActivePrintJobsLocked()) {
notifyOnAllPrintJobsHandled();
}
Message message = mHandlerCaller.obtainMessageIIO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob.getAppId(), 0, printJob.getId());
mHandlerCaller.executeOrSendMessage(message);
}
}
@@ -706,7 +739,10 @@ public final class PrintSpoolerService extends Service {
private static final String ATTR_APP_ID = "appId";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_TAG = "tag";
private static final String ATTR_CREATION_TIME = "creationTime";
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 TAG_MEDIA_SIZE = "mediaSize";
private static final String TAG_RESOLUTION = "resolution";
@@ -714,7 +750,7 @@ public final class PrintSpoolerService extends Service {
private static final String ATTR_COLOR_MODE = "colorMode";
private static final String ATTR_LOCAL_ID = "printerName";
private static final String ATTR_LOCAL_ID = "localId";
private static final String ATTR_SERVICE_NAME = "serviceName";
private static final String ATTR_WIDTH_MILS = "widthMils";
@@ -794,7 +830,17 @@ public final class PrintSpoolerService extends Service {
if (tag != null) {
serializer.attribute(null, ATTR_TAG, tag);
}
serializer.attribute(null, ATTR_CREATION_TIME, String.valueOf(
printJob.getCreationTime()));
serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
String printerName = printJob.getPrinterName();
if (!TextUtils.isEmpty(printerName)) {
serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
}
String stateReason = printJob.getStateReason();
if (!TextUtils.isEmpty(stateReason)) {
serializer.attribute(null, ATTR_STATE_REASON, stateReason);
}
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
@@ -979,8 +1025,14 @@ public final class PrintSpoolerService extends Service {
printJob.setUserId(userId);
String tag = parser.getAttributeValue(null, ATTR_TAG);
printJob.setTag(tag);
String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
printJob.setCreationTime(Long.parseLong(creationTime));
String copies = parser.getAttributeValue(null, ATTR_COPIES);
printJob.setCopies(Integer.parseInt(copies));
String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
printJob.setPrinterName(printerName);
String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
printJob.setStateReason(stateReason);
parser.next();

View File

@@ -32,9 +32,11 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintManager;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
@@ -299,6 +301,39 @@ public final class PrintManagerService extends IPrintManager.Stub {
}
}
@Override
public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int appId, int userId) throws RemoteException {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.addPrintJobStateChangeListener(listener, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.removePrintJobStateChangeListener(listener);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)

View File

@@ -91,6 +91,7 @@ final class RemotePrintSpooler {
public static interface PrintSpoolerCallbacks {
public void onPrintJobQueued(PrintJobInfo printJob);
public void onAllPrintJobsForServiceHandled(ComponentName printService);
public void onPrintJobStateChanged(PrintJobId printJobId, int appId);
}
public RemotePrintSpooler(Context context, int userId,
@@ -345,6 +346,10 @@ final class RemotePrintSpooler {
}
}
private void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
mCallbacks.onPrintJobStateChanged(printJobId, appId);
}
private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
synchronized (mLock) {
if (mRemoteInstance != null) {
@@ -618,5 +623,18 @@ final class RemotePrintSpooler {
}
}
}
@Override
public void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.onPrintJobStateChanged(printJobId, appId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
}
}

View File

@@ -36,6 +36,7 @@ import android.os.RemoteException;
import android.os.UserManager;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobId;
@@ -103,8 +104,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private final RemotePrintSpooler mSpooler;
private final Handler mHandler;
private PrinterDiscoverySessionMediator mPrinterDiscoverySession;
private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
private boolean mDestroyed;
public UserState(Context context, int userId, Object lock) {
@@ -112,6 +117,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
mUserId = userId;
mLock = lock;
mSpooler = new RemotePrintSpooler(context, userId, this);
mHandler = new UserStateHandler(context.getMainLooper());
synchronized (mLock) {
enableSystemPrintServicesOnFirstBootLocked();
}
@@ -164,6 +170,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
printJob.setLabel(printJobName);
printJob.setAttributes(attributes);
printJob.setState(PrintJobInfo.STATE_CREATED);
printJob.setCopies(1);
// Spin the spooler to add the job and show the config UI.
new AsyncTask<Void, Void, Void>() {
@@ -351,6 +358,51 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
synchronized (mLock) {
throwIfDestroyedLocked();
if (mPrintJobStateChangeListenerRecords == null) {
mPrintJobStateChangeListenerRecords =
new ArrayList<PrintJobStateChangeListenerRecord>();
}
mPrintJobStateChangeListenerRecords.add(
new PrintJobStateChangeListenerRecord(listener, appId) {
@Override
public void onBinderDied() {
mPrintJobStateChangeListenerRecords.remove(this);
}
});
}
}
public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
synchronized (mLock) {
throwIfDestroyedLocked();
if (mPrintJobStateChangeListenerRecords == null) {
return;
}
final int recordCount = mPrintJobStateChangeListenerRecords.size();
for (int i = 0; i < recordCount; i++) {
PrintJobStateChangeListenerRecord record =
mPrintJobStateChangeListenerRecords.get(i);
if (record.listener.asBinder().equals(listener.asBinder())) {
mPrintJobStateChangeListenerRecords.remove(i);
break;
}
}
if (mPrintJobStateChangeListenerRecords.isEmpty()) {
mPrintJobStateChangeListenerRecords = null;
}
}
}
@Override
public void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_JOB_STATE_CHANGED,
appId, 0, printJobId).sendToTarget();
}
@Override
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
@@ -698,6 +750,65 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
private void handleDispatchPrintJobStateChanged(PrintJobId printJobId, int appId) {
final List<PrintJobStateChangeListenerRecord> records;
synchronized (mLock) {
if (mPrintJobStateChangeListenerRecords == null) {
return;
}
records = new ArrayList<PrintJobStateChangeListenerRecord>(
mPrintJobStateChangeListenerRecords);
}
final int recordCount = records.size();
for (int i = 0; i < recordCount; i++) {
PrintJobStateChangeListenerRecord record = records.get(i);
if (record.appId == PrintManager.APP_ID_ANY
|| record.appId == appId)
try {
record.listener.onPrintJobStateChanged(printJobId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error notifying for print job state change", re);
}
}
}
private final class UserStateHandler extends Handler {
public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
public UserStateHandler(Looper looper) {
super(looper, null, false);
}
@Override
public void handleMessage(Message message) {
if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) {
PrintJobId printJobId = (PrintJobId) message.obj;
final int appId = message.arg1;
handleDispatchPrintJobStateChanged(printJobId, appId);
}
}
}
private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
final IPrintJobStateChangeListener listener;
final int appId;
public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
this.listener = listener;
this.appId = appId;
listener.asBinder().linkToDeath(this, 0);
}
@Override
public void binderDied() {
listener.asBinder().unlinkToDeath(this, 0);
onBinderDied();
}
public abstract void onBinderDied();
}
private class PrinterDiscoverySessionMediator {
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();