Merge "Optional parameters for TextClassifier APIs."

This commit is contained in:
TreeHugger Robot
2017-11-06 13:44:48 +00:00
committed by Android (Google) Code Review
8 changed files with 244 additions and 60 deletions

View File

@@ -48955,14 +48955,22 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
public static final class TextClassification.Options {
ctor public TextClassification.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
}
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -48985,6 +48993,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
public static final class TextSelection.Options {
ctor public TextSelection.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
}
}
package android.view.textservice {

View File

@@ -52694,14 +52694,22 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
public static final class TextClassification.Options {
ctor public TextClassification.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
}
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -52724,6 +52732,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
public static final class TextSelection.Options {
ctor public TextSelection.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
}
}
package android.view.textservice {

View File

@@ -49592,14 +49592,22 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
public static final class TextClassification.Options {
ctor public TextClassification.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
}
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -49622,6 +49630,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
public static final class TextSelection.Options {
ctor public TextSelection.Options();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
}
}
package android.view.textservice {

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.LocaleList;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -438,4 +439,31 @@ public final class TextClassification {
mLogType, mVersionInfo);
}
}
/**
* TextClassification optional input parameters.
*/
public static final class Options {
private LocaleList mDefaultLocales;
/**
* @param defaultLocales ordered list of locale preferences that may be used to disambiguate
* the provided text. If no locale preferences exist, set this to null or an empty
* locale list.
*/
public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
mDefaultLocales = defaultLocales;
return this;
}
/**
* @return ordered list of locale preferences that can be used to disambiguate
* the provided text.
*/
@Nullable
public LocaleList getDefaultLocales() {
return mDefaultLocales;
}
}
}

View File

