diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2013-10-09 10:53:26 -0700 |
---|---|---|
committer | Svetoslav <svetoslavganov@google.com> | 2013-10-11 10:04:02 -0700 |
commit | caff38821ad81389b5baf2053ba851c38272ec63 (patch) | |
tree | 6d7713cd0ec6a26608af5a7f0ba80d4979c9ff06 /packages/PrintSpooler | |
parent | 1db8cf12a985425a73d24875d9d308c14c0b4359 (diff) | |
download | frameworks_base-caff38821ad81389b5baf2053ba851c38272ec63.zip frameworks_base-caff38821ad81389b5baf2053ba851c38272ec63.tar.gz frameworks_base-caff38821ad81389b5baf2053ba851c38272ec63.tar.bz2 |
Added UI for errors during layout and write.
1. If an error happens during layout or write we show an error
message with the string provided by the application which
has an OK button to retry or tap outside to cancel.
2. Updated the targed and min SDK version for the PrintSpooler.
bug:11127269
Change-Id: I4301cf3716119b1e33b95347a8451fc1c128343b
Diffstat (limited to 'packages/PrintSpooler')
4 files changed, 199 insertions, 25 deletions
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 1e6954e..e884558 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -41,8 +41,6 @@ <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/> - <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/> - <application android:allowClearUserData="true" android:label="@string/app_label" diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml new file mode 100644 index 0000000..222b5b6 --- /dev/null +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml @@ -0,0 +1,65 @@ +<?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:id="@+id/content_generating" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="@color/editable_background" + android:orientation="vertical"> + + <TextView + android:id="@+id/message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dip" + android:layout_marginEnd="16dip" + android:layout_marginTop="32dip" + android:layout_marginBottom="32dip" + android:layout_gravity="center" + style="?android:attr/buttonBarButtonStyle" + android:singleLine="true" + android:ellipsize="end" + android:text="@string/print_error_default_message" + android:textColor="@color/important_text" + android:textSize="16sp"> + </TextView> + + <View + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="@color/separator"> + </View> + + </LinearLayout> + + <Button + android:id="@+id/ok_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_horizontal" + style="?android:attr/buttonBarButtonStyle" + android:text="@android:string/ok" + android:textSize="16sp" + android:textColor="@color/important_text"> + </Button> + +</LinearLayout> diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 67c455d..d74b414 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -44,7 +44,7 @@ <string name="label_pages">Pages (<xliff:g id="page_count" example="5">%1$s</xliff:g>)</string> <!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=20] --> - <string name="pages_range_example">e.g. 1–5, 8, 11–13</string> + <string name="pages_range_example">e.g. 1—5,8,11—13</string> <!-- Title for the pring preview button .[CHAR LIMIT=30] --> <string name="print_preview">Print preview</string> @@ -142,6 +142,9 @@ <!-- Label for a printer that is not available. [CHAR LIMIT=25] --> <string name="printer_unavailable"><xliff:g id="print_job_name" example="Canon-123GHT">%1$s</xliff:g> – unavailable</string> + <!-- Default message of an alert dialog for app error while generating a print job. [CHAR LIMIT=50] --> + <string name="print_error_default_message">Couldn\'t generate print job</string> + <!-- Arrays --> <!-- Color mode labels. --> diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 2922dd1..b5b2b3f 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -84,6 +84,8 @@ import android.widget.TextView; import com.android.printspooler.MediaSizeUtils.MediaSizeComparator; +import libcore.io.IoUtils; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -100,8 +102,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import libcore.io.IoUtils; - /** * Activity for configuring a print job. */ @@ -339,6 +339,10 @@ public class PrintJobConfigActivity extends Activity { return mControllerState >= CONTROLLER_STATE_LAYOUT_COMPLETED; } + public boolean isPerformingLayout() { + return mControllerState == CONTROLLER_STATE_LAYOUT_STARTED; + } + public boolean isWorking() { return mControllerState == CONTROLLER_STATE_LAYOUT_STARTED || mControllerState == CONTROLLER_STATE_WRITE_STARTED; @@ -354,9 +358,18 @@ public class PrintJobConfigActivity extends Activity { if (!mController.hasStarted()) { mController.start(); } + + // If the print attributes are the same and we are performing + // a layout, then we have to wait for it to completed which will + // trigger writing of the necessary pages. + final boolean printAttributesChanged = printAttributesChanged(); + if (!printAttributesChanged && isPerformingLayout()) { + return; + } + // If print is confirmed we always do a layout since the previous // ones were for preview and this one is for printing. - if (!printAttributesChanged() && !mEditor.isPrintConfirmed()) { + if (!printAttributesChanged && !mEditor.isPrintConfirmed()) { if (mDocument.info == null) { // We are waiting for the result of a layout, so do nothing. return; @@ -474,14 +487,20 @@ public class PrintJobConfigActivity extends Activity { mRequestCounter.incrementAndGet()); } - private void handleOnLayoutFailed(CharSequence error, int sequence) { + private void handleOnLayoutFailed(final 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(); + mEditor.showUi(Editor.UI_ERROR, new Runnable() { + @Override + public void run() { + if (!TextUtils.isEmpty(error)) { + TextView messageView = (TextView) findViewById(R.id.message); + messageView.setText(error); + } + } + }); } private void handleOnWriteFinished(PageRange[] pages, int sequence) { @@ -577,13 +596,20 @@ public class PrintJobConfigActivity extends Activity { } } - private void handleOnWriteFailed(CharSequence error, int sequence) { + private void handleOnWriteFailed(final CharSequence error, int sequence) { if (mRequestCounter.get() != sequence) { return; } mControllerState = CONTROLLER_STATE_FAILED; - Log.e(LOG_TAG, "Error during write: " + error); - PrintJobConfigActivity.this.finish(); + mEditor.showUi(Editor.UI_ERROR, new Runnable() { + @Override + public void run() { + if (!TextUtils.isEmpty(error)) { + TextView messageView = (TextView) findViewById(R.id.message); + messageView.setText(error); + } + } + }); } private boolean equalsIgnoreSize(PrintDocumentInfo lhs, PrintDocumentInfo rhs) { @@ -781,6 +807,7 @@ public class PrintJobConfigActivity extends Activity { private static final int UI_NONE = 0; private static final int UI_EDITING_PRINT_JOB = 1; private static final int UI_GENERATING_PRINT_JOB = 2; + private static final int UI_ERROR = 3; private EditText mCopiesEditText; @@ -1282,6 +1309,21 @@ public class PrintJobConfigActivity extends Activity { updateUi(); } + public void reselectCurrentPrinter() { + if (mCurrentPrinter != null) { + // TODO: While the data did not change and we set the adapter + // to a newly inflated spinner, the latter does not show the + // current item unless we poke the adapter. This requires more + // investigation. Maybe an optimization in AdapterView does not + // call into the adapter if the view is not visible which is the + // case when we set the adapter. + mDestinationSpinnerAdapter.notifyDataSetChanged(); + final int position = mDestinationSpinnerAdapter.getPrinterIndex( + mCurrentPrinter.getId()); + mDestinationSpinner.setSelection(position); + } + } + public void refreshCurrentPrinter() { PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem(); if (printer != null) { @@ -1379,7 +1421,10 @@ public class PrintJobConfigActivity extends Activity { return; } - switch (mCurrentUi) { + final int oldUi = mCurrentUi; + mCurrentUi = ui; + + switch (oldUi) { case UI_NONE: { switch (ui) { case UI_EDITING_PRINT_JOB: { @@ -1416,6 +1461,21 @@ public class PrintJobConfigActivity extends Activity { new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); } break; + + case UI_ERROR: { + animateUiSwitch(R.layout.print_job_config_activity_content_error, + new Runnable() { + @Override + public void run() { + registerOkButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } + }, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + } break; } } break; @@ -1435,11 +1495,43 @@ public class PrintJobConfigActivity extends Activity { new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER)); } break; + + case UI_ERROR: { + animateUiSwitch(R.layout.print_job_config_activity_content_error, + new Runnable() { + @Override + public void run() { + registerOkButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } + }, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + } break; } } break; - } - mCurrentUi = ui; + case UI_ERROR: { + switch (ui) { + case UI_EDITING_PRINT_JOB: { + animateUiSwitch(R.layout.print_job_config_activity_content_editing, + new Runnable() { + @Override + public void run() { + registerPrintButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } + }, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER)); + } break; + } + } break; + } } private void registerPrintButtonClickListener() { @@ -1475,13 +1567,33 @@ public class PrintJobConfigActivity extends Activity { }); } + private void registerOkButtonClickListener() { + Button okButton = (Button) findViewById(R.id.ok_button); + okButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mEditor.showUi(Editor.UI_EDITING_PRINT_JOB, new Runnable() { + @Override + public void run() { + // Start over with a clean slate. + mOldPrintAttributes.clear(); + mController.initialize(); + mEditor.initialize(); + mEditor.bindUi(); + mEditor.reselectCurrentPrinter(); + } + }); + } + }); + } + private void doUiSwitch(int showLayoutId) { ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container); contentContainer.removeAllViews(); getLayoutInflater().inflate(showLayoutId, contentContainer, true); } - private void animateUiSwitch(int showLayoutId, final Runnable postAnimateCommand, + private void animateUiSwitch(int showLayoutId, final Runnable beforeShowNewUiAction, final LayoutParams containerParams) { // Find everything we will shuffle around. final ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container); @@ -1510,7 +1622,7 @@ public class PrintJobConfigActivity extends Activity { / (float) contentContainer.getHeight(); // Second animation - resize the container. - AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY).withLayer() + AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY) .withEndAction(new Runnable() { @Override public void run() { @@ -1521,14 +1633,10 @@ public class PrintJobConfigActivity extends Activity { contentContainer.setLayoutParams(containerParams); + beforeShowNewUiAction.run(); + // Third animation - show the new content. - AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f) - .withEndAction(new Runnable() { - @Override - public void run() { - postAnimateCommand.run(); - } - }); + AutoCancellingAnimator.animate(showingView).alpha(1.0f); } }); } |