private void doFinish() {
mDocumentAdapter = null;
mHandler = null;
+ mLayoutOrWriteCancellation = null;
}
private final class MyHandler extends Handler {
case MSG_LAYOUT: {
SomeArgs args = (SomeArgs) message.obj;
- final PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
- final PrintAttributes newAttributes = (PrintAttributes) args.arg2;
- final ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
- final Bundle metadata = (Bundle) args.arg4;
+ PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
+ PrintAttributes newAttributes = (PrintAttributes) args.arg2;
+ ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
+ Bundle metadata = (Bundle) args.arg4;
final int sequence = args.argi1;
args.recycle();
mLayoutOrWriteCancellation = cancellation;
}
- mDocumentAdapter.onLayout(oldAttributes, newAttributes,
- cancellation, new LayoutResultCallback() {
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- if (info == null) {
- throw new IllegalArgumentException("info cannot be null");
- }
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- try {
- callback.onLayoutFinished(info, changed, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error) {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- try {
- callback.onLayoutFailed(error, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
- }
- }
-
- @Override
- public void onLayoutCancelled() {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- }
- }, metadata);
+ mDocumentAdapter.onLayout(oldAttributes, newAttributes, cancellation,
+ new MyLayoutResultCallback(callback, sequence), metadata);
} break;
case MSG_WRITE: {
SomeArgs args = (SomeArgs) message.obj;
- final PageRange[] pages = (PageRange[]) args.arg1;
- final FileDescriptor fd = (FileDescriptor) args.arg2;
- final IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
+ PageRange[] pages = (PageRange[]) args.arg1;
+ FileDescriptor fd = (FileDescriptor) args.arg2;
+ IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
final int sequence = args.argi1;
args.recycle();
}
mDocumentAdapter.onWrite(pages, fd, cancellation,
- new WriteResultCallback() {
- @Override
- public void onWriteFinished(PageRange[] pages) {
- if (pages == null) {
- throw new IllegalArgumentException("pages cannot be null");
- }
- if (pages.length == 0) {
- throw new IllegalArgumentException("pages cannot be empty");
- }
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(fd);
- try {
- callback.onWriteFinished(pages, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFinished", re);
- }
- }
-
- @Override
- public void onWriteFailed(CharSequence error) {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(fd);
- try {
- callback.onWriteFailed(error, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFailed", re);
- }
- }
-
- @Override
- public void onWriteCancelled() {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Just close the fd for now.
- IoUtils.closeQuietly(fd);
- }
- });
+ new MyWriteResultCallback(callback, fd, sequence));
} break;
case MSG_FINISH: {
}
}
}
+
+ private final class MyLayoutResultCallback extends LayoutResultCallback {
+ private ILayoutResultCallback mCallback;
+ private final int mSequence;
+
+ public MyLayoutResultCallback(ILayoutResultCallback callback,
+ int sequence) {
+ mCallback = callback;
+ mSequence = sequence;
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ final ILayoutResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (info == null) {
+ throw new IllegalArgumentException("info cannot be null");
+ }
+ if (callback != null) {
+ try {
+ callback.onLayoutFinished(info, changed, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error) {
+ final ILayoutResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (callback != null) {
+ try {
+ callback.onLayoutFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutCancelled() {
+ synchronized (mLock) {
+ clearLocked();
+ }
+ }
+
+ private void clearLocked() {
+ mLayoutOrWriteCancellation = null;
+ mCallback = null;
+ }
+ }
+
+ private final class MyWriteResultCallback extends WriteResultCallback {
+ private FileDescriptor mFd;
+ private int mSequence;
+ private IWriteResultCallback mCallback;
+
+ public MyWriteResultCallback(IWriteResultCallback callback,
+ FileDescriptor fd, int sequence) {
+ mFd = fd;
+ mSequence = sequence;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages) {
+ final IWriteResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (pages == null) {
+ throw new IllegalArgumentException("pages cannot be null");
+ }
+ if (pages.length == 0) {
+ throw new IllegalArgumentException("pages cannot be empty");
+ }
+ if (callback != null) {
+ try {
+ callback.onWriteFinished(pages, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFinished", re);
+ }
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ final IWriteResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (callback != null) {
+ try {
+ callback.onWriteFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFailed", re);
+ }
+ }
+ }
+
+ @Override
+ public void onWriteCancelled() {
+ synchronized (mLock) {
+ clearLocked();
+ }
+ }
+
+ private void clearLocked() {
+ mLayoutOrWriteCancellation = null;
+ IoUtils.closeQuietly(mFd);
+ mCallback = null;
+ mFd = null;
+ }
+ }
}
}
--- /dev/null
+<?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.
+-->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/progress"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dip"
+ android:layout_gravity="center_horizontal"
+ style="?android:attr/progressBarStyleLarge">
+</ProgressBar>
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:orientation="vertical"
- android:scrollbars="vertical">
+ android:orientation="vertical">
- <GridLayout
- android:layout_width="wrap_content"
+ <ScrollView
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:columnCount="2">
+ android:scrollbars="vertical">
- <!-- 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_marginTop="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/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </view>
-
- <TextView
+ <GridLayout
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="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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </view>
-
- <TextView
- android:id="@+id/page_range_title"
- 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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </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"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Button>
-
- </GridLayout>
-
-</ScrollView>
+ 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_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="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/listPreferredItemHeight">
+ </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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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="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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </view>
+
+ <TextView
+ android:id="@+id/page_range_title"
+ 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"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </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>
+
+ </GridLayout>
+
+ </ScrollView>
+
+ <Button
+ android:id="@+id/print_button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:text="@string/print_button"
+ style="?android:attr/buttonBarButtonStyle">
+ </Button>
+
+</LinearLayout>
<!-- Title if the number of pages in a printed document is unknown. [CHAR LIMIT=20] -->
<string name="page_count_unknown">unknown</string>
- <!-- Notifications -->
+ <!-- Title for the temporary dialog show while an app is generating a print job. [CHAR LIMIT=30] -->
+ <string name="generating_print_job">Generating print job</string>
- <!-- Template for the notificaiton label for a queued print job. [CHAR LIMIT=25] -->
- <string name="queued_notification_title_template">Queued <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
+ <!-- Notifications -->
<!-- Template for the notificaiton label for a printing print job. [CHAR LIMIT=25] -->
<string name="printing_notification_title_template">Printing <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
<!-- Label for the notification button for restrating a filed print job. [CHAR LIMIT=25] -->
<string name="restart">Restart</string>
+ <!-- Message that there is no connection to a printer. [CHAR LIMIT=40] -->
+ <string name="no_connection_to_printer">No connection to printer</string>
+
<!-- Arrays -->
<!-- Color mode labels. -->
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED: {
- createQueuingNotificaiton(printJob);
- } break;
-
- case PrintJobInfo.STATE_STARTED: {
createPrintingNotificaiton(printJob);
} break;
}
}
- private void createQueuingNotificaiton(PrintJobInfo printJob) {
- Notification.Builder builder = new Notification.Builder(mContext)
- // TODO: Use appropriate icon when assets are ready
- .setSmallIcon(android.R.drawable.ic_secure)
- .setContentTitle(mContext.getString(R.string.queued_notification_title_template,
- printJob.getLabel()))
- // TODO: Use appropriate icon when assets are ready
- .addAction(android.R.drawable.ic_secure, mContext.getString(R.string.cancel),
- createCancelIntent(printJob))
- .setContentText(printJob.getPrinterId().getPrinterName())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
- }
-
private void createPrintingNotificaiton(PrintJobInfo printJob) {
Notification.Builder builder = new Notification.Builder(mContext)
// TODO: Use appropriate icon when assets are ready
package com.android.printspooler;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.widget.TextView;
import android.widget.Toast;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
private IBinder mIPrintDocumentAdapter;
+ private Dialog mGeneratingPrintJobDialog;
+
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
mSpooler.generateFileForPrintJob(mPrintJobId)));
- }
- @Override
- protected void onResume() {
- super.onResume();
try {
mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException re) {
finish();
return;
}
+
mController.initialize();
mEditor.initialize();
mPrinterDiscoveryObserver = new PrinterDiscoveryObserver(mEditor, getMainLooper());
}
@Override
- protected void onPause() {
+ protected void onDestroy() {
+ // We can safely do the work in here since at this point
+ // the system is bound to our (spooler) process which
+ // guarantees that this process will not be killed.
mSpooler.stopPrinterDiscovery();
mPrinterDiscoveryObserver.destroy();
mPrinterDiscoveryObserver = null;
- if (mController.isCancelled() || mController.isFailed()) {
+ if (mController.hasStarted()) {
+ mController.finish();
+ }
+ if (mEditor.isPrintConfirmed() && mController.isFinished()) {
+ mSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_QUEUED, null);
+ } else {
mSpooler.setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED, null);
- } else if (mController.hasStarted()) {
- mController.finish();
- if (mEditor.isPrintConfirmed()) {
- if (mController.isFinished()) {
- mSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_QUEUED, null);
- } else {
- mSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_CANCELED, null);
- }
- }
}
mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
- super.onPause();
+ if (mGeneratingPrintJobDialog != null) {
+ mGeneratingPrintJobDialog.dismiss();
+ mGeneratingPrintJobDialog = null;
+ }
+ super.onDestroy();
}
public boolean onTouchEvent(MotionEvent event) {
return !mOldPrintAttributes.equals(mCurrPrintAttributes);
}
+ private void showGeneratingPrintJobUi() {
+ getWindow().getDecorView().setVisibility(View.GONE);
+
+ DialogFragment fragment = new DialogFragment() {
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(PrintJobConfigActivity.this)
+ .setTitle(getString(R.string.generating_print_job))
+ .setView(PrintJobConfigActivity.this.getLayoutInflater().inflate(
+ R.layout.generating_print_job_dialog, null))
+ .setCancelable(false)
+ .setPositiveButton(getString(R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mEditor.cancel();
+ PrintJobConfigActivity.this.finish();
+ }
+ })
+ .create();
+ }
+ };
+ fragment.show(getFragmentManager(), getString(R.string.generating_print_job));
+ }
+
private class PrintController {
private final AtomicInteger mRequestCounter = new AtomicInteger();
private final RemotePrintDocumentAdapter mRemotePrintAdapter;
- private final Handler mHandler;
+ private final Bundle mMetadata;
- private int mControllerState = CONTROLLER_STATE_INITIALIZED;
+ private final ControllerHandler mHandler;
- private PageRange[] mRequestedPages;
-
- private Bundle mMetadata = new Bundle();
+ private final LayoutResultCallback mLayoutResultCallback;
- private final ILayoutResultCallback mILayoutResultCallback =
- new ILayoutResultCallback.Stub() {
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
- 0, info).sendToTarget();
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
- }
- }
- };
+ private final WriteResultCallback mWriteResultCallback;
- private IWriteResultCallback mIWriteResultCallback = new IWriteResultCallback.Stub() {
- @Override
- public void onWriteFinished(PageRange[] pages, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
- }
- }
+ private int mControllerState = CONTROLLER_STATE_INITIALIZED;
- @Override
- public void onWriteFailed(CharSequence error, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
- }
- }
- };
+ private PageRange[] mRequestedPages;
public PrintController(RemotePrintDocumentAdapter adapter) {
mRemotePrintAdapter = adapter;
- mHandler = new MyHandler(Looper.getMainLooper());
+ mMetadata = new Bundle();
+ mHandler = new ControllerHandler(getMainLooper());
+ mLayoutResultCallback = new LayoutResultCallback(mHandler);
+ mWriteResultCallback = new WriteResultCallback(mHandler);
}
public void initialize() {
return (mControllerState == CONTROLLER_STATE_FINISHED);
}
- public boolean isFailed() {
- return (mControllerState == CONTROLLER_STATE_FAILED);
- }
-
public boolean hasStarted() {
return mControllerState >= CONTROLLER_STATE_STARTED;
}
// If the attributes changes, then we do not do a layout but may
// have to ask the app to write some pages. Hence, pretend layout
// completed and nothing changed, so we handle writing as usual.
- handleOnLayoutFinished(mDocument.info, false);
+ handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get());
} else {
mSpooler.setPrintJobAttributesNoPersistence(mPrintJobId, mCurrPrintAttributes);
mControllerState = CONTROLLER_STATE_LAYOUT_STARTED;
mRemotePrintAdapter.layout(mOldPrintAttributes, mCurrPrintAttributes,
- mILayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
+ mLayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
}
mRemotePrintAdapter.finish();
}
- private void handleOnLayoutFinished(PrintDocumentInfo info, boolean layoutChanged) {
+ private void handleOnLayoutFinished(PrintDocumentInfo info,
+ boolean layoutChanged, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
+
if (isCancelled()) {
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
// Request a write of the pages of interest.
mControllerState = CONTROLLER_STATE_WRITE_STARTED;
- mRemotePrintAdapter.write(mRequestedPages, mIWriteResultCallback,
+ mRemotePrintAdapter.write(mRequestedPages, mWriteResultCallback,
mRequestCounter.incrementAndGet());
}
- private void handleOnLayoutFailed(CharSequence error) {
+ private void handleOnLayoutFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
mControllerState = CONTROLLER_STATE_FAILED;
// TODO: We need some UI for announcing an error.
Log.e(LOG_TAG, "Error during layout: " + error);
PrintJobConfigActivity.this.finish();
}
- private void handleOnWriteFinished(PageRange[] pages) {
+ private void handleOnWriteFinished(PageRange[] pages, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
+
if (isCancelled()) {
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
}
- private void handleOnWriteFailed(CharSequence error) {
+ private void handleOnWriteFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
mControllerState = CONTROLLER_STATE_FAILED;
Log.e(LOG_TAG, "Error during write: " + error);
PrintJobConfigActivity.this.finish();
}
- private final class MyHandler extends Handler {
+ private final class ControllerHandler 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) {
+ public ControllerHandler(Looper looper) {
super(looper, null, false);
}
case MSG_ON_LAYOUT_FINISHED: {
PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
final boolean changed = (message.arg1 == 1);
- mController.handleOnLayoutFinished(info, changed);
+ final int sequence = message.arg2;
+ handleOnLayoutFinished(info, changed, sequence);
} break;
case MSG_ON_LAYOUT_FAILED: {
CharSequence error = (CharSequence) message.obj;
- mController.handleOnLayoutFailed(error);
+ final int sequence = message.arg1;
+ handleOnLayoutFailed(error, sequence);
} break;
case MSG_ON_WRITE_FINISHED: {
PageRange[] pages = (PageRange[]) message.obj;
- mController.handleOnWriteFinished(pages);
+ final int sequence = message.arg1;
+ handleOnWriteFinished(pages, sequence);
} break;
case MSG_ON_WRITE_FAILED: {
CharSequence error = (CharSequence) message.obj;
- mController.handleOnWriteFailed(error);
+ final int sequence = message.arg1;
+ handleOnWriteFailed(error, sequence);
} break;
}
}
}
}
+ private static final class LayoutResultCallback extends ILayoutResultCallback.Stub {
+ private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
+
+ public LayoutResultCallback(PrintController.ControllerHandler handler) {
+ mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FINISHED,
+ changed ? 1 : 0, sequence, info).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+ }
+
+ private static final class WriteResultCallback extends IWriteResultCallback.Stub {
+ private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
+
+ public WriteResultCallback(PrintController.ControllerHandler handler) {
+ mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FINISHED,
+ sequence, 0, pages).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+ }
+
private final class Editor {
private final EditText mCopiesEditText;
mEditor.confirmPrint();
updateUi();
mController.update();
+ showGeneratingPrintJobUi();
}
});
// Update the notification.
mNotificationController.onPrintJobStateChanged(printJob);
- //TODO: Figure out what the right policy for read print jobs is.
-
switch (printJob.getState()) {
- case PrintJobInfo.STATE_QUEUED: {
- // Notify that we have a queued job.
- mService.onPrintJobQueued(new PrintJobInfo(printJob));
- } break;
-
+ case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
- // We really want to restart this print job.
- setPrintJobState(printJob.getId(), PrintJobInfo.STATE_QUEUED, null);
+ // We have a print job that was queued or started in the past
+ // but the device battery died or a crash occurred. In this case
+ // we assume the print job failed and let the user decide whether
+ // to restart the job or just
+ setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+ mService.getString(R.string.no_connection_to_printer));
} break;
}
}