@@ -56,23 +56,7 @@ public interface TextClassifier {
* No-op TextClassifier.
* This may be used to turn off TextClassifier features.
*/
TextClassifier NO_OP = new TextClassifier() {
@Override
public TextSelection suggestSelection(
CharSequence text,
int selectionStartIndex,
int selectionEndIndex,
LocaleList defaultLocales) {
return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
}
@Override
public TextClassification classifyText(
CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
return TextClassification.EMPTY;
}
};
TextClassifier NO_OP = new TextClassifier() {};
/**
* Returns suggested text selection start and end indices, recognized entity types, and their
@@ -82,21 +66,34 @@ public interface TextClassifier {
* by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
* @param selectionStartIndex start index of the selected part of text
* @param selectionEndIndex end index of the selected part of text
* @param defaultLocales ordered list of locale preferences that can be used to disambiguate
* the provided text. If no locale preferences exist, set this to null or an empty locale
* list in which case the classifier will decide whether to use no locale information, use
* a default locale, or use the system default.
* @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
*/
@WorkerThread
@NonNull
TextSelection suggestSelection(
default TextSelection suggestSelection(
@NonNull CharSequence text,
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable LocaleList defaultLocales);
@Nullable TextSelection.Options options) {
return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
}
/**
* @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
*/
// TODO: Consider deprecating (b/68846316)
@WorkerThread
@NonNull
default TextSelection suggestSelection(
@NonNull CharSequence text,
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable LocaleList defaultLocales) {
return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
}
/**
* Classifies the specified text and returns a {@link TextClassification} object that can be
@@ -106,21 +103,34 @@ public interface TextClassifier {
* by the sub sequence starting at startIndex and ending at endIndex)
* @param startIndex start index of the text to classify
* @param endIndex end index of the text to classify
* @param defaultLocales ordered list of locale preferences that can be used to disambiguate
* the provided text. If no locale preferences exist, set this to null or an empty locale
* list in which case the classifier will decide whether to use no locale information, use
* a default locale, or use the system default.
* @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
*/
@WorkerThread
@NonNull
TextClassification classifyText(
default TextClassification classifyText(
@NonNull CharSequence text,
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable LocaleList defaultLocales);
@Nullable TextClassification.Options options) {
return TextClassification.EMPTY;
}
/**
* @see #classifyText(CharSequence, int, int, TextClassification.Options)
*/
// TODO: Consider deprecating (b/68846316)
@WorkerThread
@NonNull
default TextClassification classifyText(
@NonNull CharSequence text,
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable LocaleList defaultLocales) {
return TextClassification.EMPTY;
}
/**
* Returns a {@link LinksInfo} that may be applied to the text to annotate it with links

View File

@@ -100,16 +100,24 @@ final class TextClassifierImpl implements TextClassifier {
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
@Nullable LocaleList defaultLocales) {
@Nullable TextSelection.Options options) {
validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
final SmartSelection smartSelection = getSmartSelection(defaultLocales);
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final SmartSelection smartSelection = getSmartSelection(locales);
final String string = text.toString();
final int[] startEnd = smartSelection.suggest(
string, selectionStartIndex, selectionEndIndex);
final int start = startEnd[0];
final int end = startEnd[1];
final int start;
final int end;
if (getSettings().isDarkLaunch() && !options.isDarkLaunchAllowed()) {
start = selectionStartIndex;
end = selectionEndIndex;
} else {
final int[] startEnd = smartSelection.suggest(
string, selectionStartIndex, selectionEndIndex);
start = startEnd[0];
end = startEnd[1];
}
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
@@ -139,18 +147,27 @@ final class TextClassifierImpl implements TextClassifier {
}
// Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.suggestSelection(
text, selectionStartIndex, selectionEndIndex, defaultLocales);
text, selectionStartIndex, selectionEndIndex, options);
}
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
@Nullable LocaleList defaultLocales) {
return suggestSelection(text, selectionStartIndex, selectionEndIndex,
new TextSelection.Options().setDefaultLocales(defaultLocales));
}
@Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
@Nullable LocaleList defaultLocales) {
@Nullable TextClassification.Options options) {
validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
SmartSelection.ClassificationResult[] results = getSmartSelection(defaultLocales)
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final SmartSelection.ClassificationResult[] results = getSmartSelection(locales)
.classifyText(string, startIndex, endIndex,
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
@@ -165,8 +182,15 @@ final class TextClassifierImpl implements TextClassifier {
Log.e(LOG_TAG, "Error getting text classification info.", t);
}
// Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.classifyText(
text, startIndex, endIndex, defaultLocales);
return TextClassifier.NO_OP.classifyText(text, startIndex, endIndex, options);
}
@Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
@Nullable LocaleList defaultLocales) {
return classifyText(text, startIndex, endIndex,
new TextClassification.Options().setDefaultLocales(defaultLocales));
}
@Override

View File

@@ -19,6 +19,8 @@ package android.view.textclassifier;
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.LocaleList;
import android.view.textclassifier.TextClassifier.EntityType;
import com.android.internal.util.Preconditions;
@@ -181,4 +183,55 @@ public final class TextSelection {
mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
}
}
/**
* TextSelection optional input parameters.
*/
public static final class Options {
private LocaleList mDefaultLocales;
private boolean mDarkLaunchAllowed;
/**
* @param defaultLocales ordered list of locale preferences that may be used to disambiguate
* the provided text. If no locale preferences exist, set this to null or an empty
* locale list.
*/
public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
mDefaultLocales = defaultLocales;
return this;
}
/**
* @return ordered list of locale preferences that can be used to disambiguate
* the provided text.
*/
@Nullable
public LocaleList getDefaultLocales() {
return mDefaultLocales;
}
/**
* @param allowed whether or not the TextClassifier should return selection suggestions
* when "dark launched". When a TextClassifier is dark launched, it can suggest
* selection changes that should not be used to actually change the user's selection.
* Instead, the suggested selection is logged, compared with the user's selection
* interaction, and used to generate quality metrics for the TextClassifier.
*
* @hide
*/
public void setDarkLaunchAllowed(boolean allowed) {
mDarkLaunchAllowed = allowed;
}
/**
* Returns true if the TextClassifier should return selection suggestions when
* "dark launched". Otherwise, returns false.
*
* @hide
*/
public boolean isDarkLaunchAllowed() {
return mDarkLaunchAllowed;
}
}
}

