diff options
| -rw-r--r-- | api/current.txt | 21 | ||||
| -rw-r--r-- | api/system-current.txt | 21 | ||||
| -rw-r--r-- | api/test-current.txt | 21 | ||||
| -rw-r--r-- | core/java/android/app/Activity.java | 21 | ||||
| -rw-r--r-- | core/java/android/text/TextAssistant.java | 56 | ||||
| -rw-r--r-- | core/java/android/text/TextClassification.java | 40 | ||||
| -rw-r--r-- | core/java/android/text/TextSelection.java | 51 | ||||
| -rw-r--r-- | core/java/android/widget/Editor.java | 55 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 30 |
9 files changed, 303 insertions, 13 deletions
diff --git a/api/current.txt b/api/current.txt index 39140213d920..6cb05eba770d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3497,6 +3497,7 @@ package android.app { method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); method public int getTaskId(); + method public android.text.TextAssistant getTextAssistant(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); method public android.app.VoiceInteractor getVoiceInteractor(); @@ -3646,6 +3647,7 @@ package android.app { method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); + method public void setTextAssistant(android.text.TextAssistant); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); @@ -38988,6 +38990,16 @@ package android.text { method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic); } + public abstract interface TextAssistant { + method public abstract void addLinks(android.text.Spannable, int); + method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int); + } + + public class TextClassification { + ctor public TextClassification(); + method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence(); + } + public abstract interface TextDirectionHeuristic { method public abstract boolean isRtl(char[], int, int); method public abstract boolean isRtl(java.lang.CharSequence, int, int); @@ -39015,6 +39027,13 @@ package android.text { field public int linkColor; } + public class TextSelection { + ctor public TextSelection(); + method public int getSelectionEndIndex(); + method public int getSelectionStartIndex(); + method public android.text.TextClassification getTextClassification(); + } + public class TextUtils { method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String); method public static java.lang.CharSequence concat(java.lang.CharSequence...); @@ -48487,6 +48506,7 @@ package android.widget { method public float getShadowRadius(); method public final boolean getShowSoftInputOnFocus(); method public java.lang.CharSequence getText(); + method public android.text.TextAssistant getTextAssistant(); method public final android.content.res.ColorStateList getTextColors(); method public java.util.Locale getTextLocale(); method public android.os.LocaleList getTextLocales(); @@ -48597,6 +48617,7 @@ package android.widget { method public final void setText(int, android.widget.TextView.BufferType); method public void setTextAppearance(int); method public deprecated void setTextAppearance(android.content.Context, int); + method public void setTextAssistant(android.text.TextAssistant); method public void setTextColor(int); method public void setTextColor(android.content.res.ColorStateList); method public void setTextIsSelectable(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index bcf4897c8661..dc22a2ae9a92 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3614,6 +3614,7 @@ package android.app { method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); method public int getTaskId(); + method public android.text.TextAssistant getTextAssistant(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); method public android.app.VoiceInteractor getVoiceInteractor(); @@ -3765,6 +3766,7 @@ package android.app { method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); + method public void setTextAssistant(android.text.TextAssistant); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); @@ -42150,6 +42152,16 @@ package android.text { method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic); } + public abstract interface TextAssistant { + method public abstract void addLinks(android.text.Spannable, int); + method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int); + } + + public class TextClassification { + ctor public TextClassification(); + method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence(); + } + public abstract interface TextDirectionHeuristic { method public abstract boolean isRtl(char[], int, int); method public abstract boolean isRtl(java.lang.CharSequence, int, int); @@ -42177,6 +42189,13 @@ package android.text { field public int linkColor; } + public class TextSelection { + ctor public TextSelection(); + method public int getSelectionEndIndex(); + method public int getSelectionStartIndex(); + method public android.text.TextClassification getTextClassification(); + } + public class TextUtils { method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String); method public static java.lang.CharSequence concat(java.lang.CharSequence...); @@ -52008,6 +52027,7 @@ package android.widget { method public float getShadowRadius(); method public final boolean getShowSoftInputOnFocus(); method public java.lang.CharSequence getText(); + method public android.text.TextAssistant getTextAssistant(); method public final android.content.res.ColorStateList getTextColors(); method public java.util.Locale getTextLocale(); method public android.os.LocaleList getTextLocales(); @@ -52118,6 +52138,7 @@ package android.widget { method public final void setText(int, android.widget.TextView.BufferType); method public void setTextAppearance(int); method public deprecated void setTextAppearance(android.content.Context, int); + method public void setTextAssistant(android.text.TextAssistant); method public void setTextColor(int); method public void setTextColor(android.content.res.ColorStateList); method public void setTextIsSelectable(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index 2dcb743b4a73..813deb904435 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3499,6 +3499,7 @@ package android.app { method public int getRequestedOrientation(); method public final android.view.SearchEvent getSearchEvent(); method public int getTaskId(); + method public android.text.TextAssistant getTextAssistant(); method public final java.lang.CharSequence getTitle(); method public final int getTitleColor(); method public android.app.VoiceInteractor getVoiceInteractor(); @@ -3648,6 +3649,7 @@ package android.app { method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); + method public void setTextAssistant(android.text.TextAssistant); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); @@ -39080,6 +39082,16 @@ package android.text { method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic); } + public abstract interface TextAssistant { + method public abstract void addLinks(android.text.Spannable, int); + method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int); + } + + public class TextClassification { + ctor public TextClassification(); + method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence(); + } + public abstract interface TextDirectionHeuristic { method public abstract boolean isRtl(char[], int, int); method public abstract boolean isRtl(java.lang.CharSequence, int, int); @@ -39107,6 +39119,13 @@ package android.text { field public int linkColor; } + public class TextSelection { + ctor public TextSelection(); + method public int getSelectionEndIndex(); + method public int getSelectionStartIndex(); + method public android.text.TextClassification getTextClassification(); + } + public class TextUtils { method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String); method public static java.lang.CharSequence concat(java.lang.CharSequence...); @@ -48745,6 +48764,7 @@ package android.widget { method public float getShadowRadius(); method public final boolean getShowSoftInputOnFocus(); method public java.lang.CharSequence getText(); + method public android.text.TextAssistant getTextAssistant(); method public final android.content.res.ColorStateList getTextColors(); method public java.util.Locale getTextLocale(); method public android.os.LocaleList getTextLocales(); @@ -48855,6 +48875,7 @@ package android.widget { method public final void setText(int, android.widget.TextView.BufferType); method public void setTextAppearance(int); method public deprecated void setTextAppearance(android.content.Context, int); + method public void setTextAssistant(android.text.TextAssistant); method public void setTextColor(int); method public void setTextColor(android.content.res.ColorStateList); method public void setTextIsSelectable(boolean); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 64e5dfc66bce..90fff8d5f79a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -74,6 +74,7 @@ import android.service.autofill.AutoFillService; import android.service.autofill.IAutoFillCallback; import android.text.Selection; import android.text.SpannableStringBuilder; +import android.text.TextAssistant; import android.text.TextUtils; import android.text.method.TextKeyListener; import android.transition.Scene; @@ -783,6 +784,8 @@ public class Activity extends ContextThemeWrapper private VoiceInteractor mVoiceInteractor; + private TextAssistant mTextAssistant; + private CharSequence mTitle; private int mTitleColor = 0; @@ -1385,6 +1388,24 @@ public class Activity extends ContextThemeWrapper } /** + * Sets the default {@link TextAssistant} for {@link android.widget.TextView}s in this Activity. + */ + public void setTextAssistant(TextAssistant textAssistant) { + mTextAssistant = textAssistant; + } + + /** + * Returns the default {@link TextAssistant} for {@link android.widget.TextView}s + * in this Activity. + */ + public TextAssistant getTextAssistant() { + if (mTextAssistant != null) { + return mTextAssistant; + } + return TextAssistant.NO_OP; + } + + /** * This is called for activities that set launchMode to "singleTop" in * their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} * flag when calling {@link #startActivity}. In either case, when the diff --git a/core/java/android/text/TextAssistant.java b/core/java/android/text/TextAssistant.java new file mode 100644 index 000000000000..b044981cdd95 --- /dev/null +++ b/core/java/android/text/TextAssistant.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.text; + +/** + * Interface for providing text assistant features. + */ +public interface TextAssistant { + + /** + * NO_OP TextAssistant. This will act as the default TextAssistant until we implement a + * TextClassificationManager. + * @hide + */ + TextAssistant NO_OP = new TextAssistant() { + + private final TextSelection mTextSelection = new TextSelection(); + + @Override + public TextSelection suggestSelection( + CharSequence text, int selectionStartIndex, int selectionEndIndex) { + mTextSelection.mStartIndex = selectionStartIndex; + mTextSelection.mEndIndex = selectionEndIndex; + return mTextSelection; + } + + @Override + public void addLinks(Spannable text, int linkMask) {} + }; + + /** + * Returns suggested text selection indices, recognized types and their associated confidence + * scores. The selections are ordered from highest to lowest scoring. + */ + TextSelection suggestSelection( + CharSequence text, int selectionStartIndex, int selectionEndIndex); + + /** + * Adds assistance clickable spans to the provided text. + */ + void addLinks(Spannable text, int linkMask); +} diff --git a/core/java/android/text/TextClassification.java b/core/java/android/text/TextClassification.java new file mode 100644 index 000000000000..bb226daaaeb0 --- /dev/null +++ b/core/java/android/text/TextClassification.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.text; + +import java.util.Collections; +import java.util.Map; + +/** + * Information about entities that a specific piece of text is classified as. + */ +public class TextClassification { + + /** @hide */ + public static final TextClassification NO_OP = new TextClassification(); + + private Map<String, Float> mTypeConfidence = Collections.unmodifiableMap(Collections.EMPTY_MAP); + + /** + * Returns a map of text classification types to their respective confidence scores. + * The scores range from 0 (low confidence) to 1 (high confidence). The items are ordered from + * high scoring items to low scoring items. + */ + public Map<String, Float> getTypeConfidence() { + return mTypeConfidence; + } +} diff --git a/core/java/android/text/TextSelection.java b/core/java/android/text/TextSelection.java new file mode 100644 index 000000000000..9400458582c7 --- /dev/null +++ b/core/java/android/text/TextSelection.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.text; + +/** + * Text selection information. + */ +public class TextSelection { + + /** @hide */ + int mStartIndex; + /** @hide */ + int mEndIndex; + + private TextClassification mTextClassification = TextClassification.NO_OP; + + /** + * Returns the start index of the text selection. + */ + public int getSelectionStartIndex() { + return mStartIndex; + } + + /** + * Returns the end index of the text selection. + */ + public int getSelectionEndIndex() { + return mEndIndex; + } + + /** + * Returns information about what the text selection is classified as. + */ + public TextClassification getTextClassification() { + return mTextClassification; + } +} diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 541fbe0528f1..95fafc471816 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -60,6 +60,8 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; +import android.text.TextClassification; +import android.text.TextSelection; import android.text.TextUtils; import android.text.method.KeyListener; import android.text.method.MetaKeyKeyListener; @@ -147,16 +149,17 @@ public class Editor { private static final String UNDO_OWNER_TAG = "Editor"; // Ordering constants used to place the Action Mode or context menu items in their menu. - private static final int MENU_ITEM_ORDER_UNDO = 1; - private static final int MENU_ITEM_ORDER_REDO = 2; - private static final int MENU_ITEM_ORDER_CUT = 3; - private static final int MENU_ITEM_ORDER_COPY = 4; - private static final int MENU_ITEM_ORDER_PASTE = 5; - private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 6; - private static final int MENU_ITEM_ORDER_SHARE = 7; - private static final int MENU_ITEM_ORDER_SELECT_ALL = 8; - private static final int MENU_ITEM_ORDER_REPLACE = 9; - private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 10; + // Reserve 1 for the app that the ASSIST logic suggests as the best app to handle the selection. + private static final int MENU_ITEM_ORDER_UNDO = 2; + private static final int MENU_ITEM_ORDER_REDO = 3; + private static final int MENU_ITEM_ORDER_SHARE = 4; + private static final int MENU_ITEM_ORDER_CUT = 5; + private static final int MENU_ITEM_ORDER_COPY = 6; + private static final int MENU_ITEM_ORDER_PASTE = 7; + private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 8; + private static final int MENU_ITEM_ORDER_SELECT_ALL = 9; + private static final int MENU_ITEM_ORDER_REPLACE = 10; + private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 11; // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); @@ -3767,10 +3770,12 @@ public class Editor { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { + TextClassification textClassification = updateSelectionWithTextAssistant(); + mode.setTitle(null); mode.setSubtitle(null); mode.setTitleOptionalHint(true); - populateMenuWithItems(menu); + populateMenuWithItems(menu, textClassification); Callback customCallback = getCustomCallback(); if (customCallback != null) { @@ -3796,13 +3801,30 @@ public class Editor { } } + private TextClassification updateSelectionWithTextAssistant() { + // Trim the text so that only text necessary to provide context of the selected text is + // sent to the assistant. + CharSequence trimmedText = mTextView.getText(); + int textLength = mTextView.getText().length(); + int trimStartIndex = 0; + int startIndex = mTextView.getSelectionStart() - trimStartIndex; + int endIndex = mTextView.getSelectionEnd() - trimStartIndex; + TextSelection textSelection = mTextView.getTextAssistant() + .suggestSelection(trimmedText, startIndex, endIndex); + Selection.setSelection( + (Spannable) mTextView.getText(), + Math.max(0, textSelection.getSelectionStartIndex() + trimStartIndex), + Math.min(textLength, textSelection.getSelectionEndIndex() + trimStartIndex)); + return textSelection.getTextClassification(); + } + private Callback getCustomCallback() { return mHasSelection ? mCustomSelectionActionModeCallback : mCustomInsertionActionModeCallback; } - private void populateMenuWithItems(Menu menu) { + private void populateMenuWithItems(Menu menu, TextClassification textClassification) { if (mTextView.canCut()) { menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT, com.android.internal.R.string.cut) @@ -3827,11 +3849,12 @@ public class Editor { if (mTextView.canShare()) { menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE, com.android.internal.R.string.share) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } updateSelectAllItem(menu); updateReplaceItem(menu); + updateAssistMenuItem(menu, textClassification); } @Override @@ -3870,6 +3893,12 @@ public class Editor { } } + private void updateAssistMenuItem(Menu menu, TextClassification textClassification) { + // TODO: Find the best app available to handle the selected text based on information in + // the TextClassification object. + // Add app icon + intent to trigger app to the menu. + } + @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 69f463cdd856..dba86556fd1d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -76,6 +76,7 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.SpannedString; import android.text.StaticLayout; +import android.text.TextAssistant; import android.text.TextDirectionHeuristic; import android.text.TextDirectionHeuristics; import android.text.TextPaint; @@ -9819,6 +9820,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mEditor == null ? null : mEditor.mCustomInsertionActionModeCallback; } + private TextAssistant mTextAssistant; + + /** + * Sets the {@link TextAssistant} for this TextView. + * If null, this TextView uses the default TextAssistant which comes from the Activity. + */ + public void setTextAssistant(TextAssistant textAssistant) { + mTextAssistant = textAssistant; + } + + /** + * Returns the {@link TextAssistant} used by this TextView. + * If no TextAssistant is set, it'll use the one from this TextView's {@link Activity} or + * {@link Context}. If no TextAssistant is found, it'll use a no-op TextAssistant. + */ + public TextAssistant getTextAssistant() { + if (mTextAssistant != null) { + return mTextAssistant; + } + if (mContext instanceof Activity) { + mTextAssistant = ((Activity) mContext).getTextAssistant(); + } else { + // The context of this TextView should be an Activity. If it is not and no + // text assistant has been set, return a NO_OP TextAssistant. + mTextAssistant = TextAssistant.NO_OP; + } + return mTextAssistant; + } + /** * @hide */ |