diff options
| -rw-r--r-- | core/api/current.txt | 12 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 353 | ||||
| -rw-r--r-- | core/res/res/values/attrs.xml | 17 | ||||
| -rw-r--r-- | core/res/res/values/public-staging.xml | 2 |
4 files changed, 382 insertions, 2 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 5878fc5c3531..c930e3ea06c3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -744,6 +744,7 @@ package android { field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final int focusedByDefault = 16844100; // 0x1010544 field @Deprecated public static final int focusedMonthDateColor = 16843587; // 0x1010343 + field public static final int focusedSearchResultHighlightColor; field public static final int font = 16844082; // 0x1010532 field public static final int fontFamily = 16843692; // 0x10103ac field public static final int fontFeatureSettings = 16843959; // 0x10104b7 @@ -1355,6 +1356,7 @@ package android { field public static final int searchHintIcon = 16843988; // 0x10104d4 field public static final int searchIcon = 16843907; // 0x1010483 field public static final int searchMode = 16843221; // 0x10101d5 + field public static final int searchResultHighlightColor; field public static final int searchSettingsDescription = 16843402; // 0x101028a field public static final int searchSuggestAuthority = 16843222; // 0x10101d6 field public static final int searchSuggestIntentAction = 16843225; // 0x10101d9 @@ -59275,6 +59277,7 @@ package android.widget { method public void append(CharSequence, int, int); method public void beginBatchEdit(); method public boolean bringPointIntoView(int); + method public boolean bringPointIntoView(@IntRange(from=0) int, boolean); method public void clearComposingText(); method public void debug(int); method public boolean didTouchFocusSelect(); @@ -59312,6 +59315,8 @@ package android.widget { method public int getExtendedPaddingTop(); method public android.text.InputFilter[] getFilters(); method public int getFirstBaselineToTopHeight(); + method @ColorInt public int getFocusedSearchResultHighlightColor(); + method public int getFocusedSearchResultIndex(); method @Nullable public String getFontFeatureSettings(); method @Nullable public String getFontVariationSettings(); method public boolean getFreezesText(); @@ -59356,6 +59361,8 @@ package android.widget { method public android.text.TextPaint getPaint(); method public int getPaintFlags(); method public String getPrivateImeOptions(); + method @ColorInt public int getSearchResultHighlightColor(); + method @Nullable public int[] getSearchResultHighlights(); method public int getSelectionEnd(); method public int getSelectionStart(); method @ColorInt public int getShadowColor(); @@ -59440,6 +59447,8 @@ package android.widget { method public void setFallbackLineSpacing(boolean); method public void setFilters(android.text.InputFilter[]); method public void setFirstBaselineToTopHeight(@IntRange(from=0) @Px int); + method public void setFocusedSearchResultHighlightColor(@ColorInt int); + method public void setFocusedSearchResultIndex(int); method public void setFontFeatureSettings(@Nullable String); method public boolean setFontVariationSettings(@Nullable String); method protected boolean setFrame(int, int, int, int); @@ -59487,6 +59496,8 @@ package android.widget { method public void setPrivateImeOptions(String); method public void setRawInputType(int); method public void setScroller(android.widget.Scroller); + method public void setSearchResultHighlightColor(@ColorInt int); + method public void setSearchResultHighlights(@Nullable int...); method public void setSelectAllOnFocus(boolean); method public void setShadowLayer(float, float, float, int); method public final void setShowSoftInputOnFocus(boolean); @@ -59526,6 +59537,7 @@ package android.widget { method public void setWidth(int); field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0 field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1 + field public static final int FOCUSED_SEARCH_RESULT_INDEX_NONE = -1; // 0xffffffff } public enum TextView.BufferType { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 4005bc86af39..d6c2d301443b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -937,6 +937,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private List<Path> mHighlightPaths; private List<Paint> mHighlightPaints; private Highlights mHighlights; + private int[] mSearchResultHighlights = null; + private Paint mSearchResultHighlightPaint = null; + private Paint mFocusedSearchResultHighlightPaint = null; + private int mFocusedSearchResultHighlightColor = 0xFFFF9632; + private int mSearchResultHighlightColor = 0xFFFFFF00; + + private int mFocusedSearchResultIndex = -1; private int mGesturePreviewHighlightStart = -1; private int mGesturePreviewHighlightEnd = -1; private Paint mGesturePreviewHighlightPaint; @@ -4030,6 +4037,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private static class TextAppearanceAttributes { int mTextColorHighlight = 0; + int mSearchResultHighlightColor = 0; + int mFocusedSearchResultHighlightColor = 0; ColorStateList mTextColor = null; ColorStateList mTextColorHint = null; ColorStateList mTextColorLink = null; @@ -4062,6 +4071,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public String toString() { return "TextAppearanceAttributes {\n" + " mTextColorHighlight:" + mTextColorHighlight + "\n" + + " mSearchResultHighlightColor: " + mSearchResultHighlightColor + "\n" + + " mFocusedSearchResultHighlightColor: " + + mFocusedSearchResultHighlightColor + "\n" + " mTextColor:" + mTextColor + "\n" + " mTextColorHint:" + mTextColorHint + "\n" + " mTextColorLink:" + mTextColorLink + "\n" @@ -4100,6 +4112,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener static { sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColorHighlight, com.android.internal.R.styleable.TextAppearance_textColorHighlight); + sAppearanceValues.put(com.android.internal.R.styleable.TextView_searchResultHighlightColor, + com.android.internal.R.styleable.TextAppearance_searchResultHighlightColor); + sAppearanceValues.put( + com.android.internal.R.styleable.TextView_focusedSearchResultHighlightColor, + com.android.internal.R.styleable.TextAppearance_focusedSearchResultHighlightColor); sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColor, com.android.internal.R.styleable.TextAppearance_textColor); sAppearanceValues.put(com.android.internal.R.styleable.TextView_textColorHint, @@ -4174,6 +4191,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener attributes.mTextColorHighlight = appearance.getColor(attr, attributes.mTextColorHighlight); break; + case com.android.internal.R.styleable.TextAppearance_searchResultHighlightColor: + attributes.mSearchResultHighlightColor = + appearance.getColor(attr, attributes.mSearchResultHighlightColor); + break; + case com.android.internal.R.styleable + .TextAppearance_focusedSearchResultHighlightColor: + attributes.mFocusedSearchResultHighlightColor = + appearance.getColor(attr, + attributes.mFocusedSearchResultHighlightColor); + break; case com.android.internal.R.styleable.TextAppearance_textColor: attributes.mTextColor = appearance.getColorStateList(attr); break; @@ -4290,6 +4317,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setHighlightColor(attributes.mTextColorHighlight); } + if (attributes.mSearchResultHighlightColor != 0) { + setSearchResultHighlightColor(attributes.mSearchResultHighlightColor); + } + + if (attributes.mFocusedSearchResultHighlightColor != 0) { + setFocusedSearchResultHighlightColor(attributes.mFocusedSearchResultHighlightColor); + } + if (attributes.mTextSize != -1) { mTextSizeUnit = attributes.mTextSizeUnit; setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */); @@ -6176,6 +6211,238 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Sets the search result ranges with flatten range representation. + * + * Ranges are represented of flattened inclusive start and exclusive end integers array. The + * inclusive start offset of the {@code i}-th range is stored in {@code 2 * i}-th of the array. + * The exclusive end offset of the {@code i}-th range is stored in {@code 2* i + 1}-th of the + * array. For example, the two ranges: (1, 2) and (3, 4) are flattened into single int array + * [1, 2, 3, 4]. + * + * TextView will render the search result with the highlights with specified color in the theme. + * If there is a focused search result, it is rendered with focused color. By calling this + * method, the focused search index will be cleared. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + * + * @param ranges the flatten ranges of the search result. null for clear. + */ + public void setSearchResultHighlights(@Nullable int... ranges) { + if (ranges == null) { + mSearchResultHighlights = null; + mHighlightPathsBogus = true; + return; + } + if (ranges.length % 2 == 1) { + throw new IllegalArgumentException( + "Flatten ranges must have even numbered elements"); + } + for (int j = 0; j < ranges.length / 2; ++j) { + int start = ranges[j * 2]; + int end = ranges[j * 2 + 1]; + if (start > end) { + throw new IllegalArgumentException( + "Reverse range found in the flatten range: " + start + ", " + end + "" + + " at " + j + "-th range"); + } + } + mHighlightPathsBogus = true; + mSearchResultHighlights = ranges; + mFocusedSearchResultIndex = FOCUSED_SEARCH_RESULT_INDEX_NONE; + invalidate(); + } + + /** + * Gets the current search result ranges. + * + * @see #setSearchResultHighlights(int[]) + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + * + * @return a flatten search result ranges. null if not available. + */ + @Nullable + public int[] getSearchResultHighlights() { + return mSearchResultHighlights; + } + + /** + * A special index used for {@link #setFocusedSearchResultIndex(int)} and + * {@link #getFocusedSearchResultIndex()} inidicating there is no focused search result. + */ + public static final int FOCUSED_SEARCH_RESULT_INDEX_NONE = -1; + + /** + * Sets the focused search result index. + * + * The focused search result is drawn in a focused color. + * Calling {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE} for clearing focused search result. + * + * This method must be called after setting search result ranges by + * {@link #setSearchResultHighlights(int[])}. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + * + * @param index a focused search index or {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE} + */ + public void setFocusedSearchResultIndex(int index) { + if (mSearchResultHighlights == null) { + throw new IllegalArgumentException("Search result range must be set beforehand."); + } + if (index < -1 || index >= mSearchResultHighlights.length / 2) { + throw new IllegalArgumentException("Focused index(" + index + ") must be larger than " + + "-1 and less than range count(" + (mSearchResultHighlights.length / 2) + ")"); + } + mFocusedSearchResultIndex = index; + mHighlightPathsBogus = true; + invalidate(); + } + + /** + * Gets the focused search result index. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + + * @return a focused search index or {@link #FOCUSED_SEARCH_RESULT_INDEX_NONE} + */ + public int getFocusedSearchResultIndex() { + return mFocusedSearchResultIndex; + } + + /** + * Sets the search result highlight color. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + + * @param color a search result highlight color. + */ + public void setSearchResultHighlightColor(@ColorInt int color) { + mSearchResultHighlightColor = color; + } + + /** + * Gets the search result highlight color. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + + * @return a search result highlight color. + */ + @ColorInt + public int getSearchResultHighlightColor() { + return mSearchResultHighlightColor; + } + + /** + * Sets focused search result highlight color. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + + * @param color a focused search result highlight color. + */ + public void setFocusedSearchResultHighlightColor(@ColorInt int color) { + mFocusedSearchResultHighlightColor = color; + } + + /** + * Gets focused search result highlight color. + * + * @attr ref android.R.styleable#TextView_searchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_searchResultHighlightColor + * @attr ref android.R.styleable#TextView_focusedSearchResultHighlightColor + * @attr ref android.R.styleable#TextAppearance_focusedSearchResultHighlightColor + * + * @see #setSearchResultHighlights(int[]) + * @see #getSearchResultHighlights() + * @see #setFocusedSearchResultIndex(int) + * @see #getFocusedSearchResultIndex() + * @see #setSearchResultHighlightColor(int) + * @see #getSearchResultHighlightColor() + * @see #setFocusedSearchResultHighlightColor(int) + * @see #getFocusedSearchResultHighlightColor() + + * @return a focused search result highlight color. + */ + @ColorInt + public int getFocusedSearchResultHighlightColor() { + return mFocusedSearchResultHighlightColor; + } + + /** * Highlights the text range (from inclusive start offset to exclusive end offset) to show what * will be selected by the ongoing select handwriting gesture. While the gesture preview * highlight is shown, the selection or cursor is hidden. If the text or selection is changed, @@ -8335,7 +8602,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener for (int i = 0; i < mHighlights.getSize(); ++i) { final int[] ranges = mHighlights.getRanges(i); final Paint paint = mHighlights.getPaint(i); - final Path path; if (mPathRecyclePool.isEmpty()) { path = new Path(); @@ -8363,6 +8629,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + addSearchHighlightPaths(); + if (hasGesturePreviewHighlight()) { final Path path; if (mPathRecyclePool.isEmpty()) { @@ -8381,6 +8649,67 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mHighlightPathsBogus = false; } + private void addSearchHighlightPaths() { + if (mSearchResultHighlights != null) { + final Path searchResultPath; + if (mPathRecyclePool.isEmpty()) { + searchResultPath = new Path(); + } else { + searchResultPath = mPathRecyclePool.get(mPathRecyclePool.size() - 1); + mPathRecyclePool.remove(mPathRecyclePool.size() - 1); + searchResultPath.reset(); + } + final Path focusedSearchResultPath; + if (mFocusedSearchResultIndex == FOCUSED_SEARCH_RESULT_INDEX_NONE) { + focusedSearchResultPath = null; + } else if (mPathRecyclePool.isEmpty()) { + focusedSearchResultPath = new Path(); + } else { + focusedSearchResultPath = mPathRecyclePool.get(mPathRecyclePool.size() - 1); + mPathRecyclePool.remove(mPathRecyclePool.size() - 1); + focusedSearchResultPath.reset(); + } + + boolean atLeastOnePathAdded = false; + for (int j = 0; j < mSearchResultHighlights.length / 2; ++j) { + final int start = mSearchResultHighlights[2 * j]; + final int end = mSearchResultHighlights[2 * j + 1]; + if (start < end) { + if (j == mFocusedSearchResultIndex) { + mLayout.getSelection(start, end, (left, top, right, bottom, layout) -> + focusedSearchResultPath.addRect(left, top, right, bottom, + Path.Direction.CW) + ); + } else { + mLayout.getSelection(start, end, (left, top, right, bottom, layout) -> + searchResultPath.addRect(left, top, right, bottom, + Path.Direction.CW) + ); + atLeastOnePathAdded = true; + } + } + } + if (atLeastOnePathAdded) { + if (mSearchResultHighlightPaint == null) { + mSearchResultHighlightPaint = new Paint(); + } + mSearchResultHighlightPaint.setColor(mSearchResultHighlightColor); + mSearchResultHighlightPaint.setStyle(Paint.Style.FILL); + mHighlightPaths.add(searchResultPath); + mHighlightPaints.add(mSearchResultHighlightPaint); + } + if (focusedSearchResultPath != null) { + if (mFocusedSearchResultHighlightPaint == null) { + mFocusedSearchResultHighlightPaint = new Paint(); + } + mFocusedSearchResultHighlightPaint.setColor(mFocusedSearchResultHighlightColor); + mFocusedSearchResultHighlightPaint.setStyle(Paint.Style.FILL); + mHighlightPaths.add(focusedSearchResultPath); + mHighlightPaints.add(mFocusedSearchResultHighlightPaint); + } + } + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private Path getUpdatedHighlightPath() { Path highlight = null; @@ -10826,6 +11155,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * This has to be called after layout. Returns true if anything changed. */ public boolean bringPointIntoView(int offset) { + return bringPointIntoView(offset, false); + } + + /** + * Move the insertion position of the given offset into visible area of the View. + * + * If the View is focused or {@code requestRectWithoutFocus} is set to true, this API may call + * {@link View#requestRectangleOnScreen(Rect)} to bring the point to the visible area if + * necessary. + * + * @param offset an offset of the character. + * @param requestRectWithoutFocus True for calling {@link View#requestRectangleOnScreen(Rect)} + * in the unfocused state. False for calling it only the View has + * the focus. + * @return true if anything changed, otherwise false. + * + * @see #bringPointIntoView(int) + */ + public boolean bringPointIntoView(@IntRange(from = 0) int offset, + boolean requestRectWithoutFocus) { if (isLayoutRequested()) { mDeferScroll = offset; return false; @@ -11002,7 +11351,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener changed = true; } - if (isFocused()) { + if (requestRectWithoutFocus && isFocused()) { // This offsets because getInterestingRect() is in terms of viewport coordinates, but // requestRectangleOnScreen() is in terms of content coordinates. diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index f4d563c71b20..1b6f88f3feee 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5138,6 +5138,15 @@ <attr name="textLocale" format="string" /> <!-- Color of the text selection highlight. --> <attr name="textColorHighlight" /> + <!-- Color of search results highlight. + This color is typically used when TextView/EditText shows search result in-app text + search invoked with Ctrl+F. --> + <attr name="searchResultHighlightColor" format="color" /> + <!-- Color of focused search result highlight. + This color is typically used when TextView/EditText shows search result in-app text + search invoked with Ctrl+F. --> + <attr name="focusedSearchResultHighlightColor" format="color" /> + <!-- Color of the hint text. --> <attr name="textColorHint" /> <!-- Color of the links. --> @@ -5215,6 +5224,14 @@ <attr name="textColor" /> <!-- Color of the text selection highlight. --> <attr name="textColorHighlight" /> + <!-- Color of search results highlight. + This color is typically used when TextView/EditText shows search result in-app text + search invoked with Ctrl+F. --> + <attr name="searchResultHighlightColor" format="color" /> + <!-- Color of focused search result highlight. + This color is typically used when TextView/EditText shows search result in-app text + search invoked with Ctrl+F. --> + <attr name="focusedSearchResultHighlightColor" format="color" /> <!-- Color of the hint text. --> <attr name="textColorHint" /> <!-- Base text color, typeface, size, and style. --> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 6047738b4e89..f4b49e6ce38e 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -126,6 +126,8 @@ <public name="keyboardLayoutType" /> <public name="allowUpdateOwnership" /> <public name="isCredential"/> + <public name="searchResultHighlightColor" /> + <public name="focusedSearchResultHighlightColor" /> </staging-public-group> <staging-public-group type="id" first-id="0x01cd0000"> |