summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav Ganov <svetoslavganov@google.com>2013-07-23 13:29:31 -0700
committerSvetoslav Ganov <svetoslavganov@google.com>2013-07-23 18:05:53 -0700
commit0d1daa50f6d180c57f92596501e2e5c0b5ef9997 (patch)
tree130ab8cf87d8762783a121c7e01f1fbd88f2a258
parent88d199130d44c6bacb383a7757e782cf97483c68 (diff)
downloadframeworks_base-0d1daa50f6d180c57f92596501e2e5c0b5ef9997.zip
frameworks_base-0d1daa50f6d180c57f92596501e2e5c0b5ef9997.tar.gz
frameworks_base-0d1daa50f6d180c57f92596501e2e5c0b5ef9997.tar.bz2
Updating the print dialog and its interactinos with the printing app.
1. Added support for reporting the old print attributes during layout. Now we keep track of the old print attributes, so the app can compute the delta and decide whether re-layout work is needed. 2. Fixed PrintDocumentAdapter callback interleavings. Layout callbacks were intermixing with write ones - a mess. Now we make an attempt to cancel layout and write if they respond to cancellation, otherwise we wait but do not interleave them. 3. Refactored the PrintJobConfigActivity for easier maintenance and to have a single update UI method that does the minimal amount of work. Change-Id: I31ada1a0550882e6185018e6f17f923aed165d15
-rw-r--r--core/java/android/print/PrintAttributes.java16
-rw-r--r--packages/PrintSpooler/res/layout/print_job_config_activity.xml441
-rw-r--r--packages/PrintSpooler/res/values/constants.xml4
-rw-r--r--packages/PrintSpooler/res/values/strings.xml10
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java1118
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java153
6 files changed, 1081 insertions, 661 deletions
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 65f1330..87d75c0 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -384,6 +384,22 @@ public final class PrintAttributes implements Parcelable {
}
/**
+ * @hide
+ */
+ public void copyFrom(PrintAttributes other) {
+ mMediaSize = other.mMediaSize;
+ mResolution = other.mResolution;
+ mMargins = other.mMargins;
+ mInputTray = other.mInputTray;
+ mOutputTray = other.mOutputTray;
+ mDuplexMode = other.mDuplexMode;
+ mColorMode = other.mColorMode;
+ mFittingMode = other.mFittingMode;
+ mOrientation = other.mOrientation;
+ mCopies = other.mCopies;
+ }
+
+ /**
* This class specifies a supported media size.
*/
public static final class MediaSize {
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
index 8736bdd..32bc15a 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
@@ -5,7 +5,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,197 +14,264 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:scrollbars="vertical">
- <ScrollView
- android:layout_width="fill_parent"
+ <GridLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@*android:color/bright_foreground_disabled_holo_light">
+ android:orientation="vertical"
+ android:columnCount="2">
- <GridLayout
+ <!-- Destination -->
+
+ <Spinner
+ android:id="@+id/destination_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="0"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ </Spinner>
+
+ <!-- Copies -->
+
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/copies_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="2"
+ android:layout_column="0"
+ android:layout_gravity="bottom"
+ android:inputType="numberDecimal"
+ android:selectAllOnFocus="true"
+ android:minWidth="150dip">
+ </view>
+
+ <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="32dip"
- android:orientation="vertical"
- android:columnCount="2">
-
- <!-- Destination -->
-
- <Spinner
- android:id="@+id/destination_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="12dip"
- android:layout_row="0"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:minWidth="324dip"
- android:minHeight="?android:attr/listPreferredItemHeightSmall">
- </Spinner>
-
- <!-- Copies -->
-
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/copies_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="2"
- android:layout_column="0"
- android:layout_gravity="bottom"
- android:inputType="numberDecimal"
- android:selectAllOnFocus="true"
- android:minWidth="150dip">
- </view>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="1"
- android:layout_column="0"
- android:layout_gravity="left|bottom"
- android:text="@string/label_copies"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/copies_edittext">
- </TextView>
-
- <!-- Paper size -->
-
- <Spinner
- android:id="@+id/paper_size_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="2"
- android:layout_column="1"
- android:minWidth="150dip">
- </Spinner>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginTop="12dip"
- android:layout_row="1"
- android:layout_column="1"
- android:text="@string/label_paper_size"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/paper_size_spinner">
- </TextView>
-
- <!-- Color -->
-
- <Spinner
- android:id="@+id/color_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="4"
- android:layout_column="0"
- android:minWidth="150dip">
- </Spinner>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="3"
- android:layout_column="0"
- android:text="@string/label_color"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/color_spinner">
- </TextView>
-
- <!-- Orientation -->
-
- <Spinner
- android:id="@+id/orientation_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="4"
- android:layout_column="1"
- android:minWidth="150dip">
- </Spinner>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginTop="12dip"
- android:layout_row="3"
- android:layout_column="1"
- android:text="@string/label_orientation"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/orientation_spinner">
- </TextView>
-
- <!-- Pages -->
-
- <Spinner
- android:id="@+id/range_options_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="12dip"
- android:layout_row="6"
- android:layout_column="0"
- android:minWidth="150dip">
- </Spinner>
-
- <EditText
- android:id="@+id/page_range_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_row="6"
- android:layout_column="1"
- android:layout_gravity="bottom"
- android:selectAllOnFocus="true"
- android:minWidth="150dip"
- android:hint="@string/pages_range_example"
- android:inputType="textNoSuggestions"
- android:visibility="gone">
- </EditText>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="5"
- android:layout_column="0"
- android:text="@string/label_pages"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/range_options_spinner">
- </TextView>
-
- </GridLayout>
-
- </ScrollView>
-
- <Button
- android:id="@+id/print_button"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="0dip"
- android:text="@string/print_button"
- android:background="?android:attr/selectableItemBackground">
- </Button>
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="1"
+ android:layout_column="0"
+ android:layout_gravity="left|bottom"
+ android:text="@string/label_copies"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/copies_edittext">
+ </TextView>
+
+ <!-- Paper size -->
+
+ <Spinner
+ android:id="@+id/paper_size_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="2"
+ android:layout_column="1"
+ android:minWidth="150dip">
+ </Spinner>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_row="1"
+ android:layout_column="1"
+ android:text="@string/label_paper_size"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/paper_size_spinner">
+ </TextView>
+
+ <!-- Color -->
+
+ <Spinner
+ android:id="@+id/color_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="4"
+ android:layout_column="0"
+ android:minWidth="150dip">
+ </Spinner>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="3"
+ android:layout_column="0"
+ android:text="@string/label_color"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/color_spinner">
+ </TextView>
+
+ <!-- Orientation -->
+
+ <Spinner
+ android:id="@+id/orientation_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="4"
+ android:layout_column="1"
+ android:minWidth="150dip">
+ </Spinner>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="3"
+ android:layout_column="1"
+ android:text="@string/label_orientation"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/orientation_spinner">
+ </TextView>
+
+ <!-- Pages -->
+
+ <Spinner
+ android:id="@+id/range_options_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="6"
+ android:layout_column="0"
+ android:minWidth="150dip">
+ </Spinner>
+
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/page_range_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="6"
+ android:layout_column="1"
+ android:layout_gravity="bottom"
+ android:selectAllOnFocus="true"
+ android:minWidth="150dip"
+ android:hint="@string/pages_range_example"
+ android:inputType="textNoSuggestions"
+ android:visibility="gone">
+ </view>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="5"
+ android:layout_column="0"
+ android:text="@string/label_pages"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/range_options_spinner">
+ </TextView>
+
+ <!-- Print pereview -->
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="7"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <Button
+ android:id="@+id/print_preview_button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="8"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:text="@string/print_preview"
+ android:gravity="left|center_vertical"
+ android:background="?android:attr/selectableItemBackground">
+ </Button>
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="32dip"
+ android:layout_row="9"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_row="10"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <Button
+ android:id="@+id/print_button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_row="11"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:padding="0dip"
+ android:text="@string/print_button"
+ android:background="?android:attr/selectableItemBackground">
+ </Button>
+
+ </GridLayout>
-</LinearLayout>
+</ScrollView>
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index 7d2cdc3..96cdeb1 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -16,8 +16,8 @@
<resources>
- <integer name="page_option_value_all">1</integer>
- <integer name="page_option_value_page_range">2</integer>
+ <integer name="page_option_value_all">0</integer>
+ <integer name="page_option_value_page_range">1</integer>
<integer-array name="page_options_values" translatable="false">
<item>@integer/page_option_value_all</item>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index de6fb60..27540d7 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -43,8 +43,14 @@
<!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=15] -->
<string name="pages_range_example">e.g. 1&#8211;5, 8</string>
- <!-- Message to notify the user of entering invalid input. [CHAR LIMIT=25] -->
- <string name="invalid_input">Invalid input</string>
+ <!-- Title for the pring preview button .[CHAR LIMIT=30] -->
+ <string name="print_preview">Print preview</string>
+
+ <!-- Title for the pring preview button if there is no PDF viewer isntalled. [CHAR LIMIT=50] -->
+ <string name="install_for_print_preview">Install PDF viewer for preview</string>
+
+ <!-- Title of the message that the printing application crashed. [CHAR LIMIT=50] -->
+ <string name="printing_app_crashed">Printing app crashed</string>
<!-- Color mode labels. -->
<string-array name="color_mode_labels">
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 19f545d..1e1cc24 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -50,6 +51,7 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Choreographer;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -95,12 +97,18 @@ public class PrintJobConfigActivity extends Activity {
private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this);
+ private Handler mHandler;
+
+ private Editor mEditor;
+
private IPrinterDiscoveryObserver mPrinterDiscoveryObserver;
private int mAppId;
private int mPrintJobId;
- private PrintAttributes mPrintAttributes;
+ private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().create();
+ private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().create();
+ private final PrintAttributes mTempPrintAttributes = new PrintAttributes.Builder().create();
private RemotePrintDocumentAdapter mRemotePrintAdapter;
@@ -112,152 +120,6 @@ public class PrintJobConfigActivity extends Activity {
private PrintDocumentInfo mPrintDocumentInfo;
- // UI elements
-
- private EditText mCopiesEditText;
-
- private EditText mRangeEditText;
-
- private Spinner mDestinationSpinner;
- public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
-
- private Spinner mMediaSizeSpinner;
- public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
-
- private Spinner mColorModeSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
-
- private Spinner mOrientationSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
-
- private Spinner mRangeOptionsSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
-
- private Button mPrintButton;
-
- // TODO: Implement store/restore state.
-
- private final OnItemSelectedListener mOnItemSelectedListener =
- new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
- if (spinner == mDestinationSpinner) {
- updateUi();
- notifyPrintableStartIfNeeded();
- } else if (spinner == mMediaSizeSpinner) {
- SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
- mPrintAttributes.setMediaSize(mediaItem.value);
- updatePrintableContentIfNeeded();
- } else if (spinner == mColorModeSpinner) {
- SpinnerItem<Integer> colorModeItem =
- mColorModeSpinnerAdapter.getItem(position);
- mPrintAttributes.setColorMode(colorModeItem.value);
- } else if (spinner == mOrientationSpinner) {
- SpinnerItem<Integer> orientationItem =
- mOrientationSpinnerAdapter.getItem(position);
- mPrintAttributes.setOrientation(orientationItem.value);
- } else if (spinner == mRangeOptionsSpinner) {
- SpinnerItem<Integer> rangeOptionItem =
- mRangeOptionsSpinnerAdapter.getItem(position);
- if (rangeOptionItem.value == getResources().getInteger(
- R.integer.page_option_value_all)) {
- mRangeEditText.setVisibility(View.INVISIBLE);
- mRangeEditText.setEnabled(false);
- mRangeEditText.setText(null);
- mRangeEditText.setError(null);
- mPrintButton.setEnabled(true);
- } else if (rangeOptionItem.value == getResources().getInteger(
- R.integer.page_option_value_page_range)) {
- mRangeEditText.setVisibility(View.VISIBLE);
- mRangeEditText.setEnabled(true);
- mRangeEditText.requestFocus();
- mRangeEditText.setError(getString(R.string.invalid_input));
- InputMethodManager imm = (InputMethodManager)
- getSystemService(INPUT_METHOD_SERVICE);
- imm.showSoftInput(mRangeEditText, 0);
- }
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- /* do nothing*/
- }
- };
-
- private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- /* do nothing */
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- /* do nothing */
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- if (editable.length() == 0) {
- mCopiesEditText.setError(getString(R.string.invalid_input));
- mPrintButton.setEnabled(false);
- return;
- }
- final int copies = Integer.parseInt(editable.toString());
- if (copies < MIN_COPIES) {
- mCopiesEditText.setError(getString(R.string.invalid_input));
- mPrintButton.setEnabled(false);
- return;
- }
- mPrintAttributes.setCopies(copies);
- mPrintButton.setEnabled(true);
- }
- };
-
- private final TextWatcher mRangeTextWatcher = new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- /* do nothing */
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- /* do nothing */
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- String text = editable.toString();
-
- if (TextUtils.isEmpty(text)) {
- mRangeEditText.setError(getString(R.string.invalid_input));
- mPrintButton.setEnabled(false);
- return;
- }
-
- String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
- if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
- mRangeEditText.setError(getString(R.string.invalid_input));
- mPrintButton.setEnabled(false);
- return;
- }
-
- Matcher matcher = PATTERN_DIGITS.matcher(text);
- while (matcher.find()) {
- String numericString = text.substring(matcher.start(), matcher.end());
- final int pageIndex = Integer.parseInt(numericString);
- if (pageIndex < 1 || pageIndex > mPrintDocumentInfo.getPageCount()) {
- mRangeEditText.setError(getString(R.string.invalid_input));
- mPrintButton.setEnabled(false);
- return;
- }
- }
-
- mRangeEditText.setError(null);
- mPrintButton.setEnabled(true);
- }
- };
-
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
@Override
public void binderDied() {
@@ -266,207 +128,21 @@ public class PrintJobConfigActivity extends Activity {
};
@Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setContentView(R.layout.print_job_config_activity);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
- | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
-
- Bundle extras = getIntent().getExtras();
-
- mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
- if (mPrintJobId < 0) {
- throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
- }
-
- mAppId = extras.getInt(EXTRA_APP_ID, -1);
- if (mAppId < 0) {
- throw new IllegalArgumentException("Invalid app id: " + mAppId);
- }
-
- mPrintAttributes = getIntent().getParcelableExtra(EXTRA_ATTRIBUTES);
- if (mPrintAttributes == null) {
- mPrintAttributes = new PrintAttributes.Builder().create();
- }
-
- mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
- if (mIPrintDocumentAdapter == null) {
- throw new IllegalArgumentException("Printable cannot be null");
- }
- mRemotePrintAdapter = new RemotePrintDocumentAdapter(
- IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
- mPrintSpooler.generateFileForPrintJob(mPrintJobId));
-
- try {
- mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException re) {
- finish();
- }
-
- mPrinterDiscoveryObserver = new PrintDiscoveryObserver(getMainLooper());
-
- bindUi();
- }
-
- @Override
protected void onDestroy() {
mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
super.onDestroy();
}
- private void bindUi() {
- // Copies
- mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
- mCopiesEditText.setText(String.valueOf(MIN_COPIES));
- mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
-
- // Destination.
- mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
- mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(this,
- R.layout.spinner_dropdown_item) {
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- return getView(position, convertView, parent);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = getLayoutInflater().inflate(
- R.layout.spinner_dropdown_item, parent, false);
- }
-
- PrinterInfo printerInfo = getItem(position).value;
- TextView title = (TextView) convertView.findViewById(R.id.title);
- title.setText(printerInfo.getLabel());
-
- try {
- TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle);
- PackageManager pm = getPackageManager();
- PackageInfo packageInfo = pm.getPackageInfo(
- printerInfo.getId().getService().getPackageName(), 0);
- subtitle.setText(packageInfo.applicationInfo.loadLabel(pm));
- subtitle.setVisibility(View.VISIBLE);
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
-
- return convertView;
- }
- };
- mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
- mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
- // Media size.
- mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner);
- mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(this,
- R.layout.spinner_dropdown_item, R.id.title);
- mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
- mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
- // Color mode.
- mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner);
- mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
- R.layout.spinner_dropdown_item, R.id.title);
- mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
- mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
- // Orientation
- mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
- mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
- R.layout.spinner_dropdown_item, R.id.title);
- mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
- mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
- // Range
- mRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
- mRangeEditText.addTextChangedListener(mRangeTextWatcher);
-
- // Range options
- mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
- mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
- R.layout.spinner_dropdown_item, R.id.title);
- mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
- mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- final int[] rangeOptionsValues = getResources().getIntArray(
- R.array.page_options_values);
- String[] rangeOptionsLabels = getResources().getStringArray(
- R.array.page_options_labels);
- final int rangeOptionsCount = rangeOptionsLabels.length;
- for (int i = 0; i < rangeOptionsCount; i++) {
- mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>(
- rangeOptionsValues[i], rangeOptionsLabels[i]));
- }
- mRangeOptionsSpinner.setSelection(0);
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ setContentView(R.layout.print_job_config_activity);
- mPrintButton = (Button) findViewById(R.id.print_button);
- mPrintButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mPrintConfirmed = true;
- finish();
- }
- });
- }
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
+ | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
- private void updateUi() {
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value;
- printer.getDefaults(mPrintAttributes);
-
- // Copies.
- mCopiesEditText.setText(String.valueOf(
- Math.max(mPrintAttributes.getCopies(), MIN_COPIES)));
- mCopiesEditText.selectAll();
-
- // Media size.
- mMediaSizeSpinnerAdapter.clear();
- List<MediaSize> mediaSizes = printer.getMediaSizes();
- final int mediaSizeCount = mediaSizes.size();
- for (int i = 0; i < mediaSizeCount; i++) {
- MediaSize mediaSize = mediaSizes.get(i);
- mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
- mediaSize, mediaSize.getLabel()));
- }
- final int selectedMediaSizeIndex = mediaSizes.indexOf(
- mPrintAttributes.getMediaSize());
- mMediaSizeSpinner.setOnItemSelectedListener(null);
- mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
-
- // Color mode.
- final int colorModes = printer.getColorModes();
- mColorModeSpinnerAdapter.clear();
- String[] colorModeLabels = getResources().getStringArray(
- R.array.color_mode_labels);
- int remainingColorModes = colorModes;
- while (remainingColorModes != 0) {
- final int colorBitOffset = Integer.numberOfTrailingZeros(remainingColorModes);
- final int colorMode = 1 << colorBitOffset;
- remainingColorModes &= ~colorMode;
- mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
- colorModeLabels[colorBitOffset]));
- }
- final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
- (colorModes & mPrintAttributes.getColorMode()));
- mColorModeSpinner.setSelection(selectedColorModeIndex);
-
- // Orientation.
- final int orientations = printer.getOrientations();
- mOrientationSpinnerAdapter.clear();
- String[] orientationLabels = getResources().getStringArray(
- R.array.orientation_labels);
- int remainingOrientations = orientations;
- while (remainingOrientations != 0) {
- final int orientationBitOffset = Integer.numberOfTrailingZeros(remainingOrientations);
- final int orientation = 1 << orientationBitOffset;
- remainingOrientations &= ~orientation;
- mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(orientation,
- orientationLabels[orientationBitOffset]));
- }
- final int selectedOrientationIndex = Integer.numberOfTrailingZeros(
- (orientations & mPrintAttributes.getOrientation()));
- mOrientationSpinner.setSelection(selectedOrientationIndex);
+ mHandler = new MyHandler(Looper.getMainLooper());
+ mEditor = new Editor();
}
@Override
@@ -484,13 +160,12 @@ public class PrintJobConfigActivity extends Activity {
}
private void notifyPrintableStartIfNeeded() {
- if (mDestinationSpinner.getSelectedItemPosition() < 0
+ if (mEditor.getCurrentPrinter() == null
|| mStarted) {
return;
}
mStarted = true;
mRemotePrintAdapter.start();
- updatePrintableContentIfNeeded();
}
private void updatePrintableContentIfNeeded() {
@@ -498,43 +173,66 @@ public class PrintJobConfigActivity extends Activity {
return;
}
- // TODO: Implement old attributes tracking
- mPrintSpooler.setPrintJobAttributes(mPrintJobId, mPrintAttributes);
+ mPrintSpooler.setPrintJobAttributes(mPrintJobId, mCurrPrintAttributes);
+
+ mRemotePrintAdapter.cancel();
+ mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FINISHED);
+ mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FAILED);
// TODO: Implement setting the print preview attribute
- mRemotePrintAdapter.layout(new PrintAttributes.Builder().create(),
- mPrintAttributes, new LayoutResultCallback() {
+ mRemotePrintAdapter.layout(mOldPrintAttributes,
+ mCurrPrintAttributes, new LayoutResultCallback() {
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- mPrintDocumentInfo = info;
+ mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
+ 0, info).sendToTarget();
+ }
- // TODO: Handle the case of unchanged content
- mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info);
+ @Override
+ public void onLayoutFailed(CharSequence error) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
+ }
+ }, new Bundle());
+ }
- // TODO: Implement page selector.
- final List<PageRange> pages = new ArrayList<PageRange>();
- pages.add(PageRange.ALL_PAGES);
+ private void handleOnLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ mPrintDocumentInfo = info;
- mRemotePrintAdapter.write(pages, new WriteResultCallback() {
- @Override
- public void onWriteFinished(List<PageRange> pages) {
- updatePrintPreview(mRemotePrintAdapter.getFile());
- }
+ mEditor.updateUiIfNeeded();
- @Override
- public void onWriteFailed(CharSequence error) {
- Log.e(LOG_TAG, "Error write layout: " + error);
- finishActivity(Activity.RESULT_CANCELED);
- }
- });
+ // TODO: Handle the case of unchanged content
+ mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info);
+
+ // TODO: Implement page selector.
+ final List<PageRange> pages = new ArrayList<PageRange>();
+ pages.add(PageRange.ALL_PAGES);
+
+ mRemotePrintAdapter.write(pages, new WriteResultCallback() {
+ @Override
+ public void onWriteFinished(List<PageRange> pages) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
}
@Override
- public void onLayoutFailed(CharSequence error) {
- Log.e(LOG_TAG, "Error during layout: " + error);
- finishActivity(Activity.RESULT_CANCELED);
+ public void onWriteFailed(CharSequence error) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
}
- }, new Bundle());
+ });
+ }
+
+ private void handleOnLayoutFailed(CharSequence error) {
+ Log.e(LOG_TAG, "Error during layout: " + error);
+ finishActivity(Activity.RESULT_CANCELED);
+ }
+
+ private void handleOnWriteFinished(List<PageRange> pages) {
+ // TODO: Now we have to allow the preview button
+ mEditor.updatePrintPreview(mRemotePrintAdapter.getFile());
+ }
+
+ private void handleOnWriteFailed(CharSequence error) {
+ Log.e(LOG_TAG, "Error write layout: " + error);
+ finishActivity(Activity.RESULT_CANCELED);
}
private void notifyPrintableFinishIfNeeded() {
@@ -542,11 +240,14 @@ public class PrintJobConfigActivity extends Activity {
return;
}
- mRemotePrintAdapter.finish(!mPrintConfirmed);
+ if (!mPrintConfirmed) {
+ mRemotePrintAdapter.cancel();
+ }
+ mRemotePrintAdapter.finish();
+ PrinterInfo printer = mEditor.getCurrentPrinter();
// If canceled or no printer, nothing to do.
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (!mPrintConfirmed || selectedIndex < 0) {
+ if (!mPrintConfirmed || printer == null) {
// Update the print job's status.
mPrintSpooler.setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED);
@@ -554,10 +255,7 @@ public class PrintJobConfigActivity extends Activity {
}
// Update the print job's printer.
- SpinnerItem<PrinterInfo> printerItem =
- mDestinationSpinnerAdapter.getItem(selectedIndex);
- PrinterId printerId = printerItem.value.getId();
- mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId);
+ mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printer.getId());
// Update the print job's status.
mPrintSpooler.setPrintJobState(mPrintJobId,
@@ -574,50 +272,11 @@ public class PrintJobConfigActivity extends Activity {
}
}
- private void updatePrintPreview(File file) {
- // TODO: Implement
- }
-
- private void addPrinters(List<PrinterInfo> addedPrinters) {
- final int addedPrinterCount = addedPrinters.size();
- for (int i = 0; i < addedPrinterCount; i++) {
- PrinterInfo addedPrinter = addedPrinters.get(i);
- boolean duplicate = false;
- final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
- for (int j = 0; j < existingPrinterCount; j++) {
- PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
- if (addedPrinter.getId().equals(existingPrinter.getId())) {
- duplicate = true;
- break;
- }
- }
- if (!duplicate) {
- mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>(
- addedPrinter, addedPrinter.getLabel()));
- } else {
- Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter);
- }
- }
- }
-
- private void removePrinters(List<PrinterId> pritnerIds) {
- final int printerIdCount = pritnerIds.size();
- for (int i = 0; i < printerIdCount; i++) {
- PrinterId removedPrinterId = pritnerIds.get(i);
- boolean removed = false;
- final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
- for (int j = 0; j < existingPrinterCount; j++) {
- PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
- if (removedPrinterId.equals(existingPrinter.getId())) {
- mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j));
- removed = true;
- break;
- }
- }
- if (!removed) {
- Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId);
- }
- }
+ private boolean hasPdfViewer() {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setType("application/pdf");
+ return !getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
}
// Caution: Use this only for debugging
@@ -659,16 +318,11 @@ public class PrintJobConfigActivity extends Activity {
switch (message.what) {
case MESSAGE_ADD_DICOVERED_PRINTERS: {
List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
- addPrinters(printers);
- // Just added the first printer, so select it and start printing.
- if (mDestinationSpinnerAdapter.getCount() == 1) {
- mDestinationSpinner.setSelection(0);
- }
+ mEditor.addPrinters(printers);
} break;
case MESSAGE_REMOVE_DICOVERED_PRINTERS: {
List<PrinterId> printerIds = (List<PrinterId>) message.obj;
- removePrinters(printerIds);
- // TODO: Handle removing the last printer.
+ mEditor.removePrinters(printerIds);
} break;
}
}
@@ -725,6 +379,11 @@ public class PrintJobConfigActivity extends Activity {
return true;
}
+ @Override
+ public void setError(CharSequence error, Drawable icon) {
+ setCompoundDrawables(null, null, icon, null);
+ }
+
protected void onFocusChanged(boolean gainFocus, int direction,
Rect previouslyFocusedRect) {
if (!gainFocus) {
@@ -733,4 +392,611 @@ public class PrintJobConfigActivity extends Activity {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
}
+
+ private final class MyHandler extends Handler {
+ public static final int MSG_ON_LAYOUT_FINISHED = 1;
+ public static final int MSG_ON_LAYOUT_FAILED = 2;
+ public static final int MSG_ON_WRITE_FINISHED = 3;
+ public static final int MSG_ON_WRITE_FAILED = 4;
+
+ public MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ON_LAYOUT_FINISHED: {
+ PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
+ final boolean changed = (message.arg1 == 1);
+ handleOnLayoutFinished(info, changed);
+ } break;
+
+ case MSG_ON_LAYOUT_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ handleOnLayoutFailed(error);
+ } break;
+
+ case MSG_ON_WRITE_FINISHED: {
+ List<PageRange> pages = (List<PageRange>) message.obj;
+ handleOnWriteFinished(pages);
+ } break;
+
+ case MSG_ON_WRITE_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ handleOnWriteFailed(error);
+ } break;
+ }
+ }
+ }
+
+ private class Editor {
+ private EditText mCopiesEditText;
+
+ private EditText mRangeEditText;
+
+ private Spinner mDestinationSpinner;
+ public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
+
+ private Spinner mMediaSizeSpinner;
+ public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
+
+ private Spinner mColorModeSpinner;
+ public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
+
+ private Spinner mOrientationSpinner;
+ public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
+
+ private Spinner mRangeOptionsSpinner;
+ public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
+
+ private Button mPrintPreviewButton;
+
+ private Button mPrintButton;
+
+ private final OnItemSelectedListener mOnItemSelectedListener =
+ new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+ if (spinner == mDestinationSpinner) {
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ mCurrPrintAttributes.clear();
+ final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+ if (selectedIndex >= 0) {
+ mDestinationSpinnerAdapter.getItem(selectedIndex).value.getDefaults(
+ mCurrPrintAttributes);
+ }
+ updateUiIfNeeded();
+ notifyPrintableStartIfNeeded();
+ updatePrintableContentIfNeeded();
+ } else if (spinner == mMediaSizeSpinner) {
+ SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ mCurrPrintAttributes.setMediaSize(mediaItem.value);
+ updatePrintableContentIfNeeded();
+ } else if (spinner == mColorModeSpinner) {
+ SpinnerItem<Integer> colorModeItem =
+ mColorModeSpinnerAdapter.getItem(position);
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ mCurrPrintAttributes.setColorMode(colorModeItem.value);
+ updatePrintableContentIfNeeded();
+ } else if (spinner == mOrientationSpinner) {
+ SpinnerItem<Integer> orientationItem =
+ mOrientationSpinnerAdapter.getItem(position);
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ mCurrPrintAttributes.setOrientation(orientationItem.value);
+ updatePrintableContentIfNeeded();
+ } else if (spinner == mRangeOptionsSpinner) {
+ updateUiIfNeeded();
+ updatePrintableContentIfNeeded();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ /* do nothing*/
+ }
+ };
+
+ private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ /* do nothing */
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* do nothing */
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ if (editable.length() == 0) {
+ mCopiesEditText.setError("");
+ mPrintButton.setEnabled(false);
+ return;
+ }
+ final int copies = Integer.parseInt(editable.toString());
+ if (copies < MIN_COPIES) {
+ mCopiesEditText.setError("");
+ mPrintButton.setEnabled(false);
+ return;
+ }
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ mCurrPrintAttributes.setCopies(copies);
+ }
+ };
+
+ private final TextWatcher mRangeTextWatcher = new TextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ /* do nothing */
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* do nothing */
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ String text = editable.toString();
+
+ if (TextUtils.isEmpty(text)) {
+ mRangeEditText.setError("");
+ mPrintButton.setEnabled(false);
+ return;
+ }
+
+ String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
+ if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
+ mRangeEditText.setError("");
+ mPrintButton.setEnabled(false);
+ return;
+ }
+
+ Matcher matcher = PATTERN_DIGITS.matcher(text);
+ while (matcher.find()) {
+ String numericString = text.substring(matcher.start(), matcher.end());
+ final int pageIndex = Integer.parseInt(numericString);
+ if (pageIndex < 1 || pageIndex > mPrintDocumentInfo.getPageCount()) {
+ mRangeEditText.setError("");
+ mPrintButton.setEnabled(false);
+ return;
+ }
+ }
+
+ mRangeEditText.setError(null);
+ mPrintButton.setEnabled(true);
+ }
+ };
+
+ public Editor() {
+ Bundle extras = getIntent().getExtras();
+
+ mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
+ if (mPrintJobId < 0) {
+ throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+ }
+
+ mAppId = extras.getInt(EXTRA_APP_ID, -1);
+ if (mAppId < 0) {
+ throw new IllegalArgumentException("Invalid app id: " + mAppId);
+ }
+
+ PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_ATTRIBUTES);
+ if (attributes == null) {
+ mCurrPrintAttributes.copyFrom(attributes);
+ }
+
+ mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
+ if (mIPrintDocumentAdapter == null) {
+ throw new IllegalArgumentException("Printable cannot be null");
+ }
+ mRemotePrintAdapter = new RemotePrintDocumentAdapter(
+ IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
+ mPrintSpooler.generateFileForPrintJob(mPrintJobId));
+
+ try {
+ mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException re) {
+ finish();
+ }
+
+ mPrinterDiscoveryObserver = new PrintDiscoveryObserver(getMainLooper());
+
+ bindUi();
+ }
+
+ private void bindUi() {
+ // Copies
+ mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
+ mCopiesEditText.setText(String.valueOf(MIN_COPIES));
+ mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
+ mCopiesEditText.setText(String.valueOf(
+ Math.max(mCurrPrintAttributes.getCopies(), MIN_COPIES)));
+ mCopiesEditText.selectAll();
+
+ // Destination.
+ mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
+ mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(
+ PrintJobConfigActivity.this, R.layout.spinner_dropdown_item) {
+ @Override
+ public View getDropDownView(int position, View convertView,
+ ViewGroup parent) {
+ return getView(position, convertView, parent);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.spinner_dropdown_item, parent, false);
+ }
+
+ PrinterInfo printerInfo = getItem(position).value;
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ title.setText(printerInfo.getLabel());
+
+ try {
+ TextView subtitle = (TextView)
+ convertView.findViewById(R.id.subtitle);
+ PackageManager pm = getPackageManager();
+ PackageInfo packageInfo = pm.getPackageInfo(
+ printerInfo.getId().getService().getPackageName(), 0);
+ subtitle.setText(packageInfo.applicationInfo.loadLabel(pm));
+ subtitle.setVisibility(View.VISIBLE);
+ } catch (NameNotFoundException nnfe) {
+ /* ignore */
+ }
+
+ return convertView;
+ }
+ };
+ mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
+ mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+ // Media size.
+ mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner);
+ mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(
+ PrintJobConfigActivity.this,
+ R.layout.spinner_dropdown_item, R.id.title);
+ mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
+ mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+ // Color mode.
+ mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner);
+ mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+ PrintJobConfigActivity.this,
+ R.layout.spinner_dropdown_item, R.id.title);
+ mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
+ mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+ // Orientation
+ mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
+ mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+ PrintJobConfigActivity.this,
+ R.layout.spinner_dropdown_item, R.id.title);
+ mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
+ mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+ // Range
+ mRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+ mRangeEditText.addTextChangedListener(mRangeTextWatcher);
+
+ // Range options
+ mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
+ mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+ PrintJobConfigActivity.this,
+ R.layout.spinner_dropdown_item, R.id.title);
+ mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
+ mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ final int[] rangeOptionsValues = getResources().getIntArray(
+ R.array.page_options_values);
+ String[] rangeOptionsLabels = getResources().getStringArray(
+ R.array.page_options_labels);
+ final int rangeOptionsCount = rangeOptionsLabels.length;
+ for (int i = 0; i < rangeOptionsCount; i++) {
+ mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>(
+ rangeOptionsValues[i], rangeOptionsLabels[i]));
+ }
+ mRangeOptionsSpinner.setSelection(0);
+
+ mPrintPreviewButton = (Button) findViewById(R.id.print_preview_button);
+ mPrintPreviewButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO: Implement
+ }
+ });
+
+ mPrintButton = (Button) findViewById(R.id.print_button);
+ mPrintButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPrintConfirmed = true;
+ finish();
+ }
+ });
+ }
+
+ private void updateUiIfNeeded() {
+ final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+
+ if (selectedIndex < 0) {
+ // Destination
+ mDestinationSpinner.setEnabled(false);
+
+ // Copies
+ mCopiesEditText.setText("1");
+ mCopiesEditText.setEnabled(false);
+
+ // Media size
+ mMediaSizeSpinner.setOnItemSelectedListener(null);
+ mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
+ mMediaSizeSpinner.setEnabled(false);
+
+ // Color mode
+ mColorModeSpinner.setOnItemSelectedListener(null);
+ mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
+ mColorModeSpinner.setEnabled(false);
+
+ // Orientation
+ mOrientationSpinner.setOnItemSelectedListener(null);
+ mOrientationSpinner.setSelection(AdapterView.INVALID_POSITION);
+ mOrientationSpinner.setEnabled(false);
+
+ // Range
+ mRangeOptionsSpinner.setOnItemSelectedListener(null);
+ mRangeOptionsSpinner.setSelection(0);
+ mRangeOptionsSpinner.setEnabled(false);
+ mRangeEditText.setText("");
+ mRangeEditText.setEnabled(false);
+ mRangeEditText.setVisibility(View.INVISIBLE);
+
+ // Print preview
+ mPrintPreviewButton.setEnabled(false);
+ mPrintPreviewButton.setText(getString(R.string.print_preview));
+
+ // Print
+ mPrintButton.setEnabled(false);
+ } else {
+ PrintAttributes defaultAttributes = mTempPrintAttributes;
+ PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value;
+ printer.getDefaults(defaultAttributes);
+
+ // Destination
+ mDestinationSpinner.setEnabled(true);
+
+ // Copies
+ mCopiesEditText.setEnabled(true);
+
+ // Media size.
+ List<MediaSize> mediaSizes = printer.getMediaSizes();
+ boolean mediaSizesChanged = false;
+ final int mediaSizeCount = mediaSizes.size();
+ if (mediaSizeCount != mMediaSizeSpinnerAdapter.getCount()) {
+ mediaSizesChanged = true;
+ } else {
+ for (int i = 0; i < mediaSizeCount; i++) {
+ if (!mediaSizes.get(i).equals(mMediaSizeSpinnerAdapter.getItem(i).value)) {
+ mediaSizesChanged = true;
+ break;
+ }
+ }
+ }
+ if (mediaSizesChanged) {
+ mMediaSizeSpinnerAdapter.clear();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize mediaSize = mediaSizes.get(i);
+ mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
+ mediaSize, mediaSize.getLabel()));
+ }
+ if (mediaSizeCount > 0) {
+ mMediaSizeSpinner.setEnabled(true);
+ final int selectedMediaSizeIndex = Math.max(mediaSizes.indexOf(
+ defaultAttributes.getMediaSize()), 0);
+ mMediaSizeSpinner.setOnItemSelectedListener(null);
+ mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
+ }
+ }
+
+ // Color mode.
+ final int colorModes = printer.getColorModes();
+ boolean colorModesChanged = false;
+ if (Integer.bitCount(colorModes) != mColorModeSpinnerAdapter.getCount()) {
+ colorModesChanged = true;
+ } else {
+ int remainingColorModes = colorModes;
+ while (remainingColorModes != 0) {
+ final int colorBitOffset = Integer.numberOfTrailingZeros(
+ remainingColorModes);
+ final int colorMode = 1 << colorBitOffset;
+ remainingColorModes &= ~colorMode;
+ if (colorMode != mColorModeSpinnerAdapter.getItem(colorBitOffset).value) {
+ colorModesChanged = true;
+ break;
+ }
+ }
+ }
+ if (colorModesChanged) {
+ mColorModeSpinnerAdapter.clear();
+ String[] colorModeLabels = getResources().getStringArray(
+ R.array.color_mode_labels);
+ int remainingColorModes = colorModes;
+ while (remainingColorModes != 0) {
+ final int colorBitOffset = Integer.numberOfTrailingZeros(
+ remainingColorModes);
+ final int colorMode = 1 << colorBitOffset;
+ remainingColorModes &= ~colorMode;
+ mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
+ colorModeLabels[colorBitOffset]));
+ }
+ if (colorModes > 0) {
+ mColorModeSpinner.setEnabled(true);
+ final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
+ (colorModes & defaultAttributes.getColorMode()));
+ mColorModeSpinner.setOnItemSelectedListener(null);
+ mColorModeSpinner.setSelection(selectedColorModeIndex);
+ }
+ }
+
+ // Orientation.
+ final int orientations = printer.getOrientations();
+ boolean orientationsChanged = false;
+ if (Integer.bitCount(orientations) != mOrientationSpinnerAdapter.getCount()) {
+ orientationsChanged = true;
+ } else {
+ int remainingOrientations = orientations;
+ while (remainingOrientations != 0) {
+ final int orientationBitOffset = Integer.numberOfTrailingZeros(
+ remainingOrientations);
+ final int orientation = 1 << orientationBitOffset;
+ remainingOrientations &= ~orientation;
+ if (orientation != mOrientationSpinnerAdapter.getItem(
+ orientationBitOffset).value) {
+ orientationsChanged = true;
+ break;
+ }
+ }
+ }
+ if (orientationsChanged) {
+ mOrientationSpinnerAdapter.clear();
+ String[] orientationLabels = getResources().getStringArray(
+ R.array.orientation_labels);
+ int remainingOrientations = orientations;
+ while (remainingOrientations != 0) {
+ final int orientationBitOffset = Integer.numberOfTrailingZeros(
+ remainingOrientations);
+ final int orientation = 1 << orientationBitOffset;
+ remainingOrientations &= ~orientation;
+ mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(orientation,
+ orientationLabels[orientationBitOffset]));
+ }
+ if (orientations > 0) {
+ mOrientationSpinner.setEnabled(true);
+ final int selectedOrientationIndex = Integer.numberOfTrailingZeros(
+ (orientations & defaultAttributes.getOrientation()));
+ mOrientationSpinner.setOnItemSelectedListener(null);
+ mOrientationSpinner.setSelection(selectedOrientationIndex);
+ }
+ }
+
+ // Range options
+ if (mPrintDocumentInfo != null && (mPrintDocumentInfo.getPageCount() > 1
+ || mPrintDocumentInfo.getPageCount()
+ == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) {
+ mRangeOptionsSpinner.setEnabled(true);
+ if (mRangeOptionsSpinner.getSelectedItemPosition() > 0
+ && !mRangeEditText.isEnabled()) {
+ mRangeEditText.setEnabled(true);
+ mRangeEditText.setError("");
+ mRangeEditText.setVisibility(View.VISIBLE);
+ mRangeEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager)
+ getSystemService(INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mRangeEditText, 0);
+ }
+ } else {
+ mRangeOptionsSpinner.setOnItemSelectedListener(null);
+ mRangeOptionsSpinner.setSelection(0);
+ mRangeOptionsSpinner.setEnabled(false);
+ mRangeEditText.setEnabled(false);
+ mRangeEditText.setText("");
+ mRangeEditText.setVisibility(View.INVISIBLE);
+ }
+
+ // Print preview
+ mPrintPreviewButton.setEnabled(true);
+ if (hasPdfViewer()) {
+ mPrintPreviewButton.setText(getString(R.string.print_preview));
+ } else {
+ mPrintPreviewButton.setText(getString(R.string.install_for_print_preview));
+ }
+
+ // Print
+ mPrintButton.setEnabled(true);
+ }
+
+ // Here is some voodoo to circumvent the weird behavior of AdapterView
+ // in which a selection listener may get a callback for an event that
+ // happened before the listener was registered. The reason for that is
+ // that the selection change is handled on the next layout pass.
+ Choreographer.getInstance().postCallback(Choreographer.CALLBACK_TRAVERSAL,
+ new Runnable() {
+ @Override
+ public void run() {
+ mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ }
+ }, null);
+ }
+
+ public PrinterInfo getCurrentPrinter() {
+ final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+ if (selectedIndex >= 0) {
+ return mDestinationSpinnerAdapter.getItem(selectedIndex).value;
+ }
+ return null;
+ }
+
+ public void addPrinters(List<PrinterInfo> addedPrinters) {
+ final int addedPrinterCount = addedPrinters.size();
+ for (int i = 0; i < addedPrinterCount; i++) {
+ PrinterInfo addedPrinter = addedPrinters.get(i);
+ boolean duplicate = false;
+ final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
+ for (int j = 0; j < existingPrinterCount; j++) {
+ PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
+ if (addedPrinter.getId().equals(existingPrinter.getId())) {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate) {
+ mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>(
+ addedPrinter, addedPrinter.getLabel()));
+ } else {
+ Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter);
+ }
+ }
+
+ if (mDestinationSpinner.getSelectedItemPosition() == AdapterView.INVALID_POSITION
+ && mDestinationSpinnerAdapter.getCount() > 0) {
+ mDestinationSpinner.setSelection(0);
+ }
+ }
+
+ public void removePrinters(List<PrinterId> pritnerIds) {
+ final int printerIdCount = pritnerIds.size();
+ for (int i = 0; i < printerIdCount; i++) {
+ PrinterId removedPrinterId = pritnerIds.get(i);
+ boolean removed = false;
+ final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
+ for (int j = 0; j < existingPrinterCount; j++) {
+ PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
+ if (removedPrinterId.equals(existingPrinter.getId())) {
+ mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j));
+ removed = true;
+ break;
+ }
+ }
+ if (!removed) {
+ Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId);
+ }
+ }
+
+ if (mDestinationSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION
+ && mDestinationSpinnerAdapter.getCount() == 0) {
+ mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION);
+ }
+ }
+
+ private void updatePrintPreview(File file) {
+ // TODO: Implement
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 2bf62ee..25bb37c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -32,6 +32,8 @@ import android.print.PrintDocumentInfo;
import android.util.Log;
import android.util.Slog;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -41,8 +43,6 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-
/**
* This class represents a remote print document adapter instance.
*/
@@ -53,10 +53,12 @@ final class RemotePrintDocumentAdapter {
public static final int STATE_INITIALIZED = 0;
public static final int STATE_START_COMPLETED = 1;
- public static final int STATE_LAYOUT_COMPLETED = 2;
- public static final int STATE_WRITE_COMPLETED = 3;
- public static final int STATE_FINISH_COMPLETED = 4;
- public static final int STATE_FAILED = 6;
+ public static final int STATE_LAYOUT_STARTED = 2;
+ public static final int STATE_LAYOUT_COMPLETED = 3;
+ public static final int STATE_WRITE_STARTED = 4;
+ public static final int STATE_WRITE_COMPLETED = 5;
+ public static final int STATE_FINISH_COMPLETED = 6;
+ public static final int STATE_FAILED = 7;
private final Object mLock = new Object();
@@ -94,7 +96,6 @@ final class RemotePrintDocumentAdapter {
Log.i(LOG_TAG, "start()");
}
synchronized (mLock) {
- mTaskQueue.add(this);
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("Invalid state: " + mState);
}
@@ -109,7 +110,15 @@ final class RemotePrintDocumentAdapter {
}
return null;
}
+
+ @Override
+ public void cancel() {
+ /* cannot be cancelled */
+ }
};
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ }
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
@@ -117,29 +126,37 @@ final class RemotePrintDocumentAdapter {
LayoutResultCallback callback, Bundle metadata) {
LayoutAsyncTask task = new LayoutAsyncTask(oldAttributes, newAttributes, callback,
metadata);
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ }
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
public void write(List<PageRange> pages, WriteResultCallback callback) {
WriteAsyncTask task = new WriteAsyncTask(pages, callback);
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ }
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
- public void finish(final boolean abortPendingWork) {
+ public void cancel() {
+ synchronized (mLock) {
+ final int taskCount = mTaskQueue.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ mTaskQueue.remove(i).cancel();
+ }
+ }
+ }
+
+ public void finish() {
QueuedAsyncTask task = new QueuedAsyncTask() {
@Override
protected Void doInBackground(Void... params) {
if (DEBUG) {
- Log.i(LOG_TAG, "finish");
+ Log.i(LOG_TAG, "finish()");
}
synchronized (mLock) {
- if (abortPendingWork) {
- final int taskCount = mTaskQueue.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- mTaskQueue.remove(i).cancel();
- }
- }
- mTaskQueue.add(this);
if (mState < STATE_START_COMPLETED) {
return null;
}
@@ -155,7 +172,15 @@ final class RemotePrintDocumentAdapter {
}
return null;
}
+
+ @Override
+ public void cancel() {
+ /* cannot be cancelled */
+ }
};
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ }
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
@@ -179,6 +204,9 @@ final class RemotePrintDocumentAdapter {
new ILayoutResultCallback.Stub() {
@Override
public void onLayoutStarted(ICancellationSignal cancellationSignal) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onLayoutStarted()");
+ }
synchronized (mLock) {
mCancellationSignal = cancellationSignal;
if (isCancelled()) {
@@ -189,30 +217,43 @@ final class RemotePrintDocumentAdapter {
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onLayoutFinished()");
+ }
+ final boolean cancelled;
synchronized (mLock) {
+ cancelled = isCancelled();
mCancellationSignal = null;
- mCompleted = true;
+ mState = STATE_LAYOUT_COMPLETED;
+ mTaskQueue.remove(this);
mLock.notifyAll();
}
- mCallback.onLayoutFinished(info, changed);
+ if (!cancelled) {
+ mCallback.onLayoutFinished(info, changed);
+ }
}
@Override
public void onLayoutFailed(CharSequence error) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onLayoutFailed()");
+ }
+ final boolean cancelled;
synchronized (mLock) {
+ cancelled = isCancelled();
mCancellationSignal = null;
- mCompleted = true;
+ mState = STATE_LAYOUT_COMPLETED;
+ mTaskQueue.remove(this);
mLock.notifyAll();
}
- Slog.e(LOG_TAG, "Error laying out print document: " + error);
- mCallback.onLayoutFailed(error);
+ if (!cancelled) {
+ mCallback.onLayoutFailed(error);
+ }
}
};
private ICancellationSignal mCancellationSignal;
- private boolean mCompleted;
-
public LayoutAsyncTask(PrintAttributes oldAttributes, PrintAttributes newAttributes,
LayoutResultCallback callback, Bundle metadata) {
mOldAttributes = oldAttributes;
@@ -233,25 +274,22 @@ final class RemotePrintDocumentAdapter {
@Override
protected Void doInBackground(Void... params) {
synchronized (mLock) {
- mTaskQueue.add(this);
+ if (DEBUG) {
+ Log.i(LOG_TAG, "layout()");
+ }
if (mState != STATE_START_COMPLETED
&& mState != STATE_LAYOUT_COMPLETED
&& mState != STATE_WRITE_COMPLETED) {
throw new IllegalStateException("Invalid state: " + mState);
}
+ mState = STATE_LAYOUT_STARTED;
}
try {
mRemoteInterface.layout(mOldAttributes, mNewAttributes,
mILayoutResultCallback, mMetadata);
synchronized (mLock) {
while (true) {
- if (isCancelled()) {
- mTaskQueue.remove(this);
- break;
- }
- if (mCompleted) {
- mState = STATE_LAYOUT_COMPLETED;
- mTaskQueue.remove(this);
+ if (mState == STATE_LAYOUT_COMPLETED) {
break;
}
try {
@@ -264,6 +302,8 @@ final class RemotePrintDocumentAdapter {
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error calling layout", re);
mState = STATE_FAILED;
+ mTaskQueue.remove(this);
+ notifyLayoutFailedQuietly();
}
return null;
}
@@ -274,10 +314,19 @@ final class RemotePrintDocumentAdapter {
mCancellationSignal.cancel();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error cancelling layout", re);
+ notifyLayoutFailedQuietly();
}
}
}
+ public void notifyLayoutFailedQuietly() {
+ try {
+ mILayoutResultCallback.onLayoutFailed(null);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
private void throwIfCancelledLocked() {
if (isCancelled()) {
throw new IllegalStateException("Already cancelled");
@@ -295,6 +344,9 @@ final class RemotePrintDocumentAdapter {
new IWriteResultCallback.Stub() {
@Override
public void onWriteStarted(ICancellationSignal cancellationSignal) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onWriteStarted()");
+ }
synchronized (mLock) {
mCancellationSignal = cancellationSignal;
if (isCancelled()) {
@@ -305,9 +357,13 @@ final class RemotePrintDocumentAdapter {
@Override
public void onWriteFinished(List<PageRange> pages) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onWriteFinished()");
+ }
synchronized (mLock) {
mCancellationSignal = null;
- mCompleted = true;
+ mState = STATE_WRITE_COMPLETED;
+ mTaskQueue.remove(this);
mLock.notifyAll();
}
mCallback.onWriteFinished(pages);
@@ -315,9 +371,13 @@ final class RemotePrintDocumentAdapter {
@Override
public void onWriteFailed(CharSequence error) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onWriteFailed()");
+ }
synchronized (mLock) {
mCancellationSignal = null;
- mCompleted = true;
+ mState = STATE_WRITE_COMPLETED;
+ mTaskQueue.remove(this);
mLock.notifyAll();
}
Slog.e(LOG_TAG, "Error writing print document: " + error);
@@ -327,8 +387,6 @@ final class RemotePrintDocumentAdapter {
private ICancellationSignal mCancellationSignal;
- private boolean mCompleted;
-
private Thread mWriteThread;
public WriteAsyncTask(List<PageRange> pages, WriteResultCallback callback) {
@@ -349,14 +407,14 @@ final class RemotePrintDocumentAdapter {
@Override
protected Void doInBackground(Void... params) {
if (DEBUG) {
- Log.i(LOG_TAG, "print()");
+ Log.i(LOG_TAG, "write()");
}
synchronized (mLock) {
- mTaskQueue.add(this);
if (mState != STATE_LAYOUT_COMPLETED
&& mState != STATE_WRITE_COMPLETED) {
throw new IllegalStateException("Invalid state: " + mState);
}
+ mState = STATE_WRITE_STARTED;
}
InputStream in = null;
OutputStream out = null;
@@ -394,13 +452,7 @@ final class RemotePrintDocumentAdapter {
}
synchronized (mLock) {
while (true) {
- if (isCancelled()) {
- mTaskQueue.remove(this);
- break;
- }
- if (mCompleted) {
- mState = STATE_WRITE_COMPLETED;
- mTaskQueue.remove(this);
+ if (mState == STATE_WRITE_COMPLETED) {
break;
}
try {
@@ -413,9 +465,13 @@ final class RemotePrintDocumentAdapter {
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error writing print document", re);
mState = STATE_FAILED;
+ mTaskQueue.remove(this);
+ notifyWriteFailedQuietly();
} catch (IOException ioe) {
Slog.e(LOG_TAG, "Error writing print document", ioe);
mState = STATE_FAILED;
+ mTaskQueue.remove(this);
+ notifyWriteFailedQuietly();
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
@@ -431,10 +487,19 @@ final class RemotePrintDocumentAdapter {
mCancellationSignal.cancel();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error cancelling layout", re);
+ notifyWriteFailedQuietly();
}
}
}
+ private void notifyWriteFailedQuietly() {
+ try {
+ mIWriteResultCallback.onWriteFailed(null);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
private void throwIfCancelledLocked() {
if (isCancelled()) {
throw new IllegalStateException("Already cancelled");