diff options
author | Svetoslav <svetoslavganov@google.com> | 2013-10-28 15:15:45 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-10-28 15:15:45 -0700 |
commit | cdc2280a6e1837d3813cb5eab9a11c4f4efe8dc9 (patch) | |
tree | d9e125703ce9dffdf29049b57c8ec96698a27b97 | |
parent | 128537f600e14c941656e648205987083f4096c3 (diff) | |
parent | 0298ebb2db5b7c24d68fd3817b11e2f887471d0c (diff) | |
download | frameworks_base-cdc2280a6e1837d3813cb5eab9a11c4f4efe8dc9.zip frameworks_base-cdc2280a6e1837d3813cb5eab9a11c4f4efe8dc9.tar.gz frameworks_base-cdc2280a6e1837d3813cb5eab9a11c4f4efe8dc9.tar.bz2 |
am 0298ebb2: am 60fb1e28: am 714ba345: Merge "Complete implementation of the advanced print options." into klp-dev
* commit '0298ebb2db5b7c24d68fd3817b11e2f887471d0c':
Complete implementation of the advanced print options.
14 files changed, 552 insertions, 116 deletions
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index c2f190d..63f94fe 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -16,6 +16,7 @@ package android.print; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -160,6 +161,9 @@ public final class PrintJobInfo implements Parcelable { /** Information about the printed document. */ private PrintDocumentInfo mDocumentInfo; + /** Advanced printer specific options. */ + private Bundle mAdvancedOptions; + /** Whether we are trying to cancel this print job. */ private boolean mCanceling; @@ -184,6 +188,7 @@ public final class PrintJobInfo implements Parcelable { mAttributes = other.mAttributes; mDocumentInfo = other.mDocumentInfo; mCanceling = other.mCanceling; + mAdvancedOptions = other.mAdvancedOptions; } private PrintJobInfo(Parcel parcel) { @@ -197,20 +202,17 @@ public final class PrintJobInfo implements Parcelable { mCreationTime = parcel.readLong(); mCopies = parcel.readInt(); mStateReason = parcel.readString(); - if (parcel.readInt() == 1) { - Parcelable[] parcelables = parcel.readParcelableArray(null); + Parcelable[] parcelables = parcel.readParcelableArray(null); + if (parcelables != null) { mPageRanges = new PageRange[parcelables.length]; for (int i = 0; i < parcelables.length; i++) { mPageRanges[i] = (PageRange) parcelables[i]; } } - if (parcel.readInt() == 1) { - mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() == 1) { - mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); - } + mAttributes = (PrintAttributes) parcel.readParcelable(null); + mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null); mCanceling = (parcel.readInt() == 1); + mAdvancedOptions = parcel.readBundle(); } /** @@ -521,6 +523,71 @@ public final class PrintJobInfo implements Parcelable { mCanceling = cancelling; } + /** + * Gets whether this job has a given advanced (printer specific) print + * option. + * + * @param key The option key. + * @return Whether the option is present. + * + * @hide + */ + public boolean hasAdvancedOption(String key) { + return mAdvancedOptions != null && mAdvancedOptions.containsKey(key); + } + + /** + * Gets the value of an advanced (printer specific) print option. + * + * @param key The option key. + * @return The option value. + * + * @hide + */ + public String getAdvancedStringOption(String key) { + if (mAdvancedOptions != null) { + return mAdvancedOptions.getString(key); + } + return null; + } + + /** + * Gets the value of an advanced (printer specific) print option. + * + * @param key The option key. + * @return The option value. + * + * @hide + */ + public int getAdvancedIntOption(String key) { + if (mAdvancedOptions != null) { + return mAdvancedOptions.getInt(key); + } + return 0; + } + + /** + * Gets the advanced options. + * + * @return The advanced options. + * + * @hide + */ + public Bundle getAdvancedOptions() { + return mAdvancedOptions; + } + + /** + * Sets the advanced options. + * + * @param options The advanced options. + * + * @hide + */ + public void setAdvancedOptions(Bundle options) { + mAdvancedOptions = options; + } + @Override public int describeContents() { return 0; @@ -538,25 +605,11 @@ public final class PrintJobInfo implements Parcelable { parcel.writeLong(mCreationTime); parcel.writeInt(mCopies); parcel.writeString(mStateReason); - if (mPageRanges != null) { - parcel.writeInt(1); - parcel.writeParcelableArray(mPageRanges, flags); - } else { - parcel.writeInt(0); - } - if (mAttributes != null) { - parcel.writeInt(1); - mAttributes.writeToParcel(parcel, flags); - } else { - parcel.writeInt(0); - } - if (mDocumentInfo != null) { - parcel.writeInt(1); - mDocumentInfo.writeToParcel(parcel, flags); - } else { - parcel.writeInt(0); - } + parcel.writeParcelableArray(mPageRanges, flags); + parcel.writeParcelable(mAttributes, flags); + parcel.writeParcelable(mDocumentInfo, 0); parcel.writeInt(mCanceling ? 1 : 0); + parcel.writeBundle(mAdvancedOptions); } @Override @@ -577,6 +630,7 @@ public final class PrintJobInfo implements Parcelable { builder.append(", cancelling: " + mCanceling); builder.append(", pages: " + (mPageRanges != null ? Arrays.toString(mPageRanges) : null)); + builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null)); builder.append("}"); return builder.toString(); } @@ -663,7 +717,10 @@ public final class PrintJobInfo implements Parcelable { * @param value The option value. */ public void putAdvancedOption(String key, String value) { - + if (mPrototype.mAdvancedOptions == null) { + mPrototype.mAdvancedOptions = new Bundle(); + } + mPrototype.mAdvancedOptions.putString(key, value); } /** @@ -673,7 +730,10 @@ public final class PrintJobInfo implements Parcelable { * @param value The option value. */ public void putAdvancedOption(String key, int value) { - + if (mPrototype.mAdvancedOptions == null) { + mPrototype.mAdvancedOptions = new Bundle(); + } + mPrototype.mAdvancedOptions.putInt(key, value); } /** diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java index fdeb373..6fa0bdd 100644 --- a/core/java/android/printservice/PrintJob.java +++ b/core/java/android/printservice/PrintJob.java @@ -321,7 +321,7 @@ public final class PrintJob { */ public String getAdvancedStringOption(String key) { PrintService.throwIfNotCalledOnMainThread(); - return null; + return getInfo().getAdvancedStringOption(key); } /** @@ -333,7 +333,7 @@ public final class PrintJob { */ public boolean hasAdvancedOption(String key) { PrintService.throwIfNotCalledOnMainThread(); - return false; + return getInfo().hasAdvancedOption(key); } /** @@ -344,7 +344,7 @@ public final class PrintJob { */ public int getAdvancedIntOption(String key) { PrintService.throwIfNotCalledOnMainThread(); - return 0; + return getInfo().getAdvancedIntOption(key); } @Override diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index 0fc5f7f..eb0ac2e 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -209,6 +209,14 @@ public abstract class PrintService extends Service { * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)} * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}. * </p> + * <p> + * If the advanced print options activity offers changes to the standard print + * options, you can get the current {@link android.print.PrinterInfo} using the + * "android.intent.extra.print.EXTRA_PRINTER_INFO" extra which will allow you to + * present the user with UI options supported by the current printer. For example, + * if the current printer does not support a give media size, you should not + * offer it in the advanced print options dialog. + * </p> */ public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO"; diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java index 8e9636c..a2c6c09 100644 --- a/core/java/android/printservice/PrintServiceInfo.java +++ b/core/java/android/printservice/PrintServiceInfo.java @@ -60,6 +60,8 @@ public final class PrintServiceInfo implements Parcelable { private final String mAddPrintersActivityName; + private final String mAdvancedPrintOptionsActivityName; + /** * Creates a new instance. * @@ -70,6 +72,7 @@ public final class PrintServiceInfo implements Parcelable { mResolveInfo = parcel.readParcelable(null); mSettingsActivityName = parcel.readString(); mAddPrintersActivityName = parcel.readString(); + mAdvancedPrintOptionsActivityName = parcel.readString(); } /** @@ -78,14 +81,16 @@ public final class PrintServiceInfo implements Parcelable { * @param resolveInfo The service resolve info. * @param settingsActivityName Optional settings activity name. * @param addPrintersActivityName Optional add printers activity name. + * @param advancedPrintOptionsActivityName Optional advanced print options activity. */ public PrintServiceInfo(ResolveInfo resolveInfo, String settingsActivityName, - String addPrintersActivityName) { + String addPrintersActivityName, String advancedPrintOptionsActivityName) { mId = new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name).flattenToString(); mResolveInfo = resolveInfo; mSettingsActivityName = settingsActivityName; mAddPrintersActivityName = addPrintersActivityName; + mAdvancedPrintOptionsActivityName = advancedPrintOptionsActivityName; } /** @@ -99,6 +104,7 @@ public final class PrintServiceInfo implements Parcelable { public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) { String settingsActivityName = null; String addPrintersActivityName = null; + String advancedPrintOptionsActivityName = null; XmlResourceParser parser = null; PackageManager packageManager = context.getPackageManager(); @@ -128,6 +134,9 @@ public final class PrintServiceInfo implements Parcelable { addPrintersActivityName = attributes.getString( com.android.internal.R.styleable.PrintService_addPrintersActivity); + advancedPrintOptionsActivityName = attributes.getString(com.android.internal + .R.styleable.PrintService_advancedPrintOptionsActivity); + attributes.recycle(); } } catch (IOException ioe) { @@ -144,7 +153,8 @@ public final class PrintServiceInfo implements Parcelable { } } - return new PrintServiceInfo(resolveInfo, settingsActivityName, addPrintersActivityName); + return new PrintServiceInfo(resolveInfo, settingsActivityName, + addPrintersActivityName, advancedPrintOptionsActivityName); } /** @@ -195,6 +205,19 @@ public final class PrintServiceInfo implements Parcelable { } /** + * The advanced print options activity name. + * <p> + * <strong>Statically set from + * {@link PrintService#SERVICE_META_DATA meta-data}.</strong> + * </p> + * + * @return The advanced print options activity name. + */ + public String getAdvancedOptionsActivityName() { + return mAdvancedPrintOptionsActivityName; + } + + /** * {@inheritDoc} */ public int describeContents() { @@ -206,6 +229,7 @@ public final class PrintServiceInfo implements Parcelable { parcel.writeParcelable(mResolveInfo, 0); parcel.writeString(mSettingsActivityName); parcel.writeString(mAddPrintersActivityName); + parcel.writeString(mAdvancedPrintOptionsActivityName); } @Override @@ -243,6 +267,8 @@ public final class PrintServiceInfo implements Parcelable { builder.append(", resolveInfo=").append(mResolveInfo); builder.append(", settingsActivityName=").append(mSettingsActivityName); builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName); + builder.append(", advancedPrintOptionsActivityName=") + .append(mAdvancedPrintOptionsActivityName); builder.append("}"); return builder.toString(); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9dcefee..a337098 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2636,7 +2636,11 @@ add printers to this print service. --> <attr name="addPrintersActivity" format="string"/> <!-- Fully qualified class name of an activity with advanced print options - specific to this print service. --> + specific to this print service. If this activity is specified the system + will allow the user a choice to open it given the currently selected printer + has advanced options which is specified by the print service via + {@link android.print.PrinterInfo.Builder#setHasAdvancedOptions(boolean)}. + --> <attr name="advancedPrintOptionsActivity" format="string"/> <!-- The vendor name if this print service is vendor specific. --> <attr name="vendor" format="string"/> diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml index d503216..3303ef1 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml @@ -16,7 +16,7 @@ <com.android.printspooler.PrintDialogFrame xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" - android:layout_height="fill_parent"> + android:layout_height="wrap_content"> <FrameLayout android:id="@+id/content_container" android:layout_width="fill_parent" diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml index 02740a3..e50a7af 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml @@ -18,8 +18,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:scrollbars="vertical" - android:background="@color/editable_background"> + android:scrollbars="vertical"> <LinearLayout android:layout_width="fill_parent" @@ -42,6 +41,7 @@ <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" + android:layout_marginBottom="24dip" android:orientation="horizontal" android:baselineAligned="false"> @@ -203,27 +203,79 @@ </LinearLayout> + <!-- Advanced settings button --> + + <LinearLayout + android:id="@+id/advanced_settings_container" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:visibility="gone"> + + <ImageView + android:layout_width="fill_parent" + android:layout_height="1dip" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" + android:layout_gravity="fill_horizontal" + android:background="@color/separator" + android:contentDescription="@null"> + </ImageView> + + <Button + android:id="@+id/advanced_settings_button" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" + android:layout_gravity="fill_horizontal" + android:text="@string/advanced_settings_button" + android:gravity="start|center_vertical" + android:textSize="16sp" + android:textColor="@color/item_text_color"> + </Button> + + <ImageView + android:layout_width="fill_parent" + android:layout_height="1dip" + android:layout_gravity="fill_horizontal" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" + android:background="@color/separator" + android:contentDescription="@null"> + </ImageView> + + </LinearLayout> + <!-- Print button --> - <ImageView + <FrameLayout android:layout_width="fill_parent" - android:layout_height="1dip" + android:layout_height="wrap_content" android:layout_marginTop="24dip" - android:layout_gravity="fill_horizontal" - android:background="@color/separator" - android:contentDescription="@null"> - </ImageView> + android:background="@color/action_button_background"> + + <ImageView + android:layout_width="fill_parent" + android:layout_height="1dip" + android:layout_gravity="fill_horizontal" + android:background="@color/separator" + android:contentDescription="@null"> + </ImageView> + + <Button + android:id="@+id/print_button" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_horizontal" + android:text="@string/print_button" + android:textSize="16sp" + android:textColor="@color/item_text_color"> + </Button> - <Button - android:id="@+id/print_button" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_gravity="fill_horizontal" - android:text="@string/print_button" - android:textSize="16sp" - android:textColor="@color/item_text_color"> - </Button> + </FrameLayout> </LinearLayout> diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml index 222b5b6..f573d9d 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml @@ -23,7 +23,6 @@ <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@color/editable_background" android:orientation="vertical"> <TextView @@ -43,23 +42,30 @@ android:textSize="16sp"> </TextView> + </LinearLayout> + + <FrameLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="@color/action_button_background"> + <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="@color/separator"> </View> - </LinearLayout> + <Button + android:id="@+id/ok_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_horizontal" + style="?android:attr/buttonBarButtonStyle" + android:text="@android:string/ok" + android:textSize="16sp" + android:textColor="@color/important_text"> + </Button> - <Button - android:id="@+id/ok_button" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_gravity="fill_horizontal" - style="?android:attr/buttonBarButtonStyle" - android:text="@android:string/ok" - android:textSize="16sp" - android:textColor="@color/important_text"> - </Button> + </FrameLayout> </LinearLayout> diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml index 8bdb6c9..10602ee 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml @@ -23,7 +23,6 @@ <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@color/editable_background" android:orientation="vertical"> <TextView @@ -51,23 +50,30 @@ style="?android:attr/progressBarStyleLarge"> </ProgressBar> + </LinearLayout> + + <FrameLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="@color/action_button_background"> + <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="@color/separator"> </View> - </LinearLayout> + <Button + android:id="@+id/cancel_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_horizontal" + style="?android:attr/buttonBarButtonStyle" + android:text="@string/cancel" + android:textSize="16sp" + android:textColor="@color/important_text"> + </Button> - <Button - android:id="@+id/cancel_button" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_gravity="fill_horizontal" - style="?android:attr/buttonBarButtonStyle" - android:text="@string/cancel" - android:textSize="16sp" - android:textColor="@color/important_text"> - </Button> + </FrameLayout> </LinearLayout> diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml index 9972c96..4fc25b3 100644 --- a/packages/PrintSpooler/res/values/colors.xml +++ b/packages/PrintSpooler/res/values/colors.xml @@ -16,10 +16,10 @@ <resources> - <color name="container_background">#FFFFFF</color> + <color name="container_background">#F2F2F2</color> <color name="important_text">#333333</color> <color name="print_option_title">#888888</color> <color name="separator">#CCCCCC</color> - <color name="editable_background">#F2F2F2</color> + <color name="action_button_background">#FFFFFF</color> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index d74b414..f2e768a 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -19,6 +19,9 @@ <!-- Title of the PrintSpooler application. [CHAR LIMIT=50] --> <string name="app_label">Print Spooler</string> + <!-- Label of the print dialog's button for advanced printer settings. [CHAR LIMIT=25] --> + <string name="advanced_settings_button">Printer settings</string> + <!-- Label of the print dialog's print button. [CHAR LIMIT=16] --> <string name="print_button">Print</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index db3770e..8f26361 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -19,6 +19,7 @@ package com.android.printspooler; import android.app.Activity; import android.app.Dialog; import android.app.LoaderManager; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -26,6 +27,8 @@ import android.content.Loader; import android.content.ServiceConnection; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -55,6 +58,8 @@ import android.print.PrintManager; import android.print.PrinterCapabilitiesInfo; import android.print.PrinterId; import android.print.PrinterInfo; +import android.printservice.PrintService; +import android.printservice.PrintServiceInfo; import android.provider.DocumentsContract; import android.text.Editable; import android.text.TextUtils; @@ -130,6 +135,7 @@ public class PrintJobConfigActivity extends Activity { private static final int ACTIVITY_REQUEST_CREATE_FILE = 1; private static final int ACTIVITY_REQUEST_SELECT_PRINTER = 2; + private static final int ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS = 3; private static final int CONTROLLER_STATE_FINISHED = 1; private static final int CONTROLLER_STATE_FAILED = 2; @@ -254,28 +260,27 @@ public class PrintJobConfigActivity extends Activity { } @Override - protected void onDestroy() { - // We can safely do the work in here since at this point - // the system is bound to our (spooler) process which - // guarantees that this process will not be killed. - if (mController != null && mController.hasStarted()) { - mController.finish(); - } - if (mEditor != null && mEditor.isPrintConfirmed() - && mController != null && mController.isFinished()) { - mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId, - PrintJobInfo.STATE_QUEUED, null); - } else { - mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId, - PrintJobInfo.STATE_CANCELED, null); - } - if (mGeneratingPrintJobDialog != null) { - mGeneratingPrintJobDialog.dismiss(); - mGeneratingPrintJobDialog = null; - } - mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0); - mSpoolerProvider.destroy(); - super.onDestroy(); + public void onPause() { + if (isFinishing()) { + if (mController != null && mController.hasStarted()) { + mController.finish(); + } + if (mEditor != null && mEditor.isPrintConfirmed() + && mController != null && mController.isFinished()) { + mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId, + PrintJobInfo.STATE_QUEUED, null); + } else { + mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId, + PrintJobInfo.STATE_CANCELED, null); + } + if (mGeneratingPrintJobDialog != null) { + mGeneratingPrintJobDialog.dismiss(); + mGeneratingPrintJobDialog = null; + } + mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0); + mSpoolerProvider.destroy(); + } + super.onPause(); } public boolean onTouchEvent(MotionEvent event) { @@ -607,18 +612,14 @@ public class PrintJobConfigActivity extends Activity { } else { // We did not get the pages we requested, then the application // misbehaves, so we fail quickly. - // TODO: We need some UI for announcing an error. mControllerState = CONTROLLER_STATE_FAILED; Log.e(LOG_TAG, "Received invalid pages from the app"); - mEditor.cancel(); - PrintJobConfigActivity.this.finish(); + mEditor.showUi(Editor.UI_ERROR, null); } } private void requestCreatePdfFileOrFinish() { if (mEditor.isPrintingToPdf()) { - PrintJobInfo printJob = mSpoolerProvider.getSpooler() - .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY); Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.setType("application/pdf"); intent.putExtra(Intent.EXTRA_TITLE, mDocument.info.getName()); @@ -791,6 +792,19 @@ public class PrintJobConfigActivity extends Activity { } mEditor.ensureCurrentPrinterSelected(); } break; + + case ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS: { + if (resultCode == RESULT_OK) { + PrintJobInfo printJobInfo = (PrintJobInfo) data.getParcelableExtra( + PrintService.EXTRA_PRINT_JOB_INFO); + if (printJobInfo != null) { + mEditor.updateFromAdvancedOptions(printJobInfo); + break; + } + } + mEditor.cancel(); + PrintJobConfigActivity.this.finish(); + } break; } } @@ -869,6 +883,10 @@ public class PrintJobConfigActivity extends Activity { private View mContentContainer; + private View mAdvancedPrintOptionsContainer; + + private Button mAdvancedOptionsButton; + private Button mPrintButton; private PrinterId mNextPrinterId; @@ -932,6 +950,10 @@ public class PrintJobConfigActivity extends Activity { refreshCurrentPrinter(); } } else if (spinner == mMediaSizeSpinner) { + if (mIgnoreNextMediaSizeChange) { + mIgnoreNextMediaSizeChange = false; + return; + } if (mOldMediaSizeSelectionIndex == mMediaSizeSpinner.getSelectedItemPosition()) { mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION; @@ -947,6 +969,10 @@ public class PrintJobConfigActivity extends Activity { mController.update(); } } else if (spinner == mColorModeSpinner) { + if (mIgnoreNextColorChange) { + mIgnoreNextColorChange = false; + return; + } if (mOldColorModeSelectionIndex == mColorModeSpinner.getSelectedItemPosition()) { mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION; @@ -1193,6 +1219,16 @@ public class PrintJobConfigActivity extends Activity { // greater than the to page. When computing the requested pages // we just swap them if necessary. + // Keep the print job up to date with the selected pages if we + // know how many pages are there in the document. + PageRange[] requestedPages = getRequestedPages(); + if (requestedPages != null && requestedPages.length > 0 + && requestedPages[requestedPages.length - 1].getEnd() + < mDocument.info.getPageCount()) { + mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence( + mPrintJobId, requestedPages); + } + mPageRangeEditText.setError(null); mPrintButton.setEnabled(true); updateUi(); @@ -1215,6 +1251,8 @@ public class PrintJobConfigActivity extends Activity { private boolean mIgnoreNextRangeOptionChange; private boolean mIgnoreNextCopiesChange; private boolean mIgnoreNextRangeChange; + private boolean mIgnoreNextMediaSizeChange; + private boolean mIgnoreNextColorChange; private int mCurrentUi = UI_NONE; @@ -1424,6 +1462,88 @@ public class PrintJobConfigActivity extends Activity { } } + public void updateFromAdvancedOptions(PrintJobInfo printJobInfo) { + boolean updateContent = false; + + // Copies. + mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies())); + + // Media size and orientation + PrintAttributes attributes = printJobInfo.getAttributes(); + if (!mCurrPrintAttributes.getMediaSize().equals(attributes.getMediaSize())) { + final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount(); + for (int i = 0; i < mediaSizeCount; i++) { + MediaSize mediaSize = mMediaSizeSpinnerAdapter.getItem(i).value; + if (mediaSize.asPortrait().equals(attributes.getMediaSize().asPortrait())) { + updateContent = true; + mCurrPrintAttributes.setMediaSize(attributes.getMediaSize()); + mMediaSizeSpinner.setSelection(i); + mIgnoreNextMediaSizeChange = true; + if (attributes.getMediaSize().isPortrait()) { + mOrientationSpinner.setSelection(0); + mIgnoreNextOrientationChange = true; + } else { + mOrientationSpinner.setSelection(1); + mIgnoreNextOrientationChange = true; + } + break; + } + } + } + + // Color mode. + final int colorMode = attributes.getColorMode(); + if (mCurrPrintAttributes.getColorMode() != colorMode) { + if (colorMode == PrintAttributes.COLOR_MODE_MONOCHROME) { + updateContent = true; + mColorModeSpinner.setSelection(0); + mIgnoreNextColorChange = true; + mCurrPrintAttributes.setColorMode(attributes.getColorMode()); + } else if (colorMode == PrintAttributes.COLOR_MODE_COLOR) { + updateContent = true; + mColorModeSpinner.setSelection(1); + mIgnoreNextColorChange = true; + mCurrPrintAttributes.setColorMode(attributes.getColorMode()); + } + } + + // Range. + PageRange[] pageRanges = printJobInfo.getPages(); + if (pageRanges != null && pageRanges.length > 0) { + pageRanges = PageRangeUtils.normalize(pageRanges); + final int pageRangeCount = pageRanges.length; + if (pageRangeCount == 1 && pageRanges[0] == PageRange.ALL_PAGES) { + mRangeOptionsSpinner.setSelection(0); + } else { + final int pageCount = mDocument.info.getPageCount(); + if (pageRanges[0].getStart() >= 0 + && pageRanges[pageRanges.length - 1].getEnd() < pageCount) { + mRangeOptionsSpinner.setSelection(1); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < pageRangeCount; i++) { + if (builder.length() > 0) { + builder.append(','); + } + PageRange pageRange = pageRanges[i]; + builder.append(pageRange.getStart()); + builder.append('-'); + builder.append(pageRange.getEnd()); + } + mPageRangeEditText.setText(builder.toString()); + } + } + } + + // Update the advanced options. + mSpoolerProvider.getSpooler().setPrintJobAdvancedOptionsNoPersistence( + mPrintJobId, printJobInfo.getAdvancedOptions()); + + // Update the content if needed. + if (updateContent) { + mController.update(); + } + } + public void ensurePrinterSelected(PrinterId printerId) { // If the printer is not present maybe the loader is not // updated yet. In this case make a note and as soon as @@ -1609,6 +1729,44 @@ public class PrintJobConfigActivity extends Activity { } } + private void registerAdvancedPrintOptionsButtonClickListener() { + Button advancedOptionsButton = (Button) findViewById(R.id.advanced_settings_button); + advancedOptionsButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + ComponentName serviceName = mCurrentPrinter.getId().getServiceName(); + String activityName = getAdvancedOptionsActivityName(serviceName); + if (TextUtils.isEmpty(activityName)) { + return; + } + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(new ComponentName(serviceName.getPackageName(), + activityName)); + + List<ResolveInfo> resolvedActivities = getPackageManager() + .queryIntentActivities(intent, 0); + if (resolvedActivities.isEmpty()) { + return; + } + // The activity is a component name, therefore it is one or none. + if (resolvedActivities.get(0).activityInfo.exported) { + PrintJobInfo printJobInfo = mSpoolerProvider.getSpooler().getPrintJobInfo( + mPrintJobId, PrintManager.APP_ID_ANY); + intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, printJobInfo); + // TODO: Make this an API for the next release. + intent.putExtra("android.intent.extra.print.EXTRA_PRINTER_INFO", + mCurrentPrinter); + try { + startActivityForResult(intent, + ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS); + } catch (ActivityNotFoundException anfe) { + Log.e(LOG_TAG, "Error starting activity for intent: " + intent, anfe); + } + } + } + }); + } + private void registerPrintButtonClickListener() { Button printButton = (Button) findViewById(R.id.print_button); printButton.setOnClickListener(new OnClickListener() { @@ -1656,6 +1814,9 @@ public class PrintJobConfigActivity extends Activity { mEditor.initialize(); mEditor.bindUi(); mEditor.reselectCurrentPrinter(); + if (!mController.hasPerformedLayout()) { + mController.update(); + } } }); } @@ -1857,6 +2018,11 @@ public class PrintJobConfigActivity extends Activity { mPageRangeEditText.setOnFocusChangeListener(mFocusListener); mPageRangeEditText.addTextChangedListener(mRangeTextWatcher); + // Advanced options button. + mAdvancedPrintOptionsContainer = findViewById(R.id.advanced_settings_container); + mAdvancedOptionsButton = (Button) findViewById(R.id.advanced_settings_button); + registerAdvancedPrintOptionsButtonClickListener(); + // Print button mPrintButton = (Button) findViewById(R.id.print_button); registerPrintButtonClickListener(); @@ -1875,6 +2041,7 @@ public class PrintJobConfigActivity extends Activity { mRangeOptionsSpinner.setEnabled(false); mPageRangeEditText.setEnabled(false); mPrintButton.setEnabled(false); + mAdvancedOptionsButton.setEnabled(false); return false; } @@ -1900,6 +2067,7 @@ public class PrintJobConfigActivity extends Activity { mRangeOptionsSpinner.setEnabled(false); mPageRangeEditText.setEnabled(false); mPrintButton.setEnabled(false); + mAdvancedOptionsButton.setEnabled(false); return false; } else { boolean someAttributeSelectionChanged = false; @@ -2077,7 +2245,17 @@ public class PrintJobConfigActivity extends Activity { mPageRangeTitle.setVisibility(View.INVISIBLE); } - // Print/Print preview + // Advanced print options + ComponentName serviceName = mCurrentPrinter.getId().getServiceName(); + if (!TextUtils.isEmpty(getAdvancedOptionsActivityName(serviceName))) { + mAdvancedPrintOptionsContainer.setVisibility(View.VISIBLE); + mAdvancedOptionsButton.setEnabled(true); + } else { + mAdvancedPrintOptionsContainer.setVisibility(View.GONE); + mAdvancedOptionsButton.setEnabled(false); + } + + // Print if (mDestinationSpinner.getSelectedItemId() != DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF) { String newText = getString(R.string.print_button); @@ -2117,6 +2295,21 @@ public class PrintJobConfigActivity extends Activity { } } + private String getAdvancedOptionsActivityName(ComponentName serviceName) { + PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); + List<PrintServiceInfo> printServices = printManager.getEnabledPrintServices(); + final int printServiceCount = printServices.size(); + for (int i = 0; i < printServiceCount; i ++) { + PrintServiceInfo printServiceInfo = printServices.get(i); + ServiceInfo serviceInfo = printServiceInfo.getResolveInfo().serviceInfo; + if (serviceInfo.name.equals(serviceName.getClassName()) + && serviceInfo.packageName.equals(serviceName.getPackageName())) { + return printServiceInfo.getAdvancedOptionsActivityName(); + } + } + return null; + } + private void setMediaSizeSpinnerSelectionNoCallback(int position) { if (mMediaSizeSpinner.getSelectedItemPosition() != position) { mOldMediaSizeSelectionIndex = position; diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index 636e245..609ae64 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -20,6 +20,7 @@ import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.os.AsyncTask; +import android.os.Bundle; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -623,6 +624,16 @@ public final class PrintSpoolerService extends Service { } } + public void setPrintJobAdvancedOptionsNoPersistence(PrintJobId printJobId, + Bundle advancedOptions) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setAdvancedOptions(advancedOptions); + } + } + } + public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId, PrintDocumentInfo info) { synchronized (mLock) { @@ -704,6 +715,14 @@ public final class PrintSpoolerService extends Service { private static final String ATTR_STATE_REASON = "stateReason"; private static final String ATTR_CANCELLING = "cancelling"; + private static final String TAG_ADVANCED_OPTIONS = "advancedOptions"; + private static final String TAG_ADVANCED_OPTION = "advancedOption"; + private static final String ATTR_KEY = "key"; + private static final String ATTR_TYPE = "type"; + private static final String ATTR_VALUE = "value"; + private static final String TYPE_STRING = "string"; + private static final String TYPE_INT = "int"; + private static final String TAG_MEDIA_SIZE = "mediaSize"; private static final String TAG_RESOLUTION = "resolution"; private static final String TAG_MARGINS = "margins"; @@ -899,6 +918,30 @@ public final class PrintSpoolerService extends Service { serializer.endTag(null, TAG_DOCUMENT_INFO); } + Bundle advancedOptions = printJob.getAdvancedOptions(); + if (advancedOptions != null) { + serializer.startTag(null, TAG_ADVANCED_OPTIONS); + for (String key : advancedOptions.keySet()) { + Object value = advancedOptions.get(key); + if (value instanceof String) { + String stringValue = (String) value; + serializer.startTag(null, TAG_ADVANCED_OPTION); + serializer.attribute(null, ATTR_KEY, key); + serializer.attribute(null, ATTR_TYPE, TYPE_STRING); + serializer.attribute(null, ATTR_VALUE, stringValue); + serializer.endTag(null, TAG_ADVANCED_OPTION); + } else if (value instanceof Integer) { + String intValue = Integer.toString((Integer) value); + serializer.startTag(null, TAG_ADVANCED_OPTION); + serializer.attribute(null, ATTR_KEY, key); + serializer.attribute(null, ATTR_TYPE, TYPE_INT); + serializer.attribute(null, ATTR_VALUE, intValue); + serializer.endTag(null, TAG_ADVANCED_OPTION); + } + } + serializer.endTag(null, TAG_ADVANCED_OPTIONS); + } + serializer.endTag(null, TAG_JOB); if (DEBUG_PERSISTENCE) { @@ -1027,6 +1070,7 @@ public final class PrintSpoolerService extends Service { skipEmptyTextTags(parser); expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE); parser.next(); + skipEmptyTextTags(parser); } if (pageRanges != null) { PageRange[] pageRangesArray = new PageRange[pageRanges.size()]; @@ -1057,8 +1101,8 @@ public final class PrintSpoolerService extends Service { final int labelResId = (labelResIdString != null) ? Integer.parseInt(labelResIdString) : 0; label = parser.getAttributeValue(null, ATTR_LABEL); - MediaSize mediaSize = new MediaSize(id, label, packageName, labelResId, - widthMils, heightMils); + MediaSize mediaSize = new MediaSize(id, label, packageName, + widthMils, heightMils, labelResId); builder.setMediaSize(mediaSize); parser.next(); skipEmptyTextTags(parser); @@ -1127,6 +1171,32 @@ public final class PrintSpoolerService extends Service { parser.next(); } + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTIONS)) { + parser.next(); + skipEmptyTextTags(parser); + Bundle advancedOptions = new Bundle(); + while (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTION)) { + String key = parser.getAttributeValue(null, ATTR_KEY); + String value = parser.getAttributeValue(null, ATTR_VALUE); + String type = parser.getAttributeValue(null, ATTR_TYPE); + if (TYPE_STRING.equals(type)) { + advancedOptions.putString(key, value); + } else if (TYPE_INT.equals(type)) { + advancedOptions.putInt(key, Integer.valueOf(value)); + } + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTION); + parser.next(); + skipEmptyTextTags(parser); + } + printJob.setAdvancedOptions(advancedOptions); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTIONS); + parser.next(); + } + mPrintJobs.add(printJob); if (DEBUG_PERSISTENCE) { diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index b69dcee..f23a992 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -231,10 +231,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { for (int i = 0; i < cachedPrintJobCount; i++) { PrintJobInfo cachedPrintJob = cachedPrintJobs.get(i); result.put(cachedPrintJob.getId(), cachedPrintJob); - // Strip out the tag - it is visible only to print services. - // Also the cached print jobs are delivered only to apps, so - // stripping the tag of a cached print job is fine. + // Strip out the tag and the advanced print options. + // They are visible only to print services. cachedPrintJob.setTag(null); + cachedPrintJob.setAdvancedOptions(null); } // Add everything else the spooler knows about. @@ -245,8 +245,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { for (int i = 0; i < printJobCount; i++) { PrintJobInfo printJob = printJobs.get(i); result.put(printJob.getId(), printJob); - // Strip out the tag - it is visible only to print services. + // Strip out the tag and the advanced print options. + // They are visible only to print services. printJob.setTag(null); + printJob.setAdvancedOptions(null); } } @@ -255,10 +257,16 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) { PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId); + if (printJob == null) { + printJob = mSpooler.getPrintJobInfo(printJobId, appId); + } if (printJob != null) { - return printJob; + // Strip out the tag and the advanced print options. + // They are visible only to print services. + printJob.setTag(null); + printJob.setAdvancedOptions(null); } - return mSpooler.getPrintJobInfo(printJobId, appId); + return printJob; } public void cancelPrintJob(PrintJobId printJobId, int appId) { |