diff options
| author | 2013-07-17 18:37:36 -0700 | |
|---|---|---|
| committer | 2013-07-19 16:23:12 -0700 | |
| commit | 597945fd3a6b52ac70bb9afc5ec8c59039fffd77 (patch) | |
| tree | 1e44c6e0c34deba26033b46878bbbfd010a3f8d9 | |
| parent | 7a5480d6d74eb64a360ed20062c66926c9eef9bc (diff) | |
First pass of the print dialog UX
Change-Id: I315a16d7f68c73ca180c76e722847b4b1bdea55b
| -rw-r--r-- | core/java/android/printservice/PrintService.java | 15 | ||||
| -rw-r--r-- | packages/PrintSpooler/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | packages/PrintSpooler/res/layout/print_job_config_activity.xml | 425 | ||||
| -rw-r--r-- | packages/PrintSpooler/res/layout/spinner_dropdown_item.xml | 48 | ||||
| -rw-r--r-- | packages/PrintSpooler/res/values/constants.xml (renamed from packages/PrintSpooler/res/menu/print_job_config_activity.xml) | 18 | ||||
| -rw-r--r-- | packages/PrintSpooler/res/values/strings.xml | 76 | ||||
| -rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java | 426 | ||||
| -rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java | 18 | ||||
| -rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java | 4 | ||||
| -rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java | 59 | ||||
| -rw-r--r-- | services/java/com/android/server/print/RemotePrintSpooler.java | 3 |
11 files changed, 525 insertions, 570 deletions
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index 820c2d8ff4ef..dde31d25678b 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -245,13 +245,10 @@ public abstract class PrintService extends Service { * @see #removeDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() - * - * @throws IllegalStateException If this service is not connected. */ public final void addDiscoveredPrinters(List<PrinterInfo> printers) { final IPrinterDiscoveryObserver observer; synchronized (mLock) { - throwIfNotConnectedLocked(); observer = mDiscoveryObserver; } if (observer != null) { @@ -284,13 +281,10 @@ public abstract class PrintService extends Service { * @see #addDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() - * - * @throws IllegalStateException If this service is not connected. */ public final void removeDiscoveredPrinters(List<PrinterId> printerIds) { final IPrinterDiscoveryObserver observer; synchronized (mLock) { - throwIfNotConnectedLocked(); observer = mDiscoveryObserver; } if (observer != null) { @@ -334,13 +328,10 @@ public abstract class PrintService extends Service { * Gets the print jobs for the printers managed by this service. * * @return The print jobs. - * - * @throws IllegalStateException If this service is not connected. */ public final List<PrintJob> getPrintJobs() { final IPrintServiceClient client; synchronized (mLock) { - throwIfNotConnectedLocked(); client = mClient; } if (client == null) { @@ -410,12 +401,6 @@ public abstract class PrintService extends Service { }; } - private void throwIfNotConnectedLocked() { - if (mClient == null) { - throw new IllegalStateException("Print serivice not connected"); - } - } - private final class MyHandler extends Handler { public static final int MESSAGE_START_PRINTER_DISCOVERY = 1; public static final int MESSAGE_STOP_PRINTER_DISCOVERY = 2; diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index fbb0060fa4a1..f0bbfa49fe06 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -46,7 +46,8 @@ <activity android:name=".PrintJobConfigActivity" - android:exported="true"> + android:exported="true" + android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar"> </activity> </application> diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml index 51e425d8c75b..8736bdd97f8c 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml @@ -14,248 +14,197 @@ limitations under the License. --> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:orientation="vertical"> - <GridLayout - android:layout_width="wrap_content" + <ScrollView + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:layout_gravity="center" - android:orientation="vertical" - android:columnCount="2"> + android:background="@*android:color/bright_foreground_disabled_holo_light"> - <EditText - android:id="@+id/copies_edittext" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="0" - android:layout_column="1" - android:minWidth="150dip" - android:inputType="number" - android:selectAllOnFocus="true"> - </EditText> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="0" - android:layout_column="0" - android:text="@string/label_copies" - android:textAppearance="?android:attr/textAppearanceMedium" - android:labelFor="@id/copies_edittext"> - </TextView> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="1" - android:layout_column="0" - android:text="@string/label_destination" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/destination_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="1" - 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="12dip" - android:layout_row="2" - android:layout_column="0" - android:text="@string/label_media_size" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/media_size_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="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="12dip" - android:layout_row="3" - android:layout_column="0" - android:text="@string/label_resolution" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/resolution_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="3" - 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="12dip" - android:layout_row="4" - android:layout_column="0" - android:text="@string/label_input_tray" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/input_tray_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="4" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView + <GridLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="5" - android:layout_column="0" - android:text="@string/label_output_tray" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/output_tray_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="5" - 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="12dip" - android:layout_row="6" - android:layout_column="0" - android:text="@string/label_duplex_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/duplex_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="6" - 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="12dip" - android:layout_row="7" - android:layout_column="0" - android:text="@string/label_color_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/color_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="7" - 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="12dip" - android:layout_row="8" - android:layout_column="0" - android:text="@string/label_fitting_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/fitting_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="8" - 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="12dip" - android:layout_row="9" - android:layout_column="0" - android:text="@string/label_orientation" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/orientation_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="9" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - </GridLayout> + 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> -</ScrollView> +</LinearLayout> diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml new file mode 100644 index 000000000000..66c67244b0ef --- /dev/null +++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + 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 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="8dip" + android:paddingRight="8dip" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="vertical" + android:gravity="center_vertical"> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="end" + android:textIsSelectable="false"> + </TextView> + + <TextView + android:id="@+id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:singleLine="true" + android:ellipsize="end" + android:textIsSelectable="false" + android:visibility="gone"> + + </TextView> + +</LinearLayout> diff --git a/packages/PrintSpooler/res/menu/print_job_config_activity.xml b/packages/PrintSpooler/res/values/constants.xml index 149c274dd1b9..7d2cdc37851f 100644 --- a/packages/PrintSpooler/res/menu/print_job_config_activity.xml +++ b/packages/PrintSpooler/res/values/constants.xml @@ -13,9 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/print_button" - android:title="@string/print_button" - android:showAsAction="ifRoom"> - </item> -</menu> + +<resources> + + <integer name="page_option_value_all">1</integer> + <integer name="page_option_value_page_range">2</integer> + + <integer-array name="page_options_values" translatable="false"> + <item>@integer/page_option_value_all</item> + <item>@integer/page_option_value_page_range</item> + </integer-array> + +</resources>
\ No newline at end of file diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 8b4b40aa2ec7..de6fb605d4ec 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -16,74 +16,44 @@ <resources> - <!-- Title of the PrintSpooler application. [CHAR LIMIT=16] --> + <!-- Title of the PrintSpooler application. [CHAR LIMIT=50] --> <string name="app_label">Print Spooler</string> - <!-- Title of the print dialog. [CHAR LIMIT=10] --> - <string name="print_job_config_dialog_title">Print</string> - <!-- Label of the print dialog's print button. [CHAR LIMIT=16] --> - <string name="print_button">Print</string> - - <!-- Label of the print dialog's cancel button. [CHAR LIMIT=16] --> - <string name="cancel_button">Cancel</string> - - <!-- Label of the destination spinner. [CHAR LIMIT=16] --> - <string name="label_destination">Destination</string> - - <!-- Label of the copies count edit text. [CHAR LIMIT=16] --> - <string name="label_copies">Copies</string> - - <!-- Label of the media size spinner. [CHAR LIMIT=16] --> - <string name="label_media_size">Media size</string> + <string name="print_button">PRINT</string> - <!-- Label of the resolution spinner. [CHAR LIMIT=16] --> - <string name="label_resolution">Resolution</string> + <!-- Label of the destination widget. [CHAR LIMIT=20] --> + <string name="label_destination">DESTIINATION</string> - <!-- Label of the input tray spinner. [CHAR LIMIT=16] --> - <string name="label_input_tray">Input tray</string> + <!-- Label of the copies count widget. [CHAR LIMIT=20] --> + <string name="label_copies">COPIES</string> - <!-- Label of the output tray spinner. [CHAR LIMIT=16] --> - <string name="label_output_tray">Output tray</string> + <!-- Label of the paper size widget. [CHAR LIMIT=20] --> + <string name="label_paper_size">PAPER SIZE</string> - <!-- Label of the duplex mode spinner. [CHAR LIMIT=16] --> - <string name="label_duplex_mode">Duplex mode</string> + <!-- Label of the color mode widget. [CHAR LIMIT=20] --> + <string name="label_color">COLOR</string> - <!-- Label of the color mode spinner. [CHAR LIMIT=16] --> - <string name="label_color_mode">Color mode</string> + <!-- Label of the orientation widget. [CHAR LIMIT=20] --> + <string name="label_orientation">ORIENTATION</string> - <!-- Label of the fitting mode spinner. [CHAR LIMIT=16] --> - <string name="label_fitting_mode">Fitting mode</string> + <!-- Label of the page selection widget. [CHAR LIMIT=20] --> + <string name="label_pages">PAGES</string> - <!-- Label of the orientation spinner. [CHAR LIMIT=16] --> - <string name="label_orientation">Orientation</string> + <!-- 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> - <!-- Duplex mode labels. --> - <string-array name="duplex_mode_labels"> - <!-- Duplex mode label: No duplexing. [CHAR LIMIT=20] --> - <item>None</item> - <!-- Duplex mode label: Turn a page along its long edge, e.g. like a book. [CHAR LIMIT=20] --> - <item>Long edge</item> - <!-- Duplex mode label: Turn a page along its short edge, e.g. like a notepad. [CHAR LIMIT=20] --> - <item>Short edge</item> - </string-array> + <!-- Message to notify the user of entering invalid input. [CHAR LIMIT=25] --> + <string name="invalid_input">Invalid input</string> <!-- Color mode labels. --> <string-array name="color_mode_labels"> <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] --> - <item>Monochrome</item> + <item>Black & White</item> <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] --> <item>Color</item> </string-array> - <!-- Fitting mode labels. --> - <string-array name="fitting_mode_labels"> - <!-- Fitting mode label: No fitting. [CHAR LIMIT=30] --> - <item>None</item> - <!-- Fitting mode label: Fit the content to the page. [CHAR LIMIT=30] --> - <item>Fit to page</item> - </string-array> - <!-- Orientation labels. --> <string-array name="orientation_labels"> <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] --> @@ -92,6 +62,14 @@ <item>Landscape</item> </string-array> + <!-- Page options labels. --> + <string-array name="page_options_labels"> + <!-- Page range option label: Print all pages [CHAR LIMIT=30] --> + <item>All</item> + <!-- Page range option label: Print a page range [CHAR LIMIT=30] --> + <item>Range</item> + </string-array> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index c0faed8afbf6..19f545d06569 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -17,7 +17,12 @@ package com.android.printspooler; import android.app.Activity; +import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -34,8 +39,6 @@ import android.print.IPrinterDiscoveryObserver; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintAttributes.MediaSize; -import android.print.PrintAttributes.Resolution; -import android.print.PrintAttributes.Tray; import android.print.PrintDocumentAdapter.LayoutResultCallback; import android.print.PrintDocumentAdapter.WriteResultCallback; import android.print.PrintDocumentInfo; @@ -43,25 +46,28 @@ import android.print.PrintJobInfo; import android.print.PrinterId; import android.print.PrinterInfo; import android.text.Editable; -import android.text.InputFilter; -import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.AttributeSet; import android.util.Log; -import android.view.Choreographer; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; +import android.widget.TextView; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Activity for configuring a print job. @@ -79,6 +85,14 @@ public class PrintJobConfigActivity extends Activity { private static final int MIN_COPIES = 1; + private static final Pattern PATTERN_DIGITS = Pattern.compile("\\d"); + + private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile( + "(?=[]\\[+&|!(){}^\"~*?:\\\\])"); + + private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile( + "([0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*[,]?[\\s]*)+"); + private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this); private IPrinterDiscoveryObserver mPrinterDiscoveryObserver; @@ -90,42 +104,36 @@ public class PrintJobConfigActivity extends Activity { private RemotePrintDocumentAdapter mRemotePrintAdapter; + private boolean mPrintConfirmed; + + private boolean mStarted; + + private IBinder mIPrintDocumentAdapter; + + 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 mResolutionSpinner; - public ArrayAdapter<SpinnerItem<Resolution>> mResolutionSpinnerAdapter; - - private Spinner mInputTraySpinner; - public ArrayAdapter<SpinnerItem<Tray>> mInputTraySpinnerAdapter; - - private Spinner mOutputTraySpinner; - public ArrayAdapter<SpinnerItem<Tray>> mOutputTraySpinnerAdapter; - - private Spinner mDuplexModeSpinner; - public ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter; - private Spinner mColorModeSpinner; public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter; - private Spinner mFittingModeSpinner; - public ArrayAdapter<SpinnerItem<Integer>> mFittingModeSpinnerAdapter; - private Spinner mOrientationSpinner; public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter; - private boolean mPrintConfirmed; + private Spinner mRangeOptionsSpinner; + public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter; - private boolean mStarted; - - private IBinder mIPrintDocumentAdapter; + private Button mPrintButton; // TODO: Implement store/restore state. @@ -140,35 +148,34 @@ public class PrintJobConfigActivity extends Activity { SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position); mPrintAttributes.setMediaSize(mediaItem.value); updatePrintableContentIfNeeded(); - } else if (spinner == mResolutionSpinner) { - SpinnerItem<Resolution> resolutionItem = - mResolutionSpinnerAdapter.getItem(position); - mPrintAttributes.setResolution(resolutionItem.value); - updatePrintableContentIfNeeded(); - } else if (spinner == mInputTraySpinner) { - SpinnerItem<Tray> inputTrayItem = - mInputTraySpinnerAdapter.getItem(position); - mPrintAttributes.setInputTray(inputTrayItem.value); - } else if (spinner == mOutputTraySpinner) { - SpinnerItem<Tray> outputTrayItem = - mOutputTraySpinnerAdapter.getItem(position); - mPrintAttributes.setOutputTray(outputTrayItem.value); - } else if (spinner == mDuplexModeSpinner) { - SpinnerItem<Integer> duplexModeItem = - mDuplexModeSpinnerAdapter.getItem(position); - mPrintAttributes.setDuplexMode(duplexModeItem.value); } else if (spinner == mColorModeSpinner) { SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position); mPrintAttributes.setColorMode(colorModeItem.value); - } else if (spinner == mFittingModeSpinner) { - SpinnerItem<Integer> fittingModeItem = - mFittingModeSpinnerAdapter.getItem(position); - mPrintAttributes.setFittingMode(fittingModeItem.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); + } } } @@ -178,11 +185,10 @@ public class PrintJobConfigActivity extends Activity { } }; - private final TextWatcher mTextWatcher = new TextWatcher() { + private final TextWatcher mCopiesTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - final int copies = Integer.parseInt(mCopiesEditText.getText().toString()); - mPrintAttributes.setCopies(copies); + /* do nothing */ } @Override @@ -191,25 +197,64 @@ public class PrintJobConfigActivity extends Activity { } @Override - public void afterTextChanged(Editable s) { - /* do nothing */ + 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 InputFilter mInputFilter = new InputFilter() { + private final TextWatcher mRangeTextWatcher = new TextWatcher() { @Override - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - StringBuffer text = new StringBuffer(dest.toString()); - text.replace(dstart, dend, source.subSequence(start, end).toString()); + 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)) { - return dest; + mRangeEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; } - final int copies = Integer.parseInt(text.toString()); - if (copies < MIN_COPIES) { - return dest; + + 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; } - return null; + + 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); } }; @@ -274,70 +319,95 @@ public class PrintJobConfigActivity extends Activity { // Copies mCopiesEditText = (EditText) findViewById(R.id.copies_edittext); mCopiesEditText.setText(String.valueOf(MIN_COPIES)); - mCopiesEditText.addTextChangedListener(mTextWatcher); - mCopiesEditText.setFilters(new InputFilter[] {mInputFilter}); + mCopiesEditText.addTextChangedListener(mCopiesTextWatcher); // Destination. mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner); mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(this, - android.R.layout.simple_spinner_dropdown_item); + 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.media_size_spinner); + mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner); mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item, R.id.title); mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter); mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Resolution. - mResolutionSpinner = (Spinner) findViewById(R.id.resolution_spinner); - mResolutionSpinnerAdapter = new ArrayAdapter<SpinnerItem<Resolution>>(this, - android.R.layout.simple_spinner_dropdown_item); - mResolutionSpinner.setAdapter(mResolutionSpinnerAdapter); - mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Input tray. - mInputTraySpinner = (Spinner) findViewById(R.id.input_tray_spinner); - mInputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this, - android.R.layout.simple_spinner_dropdown_item); - mInputTraySpinner.setAdapter(mInputTraySpinnerAdapter); - - // Output tray. - mOutputTraySpinner = (Spinner) findViewById(R.id.output_tray_spinner); - mOutputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this, - android.R.layout.simple_spinner_dropdown_item); - mOutputTraySpinner.setAdapter(mOutputTraySpinnerAdapter); - mOutputTraySpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Duplex mode. - mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_mode_spinner); - mDuplexModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); - mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter); - mDuplexModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Color mode. - mColorModeSpinner = (Spinner) findViewById(R.id.color_mode_spinner); + mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner); mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item, R.id.title); mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter); mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Color mode. - mFittingModeSpinner = (Spinner) findViewById(R.id.fitting_mode_spinner); - mFittingModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); - mFittingModeSpinner.setAdapter(mFittingModeSpinnerAdapter); - mFittingModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Orientation mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner); mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); + 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); + + mPrintButton = (Button) findViewById(R.id.print_button); + mPrintButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mPrintConfirmed = true; + finish(); + } + }); } private void updateUi() { @@ -348,6 +418,7 @@ public class PrintJobConfigActivity extends Activity { // Copies. mCopiesEditText.setText(String.valueOf( Math.max(mPrintAttributes.getCopies(), MIN_COPIES))); + mCopiesEditText.selectAll(); // Media size. mMediaSizeSpinnerAdapter.clear(); @@ -363,80 +434,6 @@ public class PrintJobConfigActivity extends Activity { mMediaSizeSpinner.setOnItemSelectedListener(null); mMediaSizeSpinner.setSelection(selectedMediaSizeIndex); - // Resolution. - mResolutionSpinnerAdapter.clear(); - List<Resolution> resolutions = printer.getResolutions(); - final int resolutionCount = resolutions.size(); - for (int i = 0; i < resolutionCount; i++) { - Resolution resolution = resolutions.get(i); - mResolutionSpinnerAdapter.add(new SpinnerItem<Resolution>( - resolution, resolution.getLabel(getPackageManager()))); - } - final int selectedResolutionIndex = resolutions.indexOf( - mPrintAttributes.getResolution()); - mResolutionSpinner.setOnItemSelectedListener(null); - mResolutionSpinner.setSelection(selectedResolutionIndex); - - // AdapterView has the weird behavior to notify the selection listener for a - // selection event that occurred *before* the listener was registered because - // it does the real selection change on the next layout pass. To avoid this - // behavior we re-attach the listener in the next traversal window - fun! - Choreographer.getInstance().postCallback( - Choreographer.CALLBACK_TRAVERSAL, new Runnable() { - @Override - public void run() { - mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - } - }, null); - - // Input tray. - mInputTraySpinnerAdapter.clear(); - List<Tray> inputTrays = printer.getInputTrays(); - if (inputTrays != null) { - final int inputTrayCount = inputTrays.size(); - for (int i = 0; i < inputTrayCount; i++) { - Tray inputTray = inputTrays.get(i); - mInputTraySpinnerAdapter.add(new SpinnerItem<Tray>( - inputTray, inputTray.getLabel(getPackageManager()))); - } - final int selectedInputTrayIndex = inputTrays.indexOf( - mPrintAttributes.getInputTray()); - mInputTraySpinner.setSelection(selectedInputTrayIndex); - } - - // Output tray. - mOutputTraySpinnerAdapter.clear(); - List<Tray> outputTrays = printer.getOutputTrays(); - if (outputTrays != null) { - final int outputTrayCount = outputTrays.size(); - for (int i = 0; i < outputTrayCount; i++) { - Tray outputTray = outputTrays.get(i); - mOutputTraySpinnerAdapter.add(new SpinnerItem<Tray>( - outputTray, outputTray.getLabel(getPackageManager()))); - } - final int selectedOutputTrayIndex = outputTrays.indexOf( - mPrintAttributes.getOutputTray()); - mOutputTraySpinner.setSelection(selectedOutputTrayIndex); - } - - // Duplex mode. - final int duplexModes = printer.getDuplexModes(); - mDuplexModeSpinnerAdapter.clear(); - String[] duplexModeLabels = getResources().getStringArray( - R.array.duplex_mode_labels); - int remainingDuplexModes = duplexModes; - while (remainingDuplexModes != 0) { - final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes); - final int duplexMode = 1 << duplexBitOffset; - remainingDuplexModes &= ~duplexMode; - mDuplexModeSpinnerAdapter.add(new SpinnerItem<Integer>(duplexMode, - duplexModeLabels[duplexBitOffset])); - } - final int selectedDuplexModeIndex = Integer.numberOfTrailingZeros( - (duplexModes & mPrintAttributes.getDuplexMode())); - mDuplexModeSpinner.setSelection(selectedDuplexModeIndex); - // Color mode. final int colorModes = printer.getColorModes(); mColorModeSpinnerAdapter.clear(); @@ -454,23 +451,6 @@ public class PrintJobConfigActivity extends Activity { (colorModes & mPrintAttributes.getColorMode())); mColorModeSpinner.setSelection(selectedColorModeIndex); - // Fitting mode. - final int fittingModes = printer.getFittingModes(); - mFittingModeSpinnerAdapter.clear(); - String[] fittingModeLabels = getResources().getStringArray( - R.array.fitting_mode_labels); - int remainingFittingModes = fittingModes; - while (remainingFittingModes != 0) { - final int fittingBitOffset = Integer.numberOfTrailingZeros(remainingFittingModes); - final int fittingMode = 1 << fittingBitOffset; - remainingFittingModes &= ~fittingMode; - mFittingModeSpinnerAdapter.add(new SpinnerItem<Integer>(fittingMode, - fittingModeLabels[fittingBitOffset])); - } - final int selectedFittingModeIndex = Integer.numberOfTrailingZeros( - (fittingModes & mPrintAttributes.getFittingMode())); - mFittingModeSpinner.setSelection(selectedFittingModeIndex); - // Orientation. final int orientations = printer.getOrientations(); mOrientationSpinnerAdapter.clear(); @@ -503,21 +483,6 @@ public class PrintJobConfigActivity extends Activity { notifyPrintableFinishIfNeeded(); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.print_job_config_activity, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.print_button) { - mPrintConfirmed = true; - finish(); - } - return super.onOptionsItemSelected(item); - } - private void notifyPrintableStartIfNeeded() { if (mDestinationSpinner.getSelectedItemPosition() < 0 || mStarted) { @@ -541,6 +506,8 @@ public class PrintJobConfigActivity extends Activity { mPrintAttributes, new LayoutResultCallback() { @Override public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { + mPrintDocumentInfo = info; + // TODO: Handle the case of unchanged content mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info); @@ -575,10 +542,7 @@ public class PrintJobConfigActivity extends Activity { return; } - if (!mPrintConfirmed) { - mRemotePrintAdapter.cancel(); - } - mRemotePrintAdapter.finish(); + mRemotePrintAdapter.finish(!mPrintConfirmed); // If canceled or no printer, nothing to do. final int selectedIndex = mDestinationSpinner.getSelectedItemPosition(); @@ -735,4 +699,38 @@ public class PrintJobConfigActivity extends Activity { return label.toString(); } } + + /** + * An instance of this class class is intended to be the first focusable + * in a layout to which the system automatically gives focus. It performs + * some voodoo to avoid the first tap on it to start an edit mode, rather + * to bring up the IME, i.e. to get the behavior as if the view was not + * focused. + */ + public static final class CustomEditText extends EditText { + private boolean mClickedBeforeFocus; + + public CustomEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean performClick() { + super.performClick(); + if (isFocused() && !mClickedBeforeFocus) { + clearFocus(); + requestFocus(); + } + mClickedBeforeFocus = true; + return true; + } + + protected void onFocusChanged(boolean gainFocus, int direction, + Rect previouslyFocusedRect) { + if (!gainFocus) { + mClickedBeforeFocus = false; + } + super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); + } + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java index 0546a4316619..9a44f7792b18 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java @@ -129,7 +129,7 @@ public class PrintSpooler { } } - public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId) { + public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, int appId) { synchronized (mLock) { List<PrintJobInfo> foundPrintJobs = null; final int printJobCount = mPrintJobs.size(); @@ -154,7 +154,7 @@ public class PrintSpooler { } } - public PrintJobInfo getPrintJob(int printJobId, int appId) { + public PrintJobInfo getPrintJobInfo(int printJobId, int appId) { synchronized (mLock) { final int printJobCount = mPrintJobs.size(); for (int i = 0; i < printJobCount; i++) { @@ -170,7 +170,7 @@ public class PrintSpooler { public boolean cancelPrintJob(int printJobId, int appId) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, appId); + PrintJobInfo printJob = getPrintJobInfo(printJobId, appId); if (printJob != null) { switch (printJob.getState()) { case PrintJobInfo.STATE_CREATED: @@ -291,7 +291,7 @@ public class PrintSpooler { FileInputStream in = null; FileOutputStream out = null; try { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { File file = generateFileForPrintJob(printJobId); in = new FileInputStream(file); @@ -355,7 +355,7 @@ public class PrintSpooler { } client = mClient; - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null && printJob.getState() < state) { success = true; printJob.setState(state); @@ -465,7 +465,7 @@ public class PrintSpooler { public boolean setPrintJobTag(int printJobId, String tag) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setTag(tag); mPersistanceManager.writeStateLocked(); @@ -477,7 +477,7 @@ public class PrintSpooler { public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setDocumentInfo(info); mPersistanceManager.writeStateLocked(); @@ -489,7 +489,7 @@ public class PrintSpooler { public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setAttributes(attributes); mPersistanceManager.writeStateLocked(); @@ -499,7 +499,7 @@ public class PrintSpooler { public void setPrintJobPrinterId(int printJobId, PrinterId printerId) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setPrinterId(printerId); mPersistanceManager.writeStateLocked(); diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index 050332cc0dc0..ad5e5b0a9dc0 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -72,7 +72,7 @@ public final class PrintSpoolerService extends Service { throws RemoteException { List<PrintJobInfo> printJobs = null; try { - printJobs = mSpooler.getPrintJobs(componentName, state, appId); + printJobs = mSpooler.getPrintJobInfos(componentName, state, appId); } finally { callback.onGetPrintJobInfosResult(printJobs, sequence); } @@ -83,7 +83,7 @@ public final class PrintSpoolerService extends Service { int appId, int sequence) throws RemoteException { PrintJobInfo printJob = null; try { - printJob = mSpooler.getPrintJob(printJobId, appId); + printJob = mSpooler.getPrintJobInfo(printJobId, appId); } finally { callback.onGetPrintJobInfoResult(printJob, sequence); } diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java index 71869323fc08..2bf62eebe8bc 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java +++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java @@ -56,6 +56,7 @@ final class RemotePrintDocumentAdapter { 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; private final Object mLock = new Object(); @@ -77,22 +78,14 @@ final class RemotePrintDocumentAdapter { Log.i(LOG_TAG, "getFile()"); } synchronized (mLock) { - if (mState < STATE_WRITE_COMPLETED) { + if (mState != STATE_WRITE_COMPLETED + && mState != STATE_FINISH_COMPLETED) { throw new IllegalStateException("Write not completed"); } return mFile; } } - public void cancel() { - synchronized (mLock) { - final int taskCount = mTaskQueue.size(); - for (int i = 0; i < taskCount; i++) { - mTaskQueue.remove(i).cancel(); - } - } - } - public void start() { QueuedAsyncTask task = new QueuedAsyncTask() { @Override @@ -101,6 +94,7 @@ final class RemotePrintDocumentAdapter { Log.i(LOG_TAG, "start()"); } synchronized (mLock) { + mTaskQueue.add(this); if (mState != STATE_INITIALIZED) { throw new IllegalStateException("Invalid state: " + mState); } @@ -116,29 +110,22 @@ final class RemotePrintDocumentAdapter { return null; } }; - synchronized (mLock) { - mTaskQueue.add(task); - task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); - } + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); } public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes, LayoutResultCallback callback, Bundle metadata) { LayoutAsyncTask task = new LayoutAsyncTask(oldAttributes, newAttributes, callback, metadata); - synchronized (mLock) { - mTaskQueue.add(task); - task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); - } + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); } public void write(List<PageRange> pages, WriteResultCallback callback) { WriteAsyncTask task = new WriteAsyncTask(pages, callback); - mTaskQueue.add(task); task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); } - public void finish() { + public void finish(final boolean abortPendingWork) { QueuedAsyncTask task = new QueuedAsyncTask() { @Override protected Void doInBackground(Void... params) { @@ -146,9 +133,15 @@ final class RemotePrintDocumentAdapter { Log.i(LOG_TAG, "finish"); } synchronized (mLock) { - if (mState != STATE_LAYOUT_COMPLETED - && mState != STATE_WRITE_COMPLETED) { - throw new IllegalStateException("Invalid state: " + mState); + 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; } } try { @@ -158,15 +151,12 @@ final class RemotePrintDocumentAdapter { } } catch (RemoteException re) { Log.e(LOG_TAG, "Error reading file", re); - mState = STATE_INITIALIZED; + mState = STATE_FAILED; } return null; } }; - synchronized (mLock) { - mTaskQueue.add(task); - task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); - } + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); } private abstract class QueuedAsyncTask extends AsyncTask<Void, Void, Void> { @@ -243,6 +233,7 @@ final class RemotePrintDocumentAdapter { @Override protected Void doInBackground(Void... params) { synchronized (mLock) { + mTaskQueue.add(this); if (mState != STATE_START_COMPLETED && mState != STATE_LAYOUT_COMPLETED && mState != STATE_WRITE_COMPLETED) { @@ -255,7 +246,6 @@ final class RemotePrintDocumentAdapter { synchronized (mLock) { while (true) { if (isCancelled()) { - mState = STATE_INITIALIZED; mTaskQueue.remove(this); break; } @@ -273,7 +263,7 @@ final class RemotePrintDocumentAdapter { } } catch (RemoteException re) { Slog.e(LOG_TAG, "Error calling layout", re); - mState = STATE_INITIALIZED; + mState = STATE_FAILED; } return null; } @@ -362,7 +352,9 @@ final class RemotePrintDocumentAdapter { Log.i(LOG_TAG, "print()"); } synchronized (mLock) { - if (mState != STATE_LAYOUT_COMPLETED) { + mTaskQueue.add(this); + if (mState != STATE_LAYOUT_COMPLETED + && mState != STATE_WRITE_COMPLETED) { throw new IllegalStateException("Invalid state: " + mState); } } @@ -403,7 +395,6 @@ final class RemotePrintDocumentAdapter { synchronized (mLock) { while (true) { if (isCancelled()) { - mState = STATE_INITIALIZED; mTaskQueue.remove(this); break; } @@ -421,10 +412,10 @@ final class RemotePrintDocumentAdapter { } } catch (RemoteException re) { Slog.e(LOG_TAG, "Error writing print document", re); - mState = STATE_INITIALIZED; + mState = STATE_FAILED; } catch (IOException ioe) { Slog.e(LOG_TAG, "Error writing print document", ioe); - mState = STATE_INITIALIZED; + mState = STATE_FAILED; } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index bf2c8e73af6c..6445c2ee9814 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -296,8 +296,7 @@ final class RemotePrintSpooler { } mContext.bindServiceAsUser(mIntent, mServiceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT, - mUserHandle); + Context.BIND_AUTO_CREATE, mUserHandle); final long startMillis = SystemClock.uptimeMillis(); while (true) { |