diff --git a/api/current.txt b/api/current.txt index 52bdf68b6451c..cfcf7025192ca 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18661,6 +18661,7 @@ package android.print { method public java.util.List getOutputTrays(); method public java.util.List getResolutions(); method public int getStatus(); + method public boolean hasAllRequiredAttributes(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int STATUS_READY = 1; // 0x1 @@ -18746,9 +18747,11 @@ package android.printservice { method protected void onDisconnected(); method protected abstract void onPrintJobQueued(android.printservice.PrintJob); method protected void onRequestCancelPrintJob(android.printservice.PrintJob); + method protected void onRequestUpdatePrinters(java.util.List); method protected abstract void onStartPrinterDiscovery(); method protected abstract void onStopPrinterDiscovery(); method public final void removeDiscoveredPrinters(java.util.List); + method public final void updateDiscoveredPrinters(java.util.List); field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService"; field public static final java.lang.String SERVICE_META_DATA = "android.printservice"; } diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl index 47975e1eafa92..46857e4eac989 100644 --- a/core/java/android/print/IPrintSpoolerClient.aidl +++ b/core/java/android/print/IPrintSpoolerClient.aidl @@ -18,6 +18,7 @@ package android.print; import android.content.ComponentName; import android.print.IPrinterDiscoveryObserver; +import android.print.PrinterId; import android.print.PrintJobInfo; @@ -30,6 +31,7 @@ oneway interface IPrintSpoolerClient { void onPrintJobQueued(in PrintJobInfo printJob); void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer); void onStopPrinterDiscovery(); + void onRequestUpdatePrinters(in List printerIds); void onAllPrintJobsForServiceHandled(in ComponentName printService); void onAllPrintJobsHandled(); } diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl index 39aeb8c73ec90..deabbcb04d77a 100644 --- a/core/java/android/print/IPrinterDiscoveryObserver.aidl +++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl @@ -25,6 +25,7 @@ import android.print.PrinterInfo; * @hide */ oneway interface IPrinterDiscoveryObserver { - void addDiscoveredPrinters(in List printers); - void removeDiscoveredPrinters(in List printers); + void onPrintersAdded(in List printers); + void onPrintersRemoved(in List printers); + void onPrintersUpdated(in List printers); } diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java index e884026aee75c..e27fbb2360550 100644 --- a/core/java/android/print/PrinterId.java +++ b/core/java/android/print/PrinterId.java @@ -19,6 +19,7 @@ package android.print; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; /** * This class represents the unique id of a printer. @@ -98,7 +99,7 @@ public final class PrinterId implements Parcelable { } else if (!mServiceComponentName.equals(other.mServiceComponentName)) { return false; } - if (mLocalId != other.mLocalId) { + if (!TextUtils.equals(mLocalId, other.mLocalId)) { return false; } return true; diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index c0daa6eb458db..15bcb734b63eb 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -23,9 +23,9 @@ import android.print.PrintAttributes.MediaSize; import android.print.PrintAttributes.Resolution; import android.print.PrintAttributes.Tray; import android.text.TextUtils; -import android.util.SparseIntArray; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -49,19 +49,22 @@ public final class PrinterInfo implements Parcelable { private static final int PROPERTY_COLOR_MODE = 5; private static final int PROPERTY_FITTING_MODE = 6; private static final int PROPERTY_ORIENTATION = 7; + private static final int PROPERTY_COUNT = 8; /** Printer status: the printer is ready to print. */ public static final int STATUS_READY = 1; + private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0); + // TODO: Add printer status constants. private PrinterId mId; private CharSequence mLabel; private int mStatus; - private Margins mMinMargins; - private final List mMediaSizes = new ArrayList(); // required - private final List mResolutions = new ArrayList(); // required + private Margins mMinMargins = DEFAULT_MARGINS; + private List mMediaSizes; + private List mResolutions; private List mInputTrays; private List mOutputTrays; @@ -70,43 +73,83 @@ public final class PrinterInfo implements Parcelable { private int mFittingModes; private int mOrientations; - private final SparseIntArray mDefaults = new SparseIntArray(); - private Margins mDefaultMargins; + private final int[] mDefaults = new int[PROPERTY_COUNT]; + private Margins mDefaultMargins = DEFAULT_MARGINS; - private PrinterInfo() { - mDefaults.put(PROPERTY_MEDIA_SIZE, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_RESOLUTION, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_INPUT_TRAY, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_OUTPUT_TRAY, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_DUPLEX_MODE, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_COLOR_MODE, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_FITTING_MODE, DEFAULT_UNDEFINED); - mDefaults.put(PROPERTY_ORIENTATION, DEFAULT_UNDEFINED); + /** + * @hide + */ + public PrinterInfo() { + Arrays.fill(mDefaults, DEFAULT_UNDEFINED); } private PrinterInfo(PrinterInfo prototype) { - mId = prototype.mId; - mLabel = prototype.mLabel; - mStatus = prototype.mStatus; + copyFrom(prototype); + } - mMinMargins = prototype.mMinMargins; - mMediaSizes.addAll(prototype.mMediaSizes); - mResolutions.addAll(prototype.mResolutions); - mInputTrays = (prototype.mInputTrays != null) - ? new ArrayList(prototype.mInputTrays) : null; - mOutputTrays = (prototype.mOutputTrays != null) - ? new ArrayList(prototype.mOutputTrays) : null; + /** + * @hide + */ + public void copyFrom(PrinterInfo other) { + mId = other.mId; + mLabel = other.mLabel; + mStatus = other.mStatus; - mDuplexModes = prototype.mDuplexModes; - mColorModes = prototype.mColorModes; - mFittingModes = prototype.mFittingModes; - mOrientations = prototype.mOrientations; - - final int defaultCount = prototype.mDefaults.size(); - for (int i = 0; i < defaultCount; i++) { - mDefaults.put(prototype.mDefaults.keyAt(i), prototype.mDefaults.valueAt(i)); + mMinMargins = other.mMinMargins; + if (other.mMediaSizes != null) { + if (mMediaSizes != null) { + mMediaSizes.clear(); + mMediaSizes.addAll(other.mMediaSizes); + } else { + mMediaSizes = new ArrayList(other.mMediaSizes); + } + } else { + mMediaSizes = null; } - mDefaultMargins = prototype.mDefaultMargins; + + if (other.mResolutions != null) { + if (mResolutions != null) { + mResolutions.clear(); + mResolutions.addAll(other.mResolutions); + } else { + mResolutions = new ArrayList(other.mResolutions); + } + } else { + mResolutions = null; + } + + if (other.mInputTrays != null) { + if (mInputTrays != null) { + mInputTrays.clear(); + mInputTrays.addAll(other.mInputTrays); + } else { + mInputTrays = new ArrayList(other.mInputTrays); + } + } else { + mInputTrays = null; + } + + if (other.mOutputTrays != null) { + if (mOutputTrays != null) { + mOutputTrays.clear(); + mOutputTrays.addAll(other.mOutputTrays); + } else { + mOutputTrays = new ArrayList(other.mOutputTrays); + } + } else { + mOutputTrays = null; + } + + mDuplexModes = other.mDuplexModes; + mColorModes = other.mColorModes; + mFittingModes = other.mFittingModes; + mOrientations = other.mOrientations; + + final int defaultCount = other.mDefaults.length; + for (int i = 0; i < defaultCount; i++) { + mDefaults[i] = other.mDefaults[i]; + } + mDefaultMargins = other.mDefaultMargins; } /** @@ -240,47 +283,64 @@ public final class PrinterInfo implements Parcelable { outAttributes.setMargins(mDefaultMargins); - final int mediaSizeIndex = mDefaults.get(PROPERTY_MEDIA_SIZE); + final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE]; if (mediaSizeIndex >= 0) { outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex)); } - final int resolutionIndex = mDefaults.get(PROPERTY_RESOLUTION); + final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION]; if (resolutionIndex >= 0) { outAttributes.setResolution(mResolutions.get(resolutionIndex)); } - final int inputTrayIndex = mDefaults.get(PROPERTY_INPUT_TRAY); + final int inputTrayIndex = mDefaults[PROPERTY_INPUT_TRAY]; if (inputTrayIndex >= 0) { outAttributes.setInputTray(mInputTrays.get(inputTrayIndex)); } - final int outputTrayIndex = mDefaults.get(PROPERTY_OUTPUT_TRAY); + final int outputTrayIndex = mDefaults[PROPERTY_OUTPUT_TRAY]; if (outputTrayIndex >= 0) { outAttributes.setOutputTray(mOutputTrays.get(outputTrayIndex)); } - final int duplexMode = mDefaults.get(PROPERTY_DUPLEX_MODE); + final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE]; if (duplexMode > 0) { outAttributes.setDuplexMode(duplexMode); } - final int colorMode = mDefaults.get(PROPERTY_COLOR_MODE); + final int colorMode = mDefaults[PROPERTY_COLOR_MODE]; if (colorMode > 0) { outAttributes.setColorMode(mColorModes & colorMode); } - final int fittingMode = mDefaults.get(PROPERTY_FITTING_MODE); + final int fittingMode = mDefaults[PROPERTY_FITTING_MODE]; if (fittingMode > 0) { outAttributes.setFittingMode(fittingMode); } - final int orientation = mDefaults.get(PROPERTY_ORIENTATION); + final int orientation = mDefaults[PROPERTY_ORIENTATION]; if (orientation > 0) { outAttributes.setOrientation(orientation); } } + /** + * Gets whether this printer info is fully-populated, i.e. whether + * all required attributes are specified. See the {@link Builder} + * documentation for which attributes are required. + * + * @return Whether this info has all required attributes. + */ + public boolean hasAllRequiredAttributes() { + return (mMediaSizes != null && !mMediaSizes.isEmpty() + && mResolutions != null && !mResolutions.isEmpty() + && mColorModes != 0 || mOrientations != 0 + && mDefaults[PROPERTY_MEDIA_SIZE] != DEFAULT_UNDEFINED + && mDefaults[PROPERTY_RESOLUTION] != DEFAULT_UNDEFINED + && mDefaults[PROPERTY_COLOR_MODE] != DEFAULT_UNDEFINED + && mDefaults[PROPERTY_ORIENTATION] != DEFAULT_UNDEFINED); + } + private PrinterInfo(Parcel parcel) { mId = parcel.readParcelable(null); mLabel = parcel.readCharSequence(); @@ -327,6 +387,112 @@ public final class PrinterInfo implements Parcelable { writeMargins(mDefaultMargins, parcel); } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mId == null) ? 0 : mId.hashCode()); + result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode()); + result = prime * result + mStatus; + result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode()); + result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode()); + result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode()); + result = prime * result + ((mInputTrays == null) ? 0 : mInputTrays.hashCode()); + result = prime * result + ((mOutputTrays == null) ? 0 : mOutputTrays.hashCode()); + result = prime * result + mDuplexModes; + result = prime * result + mColorModes; + result = prime * result + mFittingModes; + result = prime * result + mOrientations; + result = prime * result + Arrays.hashCode(mDefaults); + result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PrinterInfo other = (PrinterInfo) obj; + if (mId == null) { + if (other.mId != null) { + return false; + } + } else if (!mId.equals(other.mId)) { + return false; + } + if (!TextUtils.equals(mLabel, other.mLabel)) { + return false; + } + if (mStatus != other.mStatus) { + return false; + } + if (mMinMargins == null) { + if (other.mMinMargins != null) { + return false; + } + } else if (!mMinMargins.equals(other.mMinMargins)) { + return false; + } + if (mMediaSizes == null) { + if (other.mMediaSizes != null) { + return false; + } + } else if (!mMediaSizes.equals(other.mMediaSizes)) { + return false; + } + if (mResolutions == null) { + if (other.mResolutions != null) { + return false; + } + } else if (!mResolutions.equals(other.mResolutions)) { + return false; + } + if (mInputTrays == null) { + if (other.mInputTrays != null) { + return false; + } + } else if (!mInputTrays.equals(other.mInputTrays)) { + return false; + } + if (mOutputTrays == null) { + if (other.mOutputTrays != null) { + return false; + } + } else if (!mOutputTrays.equals(other.mOutputTrays)) { + return false; + } + if (mDuplexModes != other.mDuplexModes) { + return false; + } + if (mColorModes != other.mColorModes) { + return false; + } + if (mFittingModes != other.mFittingModes) { + return false; + } + if (mOrientations != other.mOrientations) { + return false; + } + if (!Arrays.equals(mDefaults, other.mDefaults)) { + return false; + } + if (mDefaultMargins == null) { + if (other.mDefaultMargins != null) { + return false; + } + } else if (!mDefaultMargins.equals(other.mDefaultMargins)) { + return false; + } + return true; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -351,12 +517,19 @@ public final class PrinterInfo implements Parcelable { private void readMediaSizes(Parcel parcel) { final int mediaSizeCount = parcel.readInt(); + if (mediaSizeCount > 0 && mMediaSizes == null) { + mMediaSizes = new ArrayList(); + } for (int i = 0; i < mediaSizeCount; i++) { mMediaSizes.add(MediaSize.createFromParcel(parcel)); } } private void writeResolutions(Parcel parcel) { + if (mResolutions == null) { + parcel.writeInt(0); + return; + } final int resolutionCount = mResolutions.size(); parcel.writeInt(resolutionCount); for (int i = 0; i < resolutionCount; i++) { @@ -366,6 +539,9 @@ public final class PrinterInfo implements Parcelable { private void readResolutions(Parcel parcel) { final int resolutionCount = parcel.readInt(); + if (resolutionCount > 0 && mResolutions == null) { + mResolutions = new ArrayList(); + } for (int i = 0; i < resolutionCount; i++) { mResolutions.add(Resolution.createFromParcel(parcel)); } @@ -435,15 +611,15 @@ public final class PrinterInfo implements Parcelable { private void readDefaults(Parcel parcel) { final int defaultCount = parcel.readInt(); for (int i = 0; i < defaultCount; i++) { - mDefaults.append(mDefaults.size(), parcel.readInt()); + mDefaults[i] = parcel.readInt(); } } private void writeDefaults(Parcel parcel) { - final int defaultCount = mDefaults.size(); + final int defaultCount = mDefaults.length; parcel.writeInt(defaultCount); for (int i = 0; i < defaultCount; i++) { - parcel.writeInt(mDefaults.valueAt(i)); + parcel.writeInt(mDefaults[i]); } } @@ -462,11 +638,11 @@ public final class PrinterInfo implements Parcelable { /** * Creates a new instance. * - * @param printerId The printer id. - * @param label The human readable printer label. + * @param printerId The printer id. Cannot be null. + * @param label The human readable printer label. Cannot be null or empty. * - * @throws IllegalArgumentException IF the printer id is null. - * @throws IllegalArgumentException IF the label is empty. + * @throws IllegalArgumentException If the printer id is null. + * @throws IllegalArgumentException If the label is empty. */ public Builder(PrinterId printerId, CharSequence label) { if (printerId == null) { @@ -509,11 +685,14 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.MediaSize */ public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) { + if (mPrototype.mMediaSizes == null) { + mPrototype.mMediaSizes = new ArrayList(); + } final int insertionIndex = mPrototype.mMediaSizes.size(); mPrototype.mMediaSizes.add(mediaSize); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE); - mPrototype.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex); + mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex; } return this; } @@ -534,11 +713,14 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.Resolution */ public Builder addResolution(Resolution resolution, boolean isDefault) { + if (mPrototype.mResolutions == null) { + mPrototype.mResolutions = new ArrayList(); + } final int insertionIndex = mPrototype.mResolutions.size(); mPrototype.mResolutions.add(resolution); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION); - mPrototype.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex); + mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex; } return this; } @@ -591,7 +773,7 @@ public final class PrinterInfo implements Parcelable { mPrototype.mInputTrays.add(inputTray); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY); - mPrototype.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex); + mPrototype.mDefaults[PROPERTY_INPUT_TRAY] = insertionIndex; } return this; } @@ -619,7 +801,7 @@ public final class PrinterInfo implements Parcelable { mPrototype.mOutputTrays.add(outputTray); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY); - mPrototype.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex); + mPrototype.mDefaults[PROPERTY_OUTPUT_TRAY] = insertionIndex; } return this; } @@ -652,7 +834,7 @@ public final class PrinterInfo implements Parcelable { } PrintAttributes.enforceValidColorMode(colorModes); mPrototype.mColorModes = colorModes; - mPrototype.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode); + mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode; return this; } @@ -685,7 +867,7 @@ public final class PrinterInfo implements Parcelable { } PrintAttributes.enforceValidDuplexMode(defaultDuplexMode); mPrototype.mDuplexModes = duplexModes; - mPrototype.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode); + mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode; return this; } @@ -717,7 +899,7 @@ public final class PrinterInfo implements Parcelable { } PrintAttributes.enfoceValidFittingMode(defaultFittingMode); mPrototype.mFittingModes = fittingModes; - mPrototype.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode); + mPrototype.mDefaults[PROPERTY_FITTING_MODE] = defaultFittingMode; return this; } @@ -749,55 +931,21 @@ public final class PrinterInfo implements Parcelable { } PrintAttributes.enforceValidOrientation(defaultOrientation); mPrototype.mOrientations = orientations; - mPrototype.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation); + mPrototype.mDefaults[PROPERTY_ORIENTATION] = defaultOrientation; return this; } /** - * Crates a new {@link PrinterInfo} enforcing that all required properties - * have need specified. See individual methods in this class for reference - * about required attributes. + * Crates a new {@link PrinterInfo}. * * @return A new {@link PrinterInfo}. - * - * @throws IllegalStateException If a required attribute was not specified. */ public PrinterInfo create() { - if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) { - throw new IllegalStateException("No media size specified."); - } - if (mPrototype.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) { - throw new IllegalStateException("No default media size specified."); - } - if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) { - throw new IllegalStateException("No resolution specified."); - } - if (mPrototype.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) { - throw new IllegalStateException("No default resolution specified."); - } - if (mPrototype.mColorModes == 0) { - throw new IllegalStateException("No color mode specified."); - } - if (mPrototype.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) { - throw new IllegalStateException("No default color mode specified."); - } - if (mPrototype.mOrientations == 0) { - throw new IllegalStateException("No oprientation specified."); - } - if (mPrototype.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) { - throw new IllegalStateException("No default orientation specified."); - } - if (mPrototype.mMinMargins == null) { - mPrototype.mMinMargins = new Margins(0, 0, 0, 0); - } - if (mPrototype.mDefaultMargins == null) { - mPrototype.mDefaultMargins = mPrototype.mMinMargins; - } return new PrinterInfo(mPrototype); } private void throwIfDefaultAlreadySpecified(int propertyIndex) { - if (mPrototype.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) { throw new IllegalArgumentException("Default already specified."); } } diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl index c72385adda3fc..e6fdbf999a352 100644 --- a/core/java/android/printservice/IPrintService.aidl +++ b/core/java/android/printservice/IPrintService.aidl @@ -29,8 +29,9 @@ import android.printservice.IPrintServiceClient; */ oneway interface IPrintService { void setClient(IPrintServiceClient client); - void requestCancelPrintJob(in PrintJobInfo printJobInfo); + void onRequestUpdatePrinters(in List printerIds); + void onRequestCancelPrintJob(in PrintJobInfo printJobInfo); void onPrintJobQueued(in PrintJobInfo printJobInfo); - void startPrinterDiscovery(IPrinterDiscoveryObserver observer); - void stopPrinterDiscovery(); + void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer); + void onStopPrinterDiscovery(); } diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index dde31d25678b9..15e1b7399719d 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -207,13 +207,14 @@ public abstract class PrintService extends Service { * Callback requesting from this service to start printer discovery. * At the end of the printer discovery period the system will call * {@link #onStopPrinterDiscovery()}. Discovered printers should be - * reported by calling #addDiscoveredPrinters(List) and reported ones - * that disappear should be reported by calling + * reported by calling {@link #addDiscoveredPrinters(List)} and reported + * ones that disappear should be reported by calling * {@link #removeDiscoveredPrinters(List)}. * * @see #onStopPrinterDiscovery() * @see #addDiscoveredPrinters(List) * @see #removeDiscoveredPrinters(List) + * @see #updateDiscoveredPrinters(List) */ protected abstract void onStartPrinterDiscovery(); @@ -223,6 +224,7 @@ public abstract class PrintService extends Service { * @see #onStartPrinterDiscovery() * @see #addDiscoveredPrinters(List) * @see #removeDiscoveredPrinters(List) + * @see #updateDiscoveredPrinters(List) */ protected abstract void onStopPrinterDiscovery(); @@ -236,12 +238,23 @@ public abstract class PrintService extends Service { * printers have to be added. You can call this method as many times as * necessary during the discovery period but should not pass in already * added printers. If a printer is already added in the same printer - * discovery period, it will be ignored. If you want to update an already - * added printer, you should removed it and then re-add it. + * discovery period, it will be ignored. *

+ *

+ * A {@link PrinterInfo} can have all of its required attributes specified, + * or not. Whether all attributes are specified can be verified by calling + * {@link PrinterInfo#hasAllRequiredAttributes()}. You can add printers + * regardless if all required attributes are specified. When the system + * (and the user) needs to interact with a printer, you will receive a + * call to {@link #onRequestUpdatePrinters(List)}. If you fail to update + * a printer that was added without all required attributes via calling + * {@link #updateDiscoveredPrinters(List)}, then this printer will be + * ignored, i.e. considered unavailable. + *

* * @param printers A list with discovered printers. * + * @see #updateDiscoveredPrinters(List) * @see #removeDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() @@ -253,7 +266,7 @@ public abstract class PrintService extends Service { } if (observer != null) { try { - observer.addDiscoveredPrinters(printers); + observer.onPrintersAdded(printers); } catch (RemoteException re) { Log.e(LOG_TAG, "Error adding discovered printers", re); } @@ -271,14 +284,13 @@ public abstract class PrintService extends Service { * period by a call to {@link #addDiscoveredPrinters(List)}. You can call * this method as many times as necessary during the discovery period * but should not pass in already removed printer ids. If a printer with - * a given id is already removed in the same discovery period, it will - * be ignored. If you want to update an already added printer, you should - * removed it and then re-add it. + * a given id is already removed, it will be ignored. *

* * @param printerIds A list with disappeared printer ids. * * @see #addDiscoveredPrinters(List) + * @see #updateDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() */ @@ -289,13 +301,72 @@ public abstract class PrintService extends Service { } if (observer != null) { try { - observer.removeDiscoveredPrinters(printerIds); + observer.onPrintersRemoved(printerIds); } catch (RemoteException re) { Log.e(LOG_TAG, "Error removing discovered printers", re); } } } + /** + * Updates discovered printers that are already added. This method should + * be called during a printer discovery period, i.e. after a call to + * {@link #onStartPrinterDiscovery()} and before the corresponding + * call to {@link #onStopPrinterDiscovery()}, otherwise it does nothing. + *

+ * For every printer discovery period all printers have to be added. You + * should update only printers that were added in this printer discovery + * period by a call to {@link #addDiscoveredPrinters(List)}. You can call + * this method as many times as necessary during the discovery period + * but should not try to update already removed or never added printers. + * If a printer is already removed or never added, it will be ignored. + *

+ * + * @param printers A list with updated printers. + * + * @see #addDiscoveredPrinters(List) + * @see #removeDiscoveredPrinters(List) + * @see #onStartPrinterDiscovery() + * @see #onStopPrinterDiscovery() + */ + public final void updateDiscoveredPrinters(List printers) { + final IPrinterDiscoveryObserver observer; + synchronized (mLock) { + observer = mDiscoveryObserver; + } + if (observer != null) { + try { + observer.onPrintersUpdated(printers); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error updating discovered printers", re); + } + } + } + + /** + * Called when the system will start interacting with a printer + * giving you a change to update it in case some of its capabilities + * have changed. For example, this method will be called when the + * user selects a printer. Hence, it updating this printer should + * be done as quickly as possible in order to achieve maximally + * smooth user experience. + *

+ * A {@link PrinterInfo} can have all of its required attributes specified, + * or not. Whether all attributes are specified can be verified by calling + * {@link PrinterInfo#hasAllRequiredAttributes()}. You can add printers + * regardless if all required attributes are specified. When the system + * (and the user) needs to interact with a printer, you will receive a + * call to this method. If you fail to update a printer that was added + * without all required attributes via calling + * {@link #updateDiscoveredPrinters(List)}, then this printer will be + * ignored, i.e. considered unavailable. + *

+ * + * @param printerIds The printers to be updated. + */ + protected void onRequestUpdatePrinters(List printerIds) { + } + /** * Called when canceling of a print job is requested. The service * should do best effort to fulfill the request. After the cancellation @@ -373,74 +444,87 @@ public abstract class PrintService extends Service { return new IPrintService.Stub() { @Override public void setClient(IPrintServiceClient client) { - mHandler.obtainMessage(MyHandler.MESSAGE_SET_CLEINT, client).sendToTarget(); + mHandler.obtainMessage(MyHandler.MSG_SET_CLEINT, client).sendToTarget(); } @Override - public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) { - mHandler.obtainMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY, + public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) { + mHandler.obtainMessage(MyHandler.MSG_ON_START_PRINTER_DISCOVERY, observer).sendToTarget(); } @Override - public void stopPrinterDiscovery() { - mHandler.sendEmptyMessage(MyHandler.MESSAGE_STOP_PRINTER_DISCOVERY); + public void onStopPrinterDiscovery() { + mHandler.sendEmptyMessage(MyHandler.MSG_ON_STOP_PRINTER_DISCOVERY); } @Override - public void requestCancelPrintJob(PrintJobInfo printJobInfo) { - mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB, + public void onRequestUpdatePrinters(List printerIds) { + mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_UPDATE_PRINTERS, + printerIds).sendToTarget(); + } + + @Override + public void onRequestCancelPrintJob(PrintJobInfo printJobInfo) { + mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB, printJobInfo).sendToTarget(); } @Override public void onPrintJobQueued(PrintJobInfo printJobInfo) { - mHandler.obtainMessage(MyHandler.MESSAGE_ON_PRINTJOB_QUEUED, + mHandler.obtainMessage(MyHandler.MSG_ON_PRINTJOB_QUEUED, printJobInfo).sendToTarget(); } }; } private final class MyHandler extends Handler { - public static final int MESSAGE_START_PRINTER_DISCOVERY = 1; - public static final int MESSAGE_STOP_PRINTER_DISCOVERY = 2; - public static final int MESSAGE_CANCEL_PRINTJOB = 3; - public static final int MESSAGE_ON_PRINTJOB_QUEUED = 4; - public static final int MESSAGE_SET_CLEINT = 5; + public static final int MSG_ON_START_PRINTER_DISCOVERY = 1; + public static final int MSG_ON_STOP_PRINTER_DISCOVERY = 2; + public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 3; + public static final int MSG_ON_REQUEST_UPDATE_PRINTERS = 4; + public static final int MSG_ON_PRINTJOB_QUEUED = 5; + public static final int MSG_SET_CLEINT = 6; public MyHandler(Looper looper) { super(looper, null, true); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { final int action = message.what; switch (action) { - case MESSAGE_START_PRINTER_DISCOVERY: { + case MSG_ON_START_PRINTER_DISCOVERY: { synchronized (mLock) { mDiscoveryObserver = (IPrinterDiscoveryObserver) message.obj; } onStartPrinterDiscovery(); } break; - case MESSAGE_STOP_PRINTER_DISCOVERY: { + case MSG_ON_STOP_PRINTER_DISCOVERY: { synchronized (mLock) { mDiscoveryObserver = null; } onStopPrinterDiscovery(); } break; - case MESSAGE_CANCEL_PRINTJOB: { + case MSG_ON_REQUEST_CANCEL_PRINTJOB: { PrintJobInfo printJobInfo = (PrintJobInfo) message.obj; onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient)); } break; - case MESSAGE_ON_PRINTJOB_QUEUED: { + case MSG_ON_REQUEST_UPDATE_PRINTERS: { + List printerIds = (List) message.obj; + onRequestUpdatePrinters(printerIds); + } break; + + case MSG_ON_PRINTJOB_QUEUED: { PrintJobInfo printJobInfo = (PrintJobInfo) message.obj; onPrintJobQueued(new PrintJob(printJobInfo, mClient)); } break; - case MESSAGE_SET_CLEINT: { + case MSG_SET_CLEINT: { IPrintServiceClient client = (IPrintServiceClient) message.obj; synchronized (mLock) { mClient = client; diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 86c4f372dc041..d61fd2cadc5a3 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -464,7 +464,7 @@ public class PrintJobConfigActivity extends Activity { } else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) { // We requested specific pages and got more but not all pages. // Hence, we have to offset appropriately the printed pages to - // exclude the pages we did not request. Note that pages is + // excle the pages we did not request. Note that pages is // guaranteed to be not null and not empty. final int offset = mDocument.pages[0].getStart() - pages[0].getStart(); PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length); @@ -571,16 +571,24 @@ public class PrintJobConfigActivity extends Activity { mCurrPrintAttributes.clear(); SpinnerItem dstItem = mDestinationSpinnerAdapter.getItem(position); if (dstItem != null) { - mSpooler.setPrintJobPrinterIdNoPersistence(mPrintJobId, dstItem.value.getId()); - dstItem.value.getDefaults(mCurrPrintAttributes); + PrinterInfo printer = dstItem.value; + mSpooler.setPrintJobPrinterIdNoPersistence(mPrintJobId, printer.getId()); + printer.getDefaults(mCurrPrintAttributes); + if (!printer.hasAllRequiredAttributes()) { + List printerIds = new ArrayList(); + printerIds.add(printer.getId()); + mSpooler.onReqeustUpdatePrinters(printerIds); + //TODO: We need a timeout for the update. + } else { + if (!mController.hasStarted()) { + mController.start(); + } + if (!hasErrors()) { + mController.update(); + } + } } updateUi(); - if (!mController.hasStarted()) { - mController.start(); - } - if (!hasErrors()) { - mController.update(); - } } else if (spinner == mMediaSizeSpinner) { SpinnerItem mediaItem = mMediaSizeSpinnerAdapter.getItem(position); mCurrPrintAttributes.setMediaSize(mediaItem.value); @@ -886,7 +894,9 @@ public class PrintJobConfigActivity extends Activity { final int selectedIndex = mDestinationSpinner.getSelectedItemPosition(); - if (selectedIndex < 0) { + if (selectedIndex < 0 || !mDestinationSpinnerAdapter.getItem( + selectedIndex).value.hasAllRequiredAttributes()) { + // Destination mDestinationSpinner.setEnabled(false); @@ -1173,6 +1183,45 @@ public class PrintJobConfigActivity extends Activity { } } + @SuppressWarnings("unchecked") + public void updatePrinters(List pritners) { + SpinnerItem selectedItem = + (SpinnerItem) mDestinationSpinner.getSelectedItem(); + PrinterId selectedPrinterId = (selectedItem != null) + ? selectedItem.value.getId() : null; + + boolean updated = false; + + final int printerCount = pritners.size(); + for (int i = 0; i < printerCount; i++) { + PrinterInfo updatedPrinter = pritners.get(i); + final int existingPrinterCount = mDestinationSpinnerAdapter.getCount(); + for (int j = 0; j < existingPrinterCount; j++) { + PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value; + if (updatedPrinter.getId().equals(existingPrinter.getId())) { + existingPrinter.copyFrom(updatedPrinter); + updated = true; + if (selectedPrinterId != null + && selectedPrinterId.equals(updatedPrinter.getId())) { + // The selected printer was updated. We simulate a fake + // selection to reuse the normal printer change handling. + mOnItemSelectedListener.onItemSelected(mDestinationSpinner, + mDestinationSpinner.getSelectedView(), + mDestinationSpinner.getSelectedItemPosition(), + mDestinationSpinner.getSelectedItemId()); + // TODO: This will reset the UI to the defaults for the + // printer. We may need to revisit this. + + } + break; + } + } + } + if (updated) { + mDestinationSpinnerAdapter.notifyDataSetChanged(); + } + } + private boolean hasErrors() { return mRangeEditText.getError() != null || mCopiesEditText.getError() != null; @@ -1240,8 +1289,9 @@ public class PrintJobConfigActivity extends Activity { } private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub { - private static final int MESSAGE_ADD_DICOVERED_PRINTERS = 1; - private static final int MESSAGE_REMOVE_DICOVERED_PRINTERS = 2; + private static final int MSG_ON_PRINTERS_ADDED = 1; + private static final int MSG_ON_PRINTERS_REMOVED = 2; + private static final int MSG_ON_PRINTERS_UPDATED = 3; private Handler mHandler; private Editor mEditor; @@ -1253,34 +1303,50 @@ public class PrintJobConfigActivity extends Activity { @Override public void handleMessage(Message message) { switch (message.what) { - case MESSAGE_ADD_DICOVERED_PRINTERS: { + case MSG_ON_PRINTERS_ADDED: { List printers = (List) message.obj; mEditor.addPrinters(printers); } break; - case MESSAGE_REMOVE_DICOVERED_PRINTERS: { + + case MSG_ON_PRINTERS_REMOVED: { List printerIds = (List) message.obj; mEditor.removePrinters(printerIds); } break; + + case MSG_ON_PRINTERS_UPDATED: { + List printers = (List) message.obj; + mEditor.updatePrinters(printers); + } break; } } }; } @Override - public void addDiscoveredPrinters(List printers) { + public void onPrintersAdded(List printers) { synchronized (this) { if (mHandler != null) { - mHandler.obtainMessage(MESSAGE_ADD_DICOVERED_PRINTERS, printers) + mHandler.obtainMessage(MSG_ON_PRINTERS_ADDED, printers) .sendToTarget(); } } } @Override - public void removeDiscoveredPrinters(List printers) { + public void onPrintersRemoved(List printers) { synchronized (this) { if (mHandler != null) { - mHandler.obtainMessage(MESSAGE_REMOVE_DICOVERED_PRINTERS, printers) + mHandler.obtainMessage(MSG_ON_PRINTERS_REMOVED, printers) + .sendToTarget(); + } + } + } + + @Override + public void onPrintersUpdated(List printers) { + synchronized (this) { + if (mHandler != null) { + mHandler.obtainMessage(MSG_ON_PRINTERS_UPDATED, printers) .sendToTarget(); } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java index cef4341f14b2e..870bfffda6216 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java @@ -118,19 +118,29 @@ public class PrintSpooler { } } + public void onReqeustUpdatePrinters(List printers) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mClient; + args.arg2 = printers; + mHandler.obtainMessage(MyHandler.MSG_REQUEST_UPDATE_PRINTERS, + args).sendToTarget(); + } + } + public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); args.arg1 = mClient; args.arg2 = observer; - mHandler.obtainMessage(MyHandler.MSG_ON_START_PRINTER_DISCOVERY, + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, args).sendToTarget(); } } public void stopPrinterDiscovery() { synchronized (mLock) { - mHandler.obtainMessage(MyHandler.MSG_ON_STOP_PRINTER_DISCOVERY, + mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY, mClient).sendToTarget(); } } @@ -265,7 +275,7 @@ public class PrintSpooler { SomeArgs args = SomeArgs.obtain(); args.arg1 = client; args.arg2 = new PrintJobInfo(printJob); - mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, + mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED, args).sendToTarget(); } } @@ -273,13 +283,13 @@ public class PrintSpooler { SomeArgs args = SomeArgs.obtain(); args.arg1 = client; args.arg2 = service; - mHandler.obtainMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, + mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, args).sendToTarget(); } } if (allPrintJobsHandled) { - mHandler.obtainMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED, + mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED, client).sendToTarget(); } } @@ -401,12 +411,12 @@ public class PrintSpooler { args.arg1 = mClient; args.arg2 = service; mHandler.obtainMessage( - MyHandler.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, + MyHandler.MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, args).sendToTarget(); } if (!hasActivePrintJobsLocked()) { - mHandler.obtainMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED, + mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED, mClient).sendToTarget(); } } break; @@ -415,7 +425,7 @@ public class PrintSpooler { SomeArgs args = SomeArgs.obtain(); args.arg1 = mClient; args.arg2 = new PrintJobInfo(printJob); - mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, + mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED, args).sendToTarget(); } break; } @@ -1056,20 +1066,22 @@ public class PrintSpooler { } private final class MyHandler extends Handler { - public static final int MSG_ON_START_PRINTER_DISCOVERY = 1; - public static final int MSG_ON_STOP_PRINTER_DISCOVERY = 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_START_PRINTER_DISCOVERY = 1; + public static final int MSG_STOP_PRINTER_DISCOVERY = 2; + public static final int MSG_PRINT_JOB_QUEUED = 3; + public static final int MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 4; + public static final int MSG_ALL_PRINT_JOBS_HANDLED = 5; + public static final int MSG_REQUEST_UPDATE_PRINTERS = 6; public MyHandler(Looper looper) { super(looper, null, false); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { switch (message.what) { - case MSG_ON_START_PRINTER_DISCOVERY: { + case MSG_START_PRINTER_DISCOVERY: { SomeArgs args = (SomeArgs) message.obj; IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1; IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg2; @@ -1083,7 +1095,7 @@ public class PrintSpooler { } } break; - case MSG_ON_STOP_PRINTER_DISCOVERY: { + case MSG_STOP_PRINTER_DISCOVERY: { IPrintSpoolerClient client = (IPrintSpoolerClient) message.obj; if (client != null) { try { @@ -1094,7 +1106,7 @@ public class PrintSpooler { } } break; - case MSG_ON_PRINT_JOB_QUEUED: { + case MSG_PRINT_JOB_QUEUED: { SomeArgs args = (SomeArgs) message.obj; IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1; PrintJobInfo printJob = (PrintJobInfo) args.arg2; @@ -1108,7 +1120,7 @@ public class PrintSpooler { } } break; - case MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: { + case MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: { SomeArgs args = (SomeArgs) message.obj; IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1; ComponentName service = (ComponentName) args.arg2; @@ -1117,12 +1129,13 @@ public class PrintSpooler { try { client.onAllPrintJobsForServiceHandled(service); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error notify for all print jobs per service handled.", re); + Slog.e(LOG_TAG, "Error notify for all print jobs per service" + + " handled.", re); } } } break; - case MSG_ON_ALL_PRINT_JOBS_HANDLED: { + case MSG_ALL_PRINT_JOBS_HANDLED: { final IPrintSpoolerClient client = (IPrintSpoolerClient) message.obj; // This has to run on the tread that is persisting the current state // since this call may result in the system unbinding from the spooler @@ -1140,6 +1153,18 @@ public class PrintSpooler { } }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); } break; + + case MSG_REQUEST_UPDATE_PRINTERS: { + SomeArgs args = (SomeArgs) message.obj; + IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1; + List printerIds = (List) args.arg2; + args.recycle(); + try { + client.onRequestUpdatePrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting to update pritners.", re); + } + } break; } } } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index a8f856650e6cd..7acf6ab11576c 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -100,7 +100,7 @@ final class RemotePrintService implements DeathRecipient { } public void onAllPrintJobsHandled() { - mHandler.sendEmptyMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED); + mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); } @Override @@ -109,7 +109,7 @@ final class RemotePrintService implements DeathRecipient { } private void handleBinderDied() { - ensureBound(); + ensureUnbound(); } private void handleOnAllPrintJobsHandled() { @@ -124,7 +124,7 @@ final class RemotePrintService implements DeathRecipient { } public void onRequestCancelPrintJob(PrintJobInfo printJob) { - mHandler.obtainMessage(MyHandler.MSG_REQUEST_CANCEL_PRINT_JOB, + mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINT_JOB, printJob).sendToTarget(); } @@ -137,7 +137,7 @@ final class RemotePrintService implements DeathRecipient { Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnRequestCancelPrintJob()"); } try { - mPrintService.requestCancelPrintJob(printJob); + mPrintService.onRequestCancelPrintJob(printJob); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error canceling pring job.", re); } @@ -145,7 +145,7 @@ final class RemotePrintService implements DeathRecipient { } public void onPrintJobQueued(PrintJobInfo printJob) { - mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED, + mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, printJob).sendToTarget(); } @@ -172,7 +172,7 @@ final class RemotePrintService implements DeathRecipient { } public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) { - mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, observer).sendToTarget(); + mHandler.obtainMessage(MyHandler.MSG_ON_START_PRINTER_DISCOVERY, observer).sendToTarget(); } private void handleOnStartPrinterDiscovery(final IPrinterDiscoveryObserver observer) { @@ -190,7 +190,7 @@ final class RemotePrintService implements DeathRecipient { Slog.i(LOG_TAG, "[user: " + mUserId + "] onStartPrinterDiscovery()"); } try { - mPrintService.startPrinterDiscovery(observer); + mPrintService.onStartPrinterDiscovery(observer); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re); } @@ -198,7 +198,7 @@ final class RemotePrintService implements DeathRecipient { } public void onStopPrinterDiscovery() { - mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); + mHandler.sendEmptyMessage(MyHandler.MSG_ON_STOP_PRINTER_DISCOVERY); } private void handleStopPrinterDiscovery() { @@ -216,13 +216,40 @@ final class RemotePrintService implements DeathRecipient { Slog.i(LOG_TAG, "[user: " + mUserId + "] onStopPrinterDiscovery()"); } try { - mPrintService.stopPrinterDiscovery(); + mPrintService.onStopPrinterDiscovery(); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error announcing stop printer dicovery.", re); } } } + public void onRequestUpdatePrinters(List printerIds) { + mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_UPDATE_PRINTERS, + printerIds).sendToTarget(); + } + + private void handleReqeustUpdatePritners(final List printerIds) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleReqeustUpdatePritners(printerIds); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleReqeustUpdatePritners()"); + } + try { + mPrintService.onRequestUpdatePrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting to update printers.", re); + } + } + } + private boolean isBound() { return mPrintService != null; } @@ -254,6 +281,7 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { /* ignore */ } + mPrintService.asBinder().unlinkToDeath(this, 0); mPrintService = null; mContext.unbindService(mServiceConnection); } @@ -273,11 +301,17 @@ final class RemotePrintService implements DeathRecipient { } mBinding = false; mPrintService = IPrintService.Stub.asInterface(service); + try { + service.linkToDeath(RemotePrintService.this, 0); + } catch (RemoteException re) { + handleBinderDied(); + return; + } try { mPrintService.setClient(mPrintServiceClient); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error setting client for: " + service, re); - handleDestroy(); + handleBinderDied(); return; } final int pendingCommandCount = mPendingCommands.size(); @@ -294,42 +328,49 @@ final class RemotePrintService implements DeathRecipient { } private final class MyHandler extends Handler { - public static final int MSG_ALL_PRINT_JOBS_HANDLED = 1; - public static final int MSG_REQUEST_CANCEL_PRINT_JOB = 2; - public static final int MSG_PRINT_JOB_QUEUED = 3; - public static final int MSG_START_PRINTER_DISCOVERY = 4; - public static final int MSG_STOP_PRINTER_DISCOVERY = 5; - public static final int MSG_DESTROY = 6; - public static final int MSG_BINDER_DIED = 7; + public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 1; + public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 2; + public static final int MSG_ON_PRINT_JOB_QUEUED = 3; + public static final int MSG_ON_START_PRINTER_DISCOVERY = 4; + public static final int MSG_ON_STOP_PRINTER_DISCOVERY = 5; + public static final int MSG_ON_REQUEST_UPDATE_PRINTERS = 6; + public static final int MSG_DESTROY = 7; + public static final int MSG_BINDER_DIED = 8; public MyHandler(Looper looper) { super(looper, null, false); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { switch (message.what) { - case MSG_ALL_PRINT_JOBS_HANDLED: { + case MSG_ON_ALL_PRINT_JOBS_HANDLED: { handleOnAllPrintJobsHandled(); } break; - case MSG_REQUEST_CANCEL_PRINT_JOB: { + case MSG_ON_REQUEST_CANCEL_PRINT_JOB: { PrintJobInfo printJob = (PrintJobInfo) message.obj; handleOnRequestCancelPrintJob(printJob); } break; - case MSG_PRINT_JOB_QUEUED: { + case MSG_ON_PRINT_JOB_QUEUED: { PrintJobInfo printJob = (PrintJobInfo) message.obj; handleOnPrintJobQueued(printJob); } break; - case MSG_START_PRINTER_DISCOVERY: { + case MSG_ON_START_PRINTER_DISCOVERY: { IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) message.obj; handleOnStartPrinterDiscovery(new SecurePrinterDiscoveryObserver( mComponentName, observer)); } break; - case MSG_STOP_PRINTER_DISCOVERY: { + case MSG_ON_REQUEST_UPDATE_PRINTERS: { + List printerIds = (List) message.obj; + handleReqeustUpdatePritners(printerIds); + } break; + + case MSG_ON_STOP_PRINTER_DISCOVERY: { handleStopPrinterDiscovery(); } break; @@ -436,22 +477,32 @@ final class RemotePrintService implements DeathRecipient { } @Override - public void addDiscoveredPrinters(List printers) { + public void onPrintersAdded(List printers) { throwIfPrinterIdsForPrinterInfoTampered(printers); try { - mDecoratedObsever.addDiscoveredPrinters(printers); + mDecoratedObsever.onPrintersAdded(printers); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to addDiscoveredPrinters", re); + Slog.e(LOG_TAG, "Error delegating to onPrintersAdded", re); } } @Override - public void removeDiscoveredPrinters(List printerIds) { + public void onPrintersUpdated(List printers) { + throwIfPrinterIdsForPrinterInfoTampered(printers); + try { + mDecoratedObsever.onPrintersUpdated(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error delegating to onPrintersUpdated.", re); + } + } + + @Override + public void onPrintersRemoved(List printerIds) { throwIfPrinterIdsTampered(printerIds); try { - mDecoratedObsever.removeDiscoveredPrinters(printerIds); + mDecoratedObsever.onPrintersRemoved(printerIds); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to removeDiscoveredPrinters", re); + Slog.e(LOG_TAG, "Error delegating to onPrintersRemoved", re); } } diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index ded410b25b5c1..fe5b0675413ac 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -35,6 +35,7 @@ import android.print.IPrintSpoolerClient; import android.print.IPrinterDiscoveryObserver; import android.print.PrintAttributes; import android.print.PrintJobInfo; +import android.print.PrinterId; import android.util.Slog; import android.util.TimedRemoteCaller; @@ -96,6 +97,7 @@ final class RemotePrintSpooler { public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer); public void onStopPrinterDiscovery(); public void onAllPrintJobsForServiceHandled(ComponentName printService); + public void onRequestUpdatePrinters(List printerIds); } public RemotePrintSpooler(Context context, int userId, @@ -662,7 +664,7 @@ final class RemotePrintSpooler { } @Override - public void onStopPrinterDiscovery() throws RemoteException { + public void onStopPrinterDiscovery() { RemotePrintSpooler spooler = mWeakSpooler.get(); if (spooler != null) { final long identity = Binder.clearCallingIdentity(); @@ -673,5 +675,18 @@ final class RemotePrintSpooler { } } } + + @Override + public void onRequestUpdatePrinters(List printerIds) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.onRequestUpdatePrinters(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } } } diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index 5cef4d3ceae70..c41f9b02056fd 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.print.IPrinterDiscoveryObserver; import android.print.PrintJobInfo; +import android.print.PrinterId; import android.printservice.PrintServiceInfo; import android.provider.Settings; import android.text.TextUtils; @@ -138,6 +139,21 @@ final class UserState implements PrintSpoolerCallbacks { } } + @Override + public void onRequestUpdatePrinters(List printerIds) { + final RemotePrintService service; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + service = mActiveServices.get(printerIds.get(0).getService()); + } + if (service != null) { + service.onRequestUpdatePrinters(printerIds); + } + } + public void updateIfNeededLocked() { throwIfDestroyedLocked(); if (readConfigurationLocked()) {