diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2013-07-24 01:13:01 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-07-24 01:13:01 +0000 |
commit | 4a1e24ce9dc224e568b20a52f7b6d5789689d1b0 (patch) | |
tree | d904a397470671504b3a9a43020e42c31ef8a38b | |
parent | 46a7b0d1aaa79415af4e3dbe84bbb9ca27b19139 (diff) | |
parent | 0d1daa50f6d180c57f92596501e2e5c0b5ef9997 (diff) | |
download | frameworks_base-4a1e24ce9dc224e568b20a52f7b6d5789689d1b0.zip frameworks_base-4a1e24ce9dc224e568b20a52f7b6d5789689d1b0.tar.gz frameworks_base-4a1e24ce9dc224e568b20a52f7b6d5789689d1b0.tar.bz2 |
Merge "Updating the print dialog and its interactinos with the printing app."
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–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"); |