summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/PrintSpooler/res/layout/print_activity_controls.xml3
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java100
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java163
3 files changed, 178 insertions, 88 deletions
diff --git a/packages/PrintSpooler/res/layout/print_activity_controls.xml b/packages/PrintSpooler/res/layout/print_activity_controls.xml
index a87afe0a77a9..248d0c05934a 100644
--- a/packages/PrintSpooler/res/layout/print_activity_controls.xml
+++ b/packages/PrintSpooler/res/layout/print_activity_controls.xml
@@ -239,7 +239,8 @@
android:singleLine="true"
android:ellipsize="end"
android:visibility="visible"
- android:inputType="textNoSuggestions">
+ android:inputType="number"
+ android:digits="0123456789 ,-">
</com.android.printspooler.widget.CustomErrorEditText>
</LinearLayout>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index cde0fa3b4896..e7aebddf5aa8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -62,7 +62,6 @@ import android.printservice.PrintServiceInfo;
import android.provider.DocumentsContract;
import android.text.Editable;
import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
import android.text.TextWatcher;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -117,8 +116,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
@@ -165,22 +162,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
private static final int MIN_COPIES = 1;
private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES);
- 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(
- "[\\s]*[0-9]+[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
- + "[\\s]*[0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
-
private boolean mIsOptionsUiBound = false;
private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
new PrinterAvailabilityDetector();
- private final SimpleStringSplitter mStringCommaSplitter = new SimpleStringSplitter(',');
-
private final OnFocusChangeListener mSelectAllOnFocusListener = new SelectAllOnFocusListener();
private PrintSpoolerProvider mSpoolerProvider;
@@ -1493,9 +1479,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
cancelPrint();
}
} else if (view == mMoreOptionsButton) {
- // The selected pages is only applied once the user leaves the text field. A click
- // on this button, does not count as leaving.
- updateSelectedPagesFromTextField();
+ if (mPageRangeEditText.getError() == null) {
+ // The selected pages is only applied once the user leaves the text field. A click
+ // on this button, does not count as leaving.
+ updateSelectedPagesFromTextField();
+ }
if (mCurrentPrinter != null) {
startAdvancedPrintOptionsActivity(mCurrentPrinter);
@@ -1918,42 +1906,10 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
- List<PageRange> pageRanges = new ArrayList<>();
- mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
-
- while (mStringCommaSplitter.hasNext()) {
- String range = mStringCommaSplitter.next().trim();
- if (TextUtils.isEmpty(range)) {
- continue;
- }
- final int dashIndex = range.indexOf('-');
- final int fromIndex;
- final int toIndex;
-
- if (dashIndex > 0) {
- fromIndex = Integer.parseInt(range.substring(0, dashIndex).trim()) - 1;
- // It is possible that the dash is at the end since the input
- // verification can has to allow the user to keep entering if
- // this would lead to a valid input. So we handle this.
- if (dashIndex < range.length() - 1) {
- String fromString = range.substring(dashIndex + 1, range.length()).trim();
- toIndex = Integer.parseInt(fromString) - 1;
- } else {
- toIndex = fromIndex;
- }
- } else {
- fromIndex = toIndex = Integer.parseInt(range) - 1;
- }
-
- PageRange pageRange = new PageRange(Math.min(fromIndex, toIndex),
- Math.max(fromIndex, toIndex));
- pageRanges.add(pageRange);
- }
-
- PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
- pageRanges.toArray(pageRangesArray);
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
- return PageRangeUtils.normalize(pageRangesArray);
+ return PageRangeUtils.parsePageRanges(mPageRangeEditText.getText(), pageCount);
}
return PageRange.ALL_PAGES_ARRAY;
@@ -2785,7 +2741,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
editText.setSelection(editText.getText().length());
}
- if (view == mPageRangeEditText && !hasFocus) {
+ if (view == mPageRangeEditText && !hasFocus && mPageRangeEditText.getError() == null) {
updateSelectedPagesFromTextField();
}
}
@@ -2805,18 +2761,12 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
@Override
public void afterTextChanged(Editable editable) {
final boolean hadErrors = hasErrors();
- String text = editable.toString();
- if (TextUtils.isEmpty(text)) {
- if (mPageRangeEditText.getError() == null) {
- mPageRangeEditText.setError("");
- updateOptionsUi();
- }
- return;
- }
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
+ PageRange[] ranges = PageRangeUtils.parsePageRanges(editable, pageCount);
- String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
- if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
+ if (ranges.length == 0) {
if (mPageRangeEditText.getError() == null) {
mPageRangeEditText.setError("");
updateOptionsUi();
@@ -2824,30 +2774,6 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
return;
}
- PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
- final int pageCount = (info != null) ? getAdjustedPageCount(info) : 0;
-
- // The range
- Matcher matcher = PATTERN_DIGITS.matcher(text);
- while (matcher.find()) {
- String numericString = text.substring(matcher.start(), matcher.end()).trim();
- if (TextUtils.isEmpty(numericString)) {
- continue;
- }
- final int pageIndex = Integer.parseInt(numericString);
- if (pageIndex < 1 || pageIndex > pageCount) {
- if (mPageRangeEditText.getError() == null) {
- mPageRangeEditText.setError("");
- updateOptionsUi();
- }
- return;
- }
- }
-
- // We intentionally do not catch the case of the from page being
- // greater than the to page. When computing the requested pages
- // we just swap them if necessary.
-
if (mPageRangeEditText.getError() != null) {
mPageRangeEditText.setError(null);
updateOptionsUi();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
index 2b317b3cbef0..7425c033a7a4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
@@ -18,7 +18,9 @@ package com.android.printspooler.util;
import android.print.PageRange;
import android.print.PrintDocumentInfo;
+import android.util.Pair;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -155,6 +157,167 @@ public final class PageRangeUtils {
}
/**
+ * Return the next position after {@code pos} that is not a space character.
+ *
+ * @param s The string to parse
+ * @param pos The starting position
+ *
+ * @return The position of the first space character
+ */
+ private static int readWhiteSpace(CharSequence s, int pos) {
+ while (pos < s.length() && s.charAt(pos) == ' ') {
+ pos++;
+ }
+
+ return pos;
+ }
+
+ /**
+ * Read a number from a string at a certain position.
+ *
+ * @param s The string to parse
+ * @param pos The starting position
+ *
+ * @return The position after the number + the number read or null if the number was not found
+ */
+ private static Pair<Integer, Integer> readNumber(CharSequence s, int pos) {
+ Integer result = 0;
+ while (pos < s.length() && s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
+ // Number cannot start with 0
+ if (result == 0 && s.charAt(pos) == '0') {
+ break;
+ }
+ result = result * 10 + (s.charAt(pos) - '0');
+ // Abort on overflow
+ if (result < 0) {
+ break;
+ }
+ pos++;
+ }
+
+ // 0 is not a valid page number
+ if (result == 0) {
+ return new Pair<>(pos, null);
+ } else {
+ return new Pair<>(pos, result);
+ }
+ }
+
+ /**
+ * Read a single character from a string at a certain position.
+ *
+ * @param s The string to parse
+ * @param pos The starting position
+ * @param expectedChar The character to read
+ *
+ * @return The position after the character + the character read or null if the character was
+ * not found
+ */
+ private static Pair<Integer, Character> readChar(CharSequence s, int pos, char expectedChar) {
+ if (pos < s.length() && s.charAt(pos) == expectedChar) {
+ return new Pair<>(pos + 1, expectedChar);
+ } else {
+ return new Pair<>(pos, null);
+ }
+ }
+
+ /**
+ * Read a page range character from a string at a certain position.
+ *
+ * @param s The string to parse
+ * @param pos The starting position
+ * @param maxPageNumber The highest page number to accept.
+ *
+ * @return The position after the page range + the page range read or null if the page range was
+ * not found
+ */
+ private static Pair<Integer, PageRange> readRange(CharSequence s, int pos, int maxPageNumber) {
+ Pair<Integer, Integer> retInt;
+ Pair<Integer, Character> retChar;
+
+ Character comma;
+ if (pos == 0) {
+ // When we reading the first range, we do not want to have a comma
+ comma = ',';
+ } else {
+ retChar = readChar(s, pos, ',');
+ pos = retChar.first;
+ comma = retChar.second;
+ }
+
+ pos = readWhiteSpace(s, pos);
+
+ retInt = readNumber(s, pos);
+ pos = retInt.first;
+ Integer start = retInt.second;
+
+ pos = readWhiteSpace(s, pos);
+
+ retChar = readChar(s, pos, '-');
+ pos = retChar.first;
+ Character separator = retChar.second;
+
+ pos = readWhiteSpace(s, pos);
+
+ retInt = readNumber(s, pos);
+ pos = retInt.first;
+ Integer end = retInt.second;
+
+ pos = readWhiteSpace(s, pos);
+
+ if (comma != null &&
+ // range, maybe unbounded
+ ((separator != null && (start != null || end != null)) ||
+ // single page
+ (separator == null && start != null && end == null))) {
+ if (start == null) {
+ start = 1;
+ }
+
+ if (end == null) {
+ if (separator == null) {
+ end = start;
+ } else {
+ end = maxPageNumber;
+ }
+ }
+
+ if (start <= end && start >= 1 && end <= maxPageNumber) {
+ return new Pair<>(pos, new PageRange(start - 1, end - 1));
+ }
+ }
+
+ return new Pair<>(pos, null);
+ }
+
+ /**
+ * Parse a string into an array of page ranges.
+ *
+ * @param s The string to parse
+ * @param maxPageNumber The highest page number to accept.
+ *
+ * @return The parsed ranges or null if the string could not be parsed.
+ */
+ public static PageRange[] parsePageRanges(CharSequence s, int maxPageNumber) {
+ ArrayList<PageRange> ranges = new ArrayList<>();
+
+ int pos = 0;
+ while (pos < s.length()) {
+ Pair<Integer, PageRange> retRange = readRange(s, pos, maxPageNumber);
+
+ if (retRange.second == null) {
+ ranges.clear();
+ break;
+ }
+
+ ranges.add(retRange.second);
+ pos = retRange.first;
+ }
+
+ return PageRangeUtils.normalize(ranges.toArray(new PageRange[ranges.size()]));
+ }
+
+ /**
* Offsets a the start and end of page ranges with the given value.
*
* @param pageRanges The page ranges to offset.