View File

@@ -20,10 +20,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.annotation.WorkerThread;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.AsyncTask;
import android.os.Build;
import android.os.LocaleList;
import android.text.Layout;
import android.text.Selection;
@@ -81,6 +83,7 @@ public final class SelectionActionModeHelper {
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
0, 1, mTextView.getTextLocales());
@@ -385,6 +388,7 @@ public final class SelectionActionModeHelper {
private void resetTextClassificationHelper() {
mTextClassificationHelper.init(
mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -787,6 +791,7 @@ public final class SelectionActionModeHelper {
private static final int TRIM_DELTA = 120; // characters
private Context mContext;
private TextClassifier mTextClassifier;
/** The original TextView text. **/
@@ -795,7 +800,10 @@ public final class SelectionActionModeHelper {
private int mSelectionStart;
/** End index relative to mText. */
private int mSelectionEnd;
private LocaleList mLocales;
private final TextSelection.Options mSelectionOptions = new TextSelection.Options();
private final TextClassification.Options mClassificationOptions =
new TextClassification.Options();
/** Trimmed text starting from mTrimStart in mText. */
private CharSequence mTrimmedText;
@@ -816,21 +824,24 @@ public final class SelectionActionModeHelper {
/** Whether the TextClassifier has been initialized. */
private boolean mHot;
TextClassificationHelper(TextClassifier textClassifier,
TextClassificationHelper(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
init(textClassifier, text, selectionStart, selectionEnd, locales);
init(context, textClassifier, text, selectionStart, selectionEnd, locales);
}
@UiThread
public void init(TextClassifier textClassifier,
public void init(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
mContext = Preconditions.checkNotNull(context);
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
mLocales = locales;
mClassificationOptions.setDefaultLocales(locales);
mSelectionOptions.setDefaultLocales(locales)
.setDarkLaunchAllowed(true);
}
@WorkerThread
@@ -843,8 +854,16 @@ public final class SelectionActionModeHelper {
public SelectionResult suggestSelection() {
mHot = true;
trimText();
final TextSelection selection = mTextClassifier.suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
final TextSelection selection;
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
selection = mTextClassifier.suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd, mSelectionOptions);
} else {
// Use old APIs.
selection = mTextClassifier.suggestSelection(
mTrimmedText, mRelativeStart, mRelativeEnd,
mSelectionOptions.getDefaultLocales());
}
// Do not classify new selection boundaries if TextClassifier should be dark launched.
if (!mTextClassifier.getSettings().isDarkLaunch()) {
mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
@@ -874,20 +893,28 @@ public final class SelectionActionModeHelper {
if (!Objects.equals(mText, mLastClassificationText)
|| mSelectionStart != mLastClassificationSelectionStart
|| mSelectionEnd != mLastClassificationSelectionEnd
|| !Objects.equals(mLocales, mLastClassificationLocales)) {
|| !Objects.equals(
mClassificationOptions.getDefaultLocales(),
mLastClassificationLocales)) {
mLastClassificationText = mText;
mLastClassificationSelectionStart = mSelectionStart;
mLastClassificationSelectionEnd = mSelectionEnd;
mLastClassificationLocales = mLocales;
mLastClassificationLocales = mClassificationOptions.getDefaultLocales();
trimText();
final TextClassification classification;
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
classification = mTextClassifier.classifyText(
mTrimmedText, mRelativeStart, mRelativeEnd, mClassificationOptions);
} else {
// Use old APIs.
classification = mTextClassifier.classifyText(
mTrimmedText, mRelativeStart, mRelativeEnd,
mClassificationOptions.getDefaultLocales());
}
mLastClassificationResult = new SelectionResult(
mSelectionStart,
mSelectionEnd,
mTextClassifier.classifyText(
mTrimmedText, mRelativeStart, mRelativeEnd, mLocales),
selection);
mSelectionStart, mSelectionEnd, classification, selection);
}
return mLastClassificationResult;