Merge "Complete implementation of the advanced print options." into klp-dev

This commit is contained in:
Svetoslav
2013-10-28 22:07:03 +00:00
committed by Android (Google) Code Review
14 changed files with 554 additions and 118 deletions

View File

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

View File

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

View File

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

View File

@ -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);
}
/**
@ -194,6 +204,19 @@ public final class PrintServiceInfo implements Parcelable {
return mAddPrintersActivityName;
}
/**
* 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}
*/
@ -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();
}

View File

@ -2622,7 +2622,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"/>

View File

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

View File

@ -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
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="24dip"
android:layout_gravity="fill_horizontal"
android:background="@color/separator"
android:contentDescription="@null">
</ImageView>
<Button
android:id="@+id/print_button"
style="?android:attr/buttonBarButtonStyle"
<FrameLayout
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>
android:layout_marginTop="24dip"
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>
</FrameLayout>
</LinearLayout>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {
return printJob;
if (printJob == null) {
printJob = mSpooler.getPrintJobInfo(printJobId, appId);
}
return mSpooler.getPrintJobInfo(printJobId, appId);
if (printJob != null) {
// Strip out the tag and the advanced print options.
// They are visible only to print services.
printJob.setTag(null);
printJob.setAdvancedOptions(null);
}
return printJob;
}
public void cancelPrintJob(PrintJobId printJobId, int appId) {