OSDN Git Service

Update TextAssistant interface.
authorAbodunrinwa Toki <toki@google.com>
Wed, 4 Jan 2017 23:51:42 +0000 (23:51 +0000)
committerAbodunrinwa Toki <toki@google.com>
Tue, 24 Jan 2017 15:01:24 +0000 (15:01 +0000)
Rename to TextClassifier
Move to android.view.textclassifier package
Adds getTextClassifierInfo(...)
Changes addLinks(...) to getLinks(...)

This CL also integrates this interface with framework components
and passes a context to TextClassificationManager.

Test: Tests will be added with implementation.
Bug: 34661057
Change-Id: If9e90f034ebb702c1f78e72b6a844f39eebf738f

22 files changed:
api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/app/Activity.java
core/java/android/app/SystemServiceRegistry.java
core/java/android/content/Context.java
core/java/android/text/TextAssistant.java [deleted file]
core/java/android/text/TextClassification.java [deleted file]
core/java/android/text/TextClassificationManager.java [deleted file]
core/java/android/text/TextLanguage.java [deleted file]
core/java/android/text/TextSelection.java [deleted file]
core/java/android/view/textclassifier/EntityConfidence.java [new file with mode: 0644]
core/java/android/view/textclassifier/LinksInfo.java [new file with mode: 0644]
core/java/android/view/textclassifier/TextClassificationManager.java [new file with mode: 0644]
core/java/android/view/textclassifier/TextClassificationResult.java [new file with mode: 0644]
core/java/android/view/textclassifier/TextClassifier.java [new file with mode: 0644]
core/java/android/view/textclassifier/TextLanguage.java [new file with mode: 0644]
core/java/android/view/textclassifier/TextSelection.java [new file with mode: 0644]
core/java/android/widget/Editor.java
core/java/android/widget/TextView.java
core/res/res/values/ids.xml
core/res/res/values/public.xml

index bca65ee..cb6939f 100644 (file)
@@ -1817,6 +1817,7 @@ package android {
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -3536,7 +3537,6 @@ 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();
@@ -3686,7 +3686,6 @@ 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);
@@ -39900,22 +39899,6 @@ 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 final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -39931,13 +39914,6 @@ package android.text {
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -39950,13 +39926,6 @@ 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...);
@@ -46472,6 +46441,83 @@ package android.view.inputmethod {
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    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";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -49561,7 +49607,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 android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -49677,7 +49723,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 setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
index 53552fc..bab3673 100644 (file)
@@ -1930,6 +1930,7 @@ package android {
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -3655,7 +3656,6 @@ 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();
@@ -3807,7 +3807,6 @@ 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);
@@ -43201,22 +43200,6 @@ 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 final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -43232,13 +43215,6 @@ package android.text {
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -43251,13 +43227,6 @@ 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...);
@@ -49777,6 +49746,83 @@ package android.view.inputmethod {
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    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";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -53227,7 +53273,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 android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -53343,7 +53389,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 setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
index d18af4c..9a58df2 100644 (file)
@@ -1817,6 +1817,7 @@ package android {
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -3538,7 +3539,6 @@ 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();
@@ -3688,7 +3688,6 @@ 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);
@@ -40024,22 +40023,6 @@ 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 final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -40055,13 +40038,6 @@ package android.text {
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -40074,13 +40050,6 @@ 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...);
@@ -46770,6 +46739,83 @@ package android.view.inputmethod {
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    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";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -49866,7 +49912,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 android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -49982,7 +50028,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 setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
index 556d7ad..a9d1cf6 100644 (file)
@@ -78,8 +78,6 @@ import android.service.autofill.AutoFillService;
 import android.service.autofill.IAutoFillAppCallback;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
-import android.text.TextAssistant;
-import android.text.TextClassificationManager;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.transition.Scene;
@@ -792,8 +790,6 @@ public class Activity extends ContextThemeWrapper
 
     private VoiceInteractor mVoiceInteractor;
 
-    private TextAssistant mTextAssistant;
-
     private CharSequence mTitle;
     private int mTitleColor = 0;
 
@@ -1398,24 +1394,6 @@ 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 getSystemService(TextClassificationManager.class);
-    }
-
-    /**
      * 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
index a37f22b..5d8909c 100644 (file)
@@ -119,7 +119,6 @@ import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.FontManager;
-import android.text.TextClassificationManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -128,6 +127,7 @@ import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
 
 import com.android.internal.app.IAppOpsService;
@@ -228,10 +228,10 @@ final class SystemServiceRegistry {
             }});
 
         registerService(Context.TEXT_CLASSIFICATION_SERVICE, TextClassificationManager.class,
-                new StaticServiceFetcher<TextClassificationManager>() {
+                new CachedServiceFetcher<TextClassificationManager>() {
             @Override
-            public TextClassificationManager createService() {
-                return new TextClassificationManager();
+            public TextClassificationManager createService(ContextImpl ctx) {
+                return new TextClassificationManager(ctx);
             }});
 
         registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
index f41d7f2..38e6fbe 100644 (file)
@@ -34,9 +34,7 @@ import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
-import android.app.LoadedApk;
 import android.app.Notification;
-import android.app.admin.DevicePolicyManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -64,6 +62,7 @@ import android.view.Display;
 import android.view.DisplayAdjustments;
 import android.view.ViewDebug;
 import android.view.WindowManager;
+import android.view.textclassifier.TextClassificationManager;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -3348,10 +3347,10 @@ public abstract class Context {
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.text.TextClassificationManager} for text classification services.
+     * {@link TextClassificationManager} for text classification services.
      *
      * @see #getSystemService
-     * @see android.text.TextClassificationManager
+     * @see TextClassificationManager
      */
     public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
 
diff --git a/core/java/android/text/TextAssistant.java b/core/java/android/text/TextAssistant.java
deleted file mode 100644 (file)
index b044981..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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
deleted file mode 100644 (file)
index bb226da..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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/TextClassificationManager.java b/core/java/android/text/TextClassificationManager.java
deleted file mode 100644 (file)
index d4548f0..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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 android.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Interface to the text classification service.
- * This class uses machine learning techniques to infer things about text.
- * Unless otherwise stated, methods of this class are blocking operations and should most likely not
- * be called on the UI thread.
- *
- * <p> You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
- *
- * The TextClassificationManager serves as the default TextAssistant if none has been set.
- * @see android.app.Activity#setTextAssistant(TextAssistant).
- */
-public final class TextClassificationManager implements TextAssistant {
-    // TODO: Consider not making this class implement TextAssistant.
-
-    /** @hide */
-    public TextClassificationManager() {}
-
-    /**
-     * Returns information containing languages that were detected in the provided text.
-     * This is a blocking operation and should most likely not be called on the UI thread.
-     */
-    public List<TextLanguage> detectLanguages(@NonNull CharSequence text) {
-        // TODO: Implement this using the cld3 library.
-        return Collections.emptyList();
-    }
-
-    @Override
-    public TextSelection suggestSelection(
-            @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex) {
-        // TODO: Implement.
-        return TextAssistant.NO_OP.suggestSelection(text, selectionStartIndex, selectionEndIndex);
-    }
-
-    @Override
-    public void addLinks(@NonNull Spannable text, int linkMask) {
-        // TODO: Implement.
-    }
-}
diff --git a/core/java/android/text/TextLanguage.java b/core/java/android/text/TextLanguage.java
deleted file mode 100644 (file)
index eb834f1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 android.annotation.NonNull;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Specifies detected languages for a section of text indicated by a start and end index.
- */
-public final class TextLanguage {
-
-    private final int mStartIndex;
-    private final int mEndIndex;
-    private final Map<String, Float> mLanguageConfidence;
-
-    /**
-     * Initializes a TextLanguage object.
-     *
-     * @param startIndex the start index of the detected languages in the text provided to generate
-     *      this object.
-     * @param endIndex the end index of the detected languages in the text provided to generate this
-     *      object.
-     * @param languageConfidence a map of detected language to confidence score. The language string
-     *      is a BCP-47 language tag.
-     * @throws NullPointerException if languageConfidence is null or contains a null key or value.
-     */
-    public TextLanguage(int startIndex, int endIndex,
-            @NonNull Map<String, Float> languageConfidence) {
-        mStartIndex = startIndex;
-        mEndIndex = endIndex;
-
-        Map<String, Float> map = new LinkedHashMap<>();
-        Preconditions.checkNotNull(languageConfidence).entrySet().stream()
-                .sorted(Map.Entry.comparingByValue())
-                .forEach(entry -> map.put(
-                        Preconditions.checkNotNull(entry.getKey()),
-                        Preconditions.checkNotNull(entry.getValue())));
-        mLanguageConfidence = Collections.unmodifiableMap(map);
-    }
-
-    /**
-     * Returns the start index of the detected languages in the text provided to generate this
-     * object.
-     */
-    public int getStartIndex() {
-        return mStartIndex;
-    }
-
-    /**
-     * Returns the end index of the detected languages in the text provided to generate this object.
-     */
-    public int getEndIndex() {
-        return mEndIndex;
-    }
-
-    /**
-     * Returns an unmodifiable map of detected language to confidence score. The map entries are
-     * ordered from high confidence score (1) to low confidence score (0). The language string is a
-     * BCP-47 language tag.
-     */
-    @NonNull
-    public Map<String, Float> getLanguageConfidence() {
-        return mLanguageConfidence;
-    }
-}
diff --git a/core/java/android/text/TextSelection.java b/core/java/android/text/TextSelection.java
deleted file mode 100644 (file)
index 9400458..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
new file mode 100644 (file)
index 0000000..7aab71f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper object for setting and getting entity scores for classified text.
+ *
+ * @param <T> the entity type.
+ * @hide
+ */
+final class EntityConfidence<T> {
+
+    private final Map<T, Float> mEntityConfidence = new HashMap<>();
+
+    private final Comparator<T> mEntityComparator = (e1, e2) -> {
+        float score1 = mEntityConfidence.get(e1);
+        float score2 = mEntityConfidence.get(e2);
+        if (score1 > score2) {
+            return 1;
+        }
+        if (score1 < score2) {
+            return -1;
+        }
+        return 0;
+    };
+
+    EntityConfidence() {}
+
+    EntityConfidence(@NonNull EntityConfidence<T> source) {
+        Preconditions.checkNotNull(source);
+        mEntityConfidence.putAll(source.mEntityConfidence);
+    }
+
+    /**
+     * Sets an entity type for the classified text and assigns a confidence score.
+     *
+     * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+     *      0 implies the entity does not exist for the classified text.
+     *      Values greater than 1 are clamped to 1.
+     */
+    public void setEntityType(
+            @NonNull T type, @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+        Preconditions.checkNotNull(type);
+        if (confidenceScore > 0) {
+            mEntityConfidence.put(type, Math.min(1, confidenceScore));
+        } else {
+            mEntityConfidence.remove(type);
+        }
+    }
+
+    /**
+     * Returns an immutable list of entities found in the classified text ordered from
+     * high confidence to low confidence.
+     */
+    @NonNull
+    public List<T> getEntities() {
+        List<T> entities = new ArrayList<>(mEntityConfidence.size());
+        entities.addAll(mEntityConfidence.keySet());
+        entities.sort(mEntityComparator);
+        return Collections.unmodifiableList(entities);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(T entity) {
+        if (mEntityConfidence.containsKey(entity)) {
+            return mEntityConfidence.get(entity);
+        }
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return mEntityConfidence.toString();
+    }
+}
diff --git a/core/java/android/view/textclassifier/LinksInfo.java b/core/java/android/view/textclassifier/LinksInfo.java
new file mode 100644 (file)
index 0000000..3acbdc0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.NonNull;
+
+/**
+ * Link information that can be applied to text. See: {@link #apply(CharSequence)}.
+ * Typical implementations of this interface will annotate spannable text with e.g
+ * {@link android.text.style.ClickableSpan}s or other annotations.
+ */
+public interface LinksInfo {
+
+    /**
+     * @hide
+     */
+    LinksInfo NO_OP = text -> false;
+
+    /**
+     * Applies link annotations to the specified text.
+     * These annotations are not guaranteed to be applied. For example, the annotations may not be
+     * applied if the text has changed from what it was when the link spec was generated for it.
+     *
+     * @return Whether or not the link annotations were successfully applied.
+     */
+    boolean apply(@NonNull CharSequence text);
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
new file mode 100644 (file)
index 0000000..b5ab4bf
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Interface to the text classification service.
+ *
+ * <p>You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ */
+public final class TextClassificationManager {
+
+    /** @hide */
+    public TextClassificationManager(Context context) {}
+
+    /**
+     * Returns the default text classifier.
+     */
+    public TextClassifier getDefaultTextClassifier() {
+        return TextClassifier.NO_OP;
+    }
+
+    /**
+     * Returns information containing languages that were detected in the provided text.
+     * This is a blocking operation you should avoid calling it on the UI thread.
+     *
+     * @throws IllegalArgumentException if text is null
+     */
+    public List<TextLanguage> detectLanguages(@NonNull CharSequence text) {
+        // TODO: Implement
+        return Collections.emptyList();
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationResult.java b/core/java/android/view/textclassifier/TextClassificationResult.java
new file mode 100644 (file)
index 0000000..6af0efb
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.View.OnClickListener;
+import android.view.textclassifier.TextClassifier.EntityType;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Information for generating a widget to handle classified text.
+ */
+public final class TextClassificationResult {
+
+    /**
+     * @hide
+     */
+    static final TextClassificationResult EMPTY = new TextClassificationResult.Builder().build();
+
+    @NonNull private final String mText;
+    @Nullable private final Drawable mIcon;
+    @Nullable private final String mLabel;
+    @Nullable private final Intent mIntent;
+    @Nullable private final OnClickListener mOnClickListener;
+    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final List<String> mEntities;
+
+    private TextClassificationResult(
+            @NonNull String text,
+            Drawable icon,
+            String label,
+            Intent intent,
+            OnClickListener onClickListener,
+            @NonNull EntityConfidence<String> entityConfidence) {
+        mText = text;
+        mIcon = icon;
+        mLabel = label;
+        mIntent = intent;
+        mOnClickListener = onClickListener;
+        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntities = mEntityConfidence.getEntities();
+    }
+
+    /**
+     * Gets the classified text.
+     */
+    @NonNull
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * Returns the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntities.size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntities.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    /**
+     * Returns an icon that may be rendered on a widget used to act on the classified text.
+     */
+    @Nullable
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns a label that may be rendered on a widget used to act on the classified text.
+     */
+    @Nullable
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Returns an intent that may be fired to act on the classified text.
+     */
+    @Nullable
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /**
+     * Returns an OnClickListener that may be triggered to act on the classified text.
+     */
+    @Nullable
+    public OnClickListener getOnClickListener() {
+        return mOnClickListener;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextClassificationResult {"
+                        + "text=%s, entities=%s, label=%s, intent=%s}",
+                mText, mEntityConfidence, mLabel, mIntent);
+    }
+
+    /**
+     * Creates an OnClickListener that starts an activity with the specified intent.
+     *
+     * @throws IllegalArgumentException if context or intent is null
+     * @hide
+     */
+    @NonNull
+    public static OnClickListener createStartActivityOnClick(
+            @NonNull final Context context, @NonNull final Intent intent) {
+        Preconditions.checkArgument(context != null);
+        Preconditions.checkArgument(intent != null);
+        return v -> context.startActivity(intent);
+    }
+
+    /**
+     * Builder for building {@link TextClassificationResult}s.
+     */
+    public static final class Builder {
+
+        @NonNull private String mText;
+        @Nullable private Drawable mIcon;
+        @Nullable private String mLabel;
+        @Nullable private Intent mIntent;
+        @Nullable private OnClickListener mOnClickListener;
+        @NonNull private final EntityConfidence<String> mEntityConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Sets the classified text.
+         */
+        public Builder setText(@NonNull String text) {
+            mText = Preconditions.checkNotNull(text);
+            return this;
+        }
+
+        /**
+         * Sets an entity type for the classification result and assigns a confidence score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0)float confidenceScore) {
+            mEntityConfidence.setEntityType(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Sets an icon that may be rendered on a widget used to act on the classified text.
+         */
+        public Builder setIcon(@Nullable Drawable icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets a label that may be rendered on a widget used to act on the classified text.
+         */
+        public Builder setLabel(@Nullable String label) {
+            mLabel = label;
+            return this;
+        }
+
+        /**
+         * Sets an intent that may be fired to act on the classified text.
+         */
+        public Builder setIntent(@Nullable Intent intent) {
+            mIntent = intent;
+            return this;
+        }
+
+        /**
+         * Sets an OnClickListener that may be triggered to act on the classified text.
+         */
+        public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
+            mOnClickListener = onClickListener;
+            return this;
+        }
+
+        /**
+         * Builds an returns a {@link TextClassificationResult}.
+         */
+        public TextClassificationResult build() {
+            return new TextClassificationResult(
+                    mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence);
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
new file mode 100644 (file)
index 0000000..b84e2ae
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for providing text classification related features.
+ *
+ * <p>Unless otherwise stated, methods of this interface are blocking operations and you should
+ * avoid calling them on the UI thread.
+ */
+public interface TextClassifier {
+
+    String TYPE_OTHER = "other";
+    String TYPE_EMAIL = "email";
+    String TYPE_PHONE = "phone";
+    String TYPE_ADDRESS = "address";
+
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef({
+            TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS
+    })
+    @interface EntityType {}
+
+    /**
+     * 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) {
+            return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+        }
+
+        @Override
+        public TextClassificationResult getTextClassificationResult(
+                CharSequence text, int startIndex, int endIndex) {
+            return TextClassificationResult.EMPTY;
+        }
+
+        @Override
+        public LinksInfo getLinks(CharSequence text, int linkMask) {
+            return LinksInfo.NO_OP;
+        }
+    };
+
+    /**
+     * Returns suggested text selection indices, recognized types and their associated confidence
+     * scores. The selections are ordered from highest to lowest scoring.
+     *
+     * @param text text providing context for the selected text (which is specified
+     *      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
+     *
+     * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
+     *      selectionEndIndex is greater than text.length() or less than selectionStartIndex
+     */
+    @NonNull
+    TextSelection suggestSelection(
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int selectionStartIndex,
+            @IntRange(from = 0) int selectionEndIndex);
+
+    /**
+     * Returns a {@link TextClassificationResult} object that can be used to generate a widget for
+     * handling the classified text.
+     *
+     * @param text text providing context for the text to classify (which is specified
+     *      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
+     *
+     * @throws IllegalArgumentException if text is null; startIndex is negative;
+     *      endIndex is greater than text.length() or less than startIndex
+     */
+    @NonNull
+    TextClassificationResult getTextClassificationResult(
+            @NonNull CharSequence text, int startIndex, int endIndex);
+
+    /**
+     * Returns a {@link LinksInfo} that may be applied to the text to annotate it with links
+     * information.
+     *
+     * @param text the text to generate annotations for
+     * @param linkMask See {@link android.text.util.Linkify} for a list of linkMasks that may be
+     *      specified. Subclasses of this interface may specify additional linkMasks
+     *
+     * @throws IllegalArgumentException if text is null
+     */
+    LinksInfo getLinks(@NonNull CharSequence text, int linkMask);
+}
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
new file mode 100644 (file)
index 0000000..d94d163
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Specifies detected languages for a section of text indicated by a start and end index.
+ */
+public final class TextLanguage {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    @NonNull private final EntityConfidence<Locale> mLanguageConfidence;
+    @NonNull private final List<Locale> mLanguages;
+
+    private TextLanguage(
+            int startIndex, int endIndex, @NonNull EntityConfidence<Locale> languageConfidence) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+        mLanguageConfidence = new EntityConfidence<>(languageConfidence);
+        mLanguages = mLanguageConfidence.getEntities();
+    }
+
+    /**
+     * Returns the start index of the detected languages in the text provided to generate this
+     * object.
+     */
+    public int getStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * Returns the end index of the detected languages in the text provided to generate this object.
+     */
+    public int getEndIndex() {
+        return mEndIndex;
+    }
+
+    /**
+     * Returns the number of languages found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getLanguageCount() {
+        return mLanguages.size();
+    }
+
+    /**
+     * Returns the language locale at the specified index.
+     * Language locales are ordered from high confidence to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getLanguageCount() for the number of language locales available.
+     */
+    @NonNull
+    public Locale getLanguage(int index) {
+        return mLanguages.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified language. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the language was
+     * not found for the classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@Nullable Locale language) {
+        return mLanguageConfidence.getConfidenceScore(language);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextLanguage {%d, %d, %s}",
+                mStartIndex, mEndIndex, mLanguageConfidence);
+    }
+
+    /**
+     * Builder to build {@link TextLanguage} objects.
+     */
+    public static final class Builder {
+
+        private final int mStartIndex;
+        private final int mEndIndex;
+        @NonNull private final EntityConfidence<Locale> mLanguageConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Creates a builder to build {@link TextLanguage} objects.
+         *
+         * @param startIndex the start index of the detected languages in the text provided
+         *      to generate the result
+         * @param endIndex the end index of the detected languages in the text provided
+         *      to generate the result. Must be greater than startIndex
+         */
+        public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex > startIndex);
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * Sets a language locale with the associated confidence score.
+         */
+        public Builder setLanguage(
+                @NonNull Locale locale, @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mLanguageConfidence.setEntityType(locale, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@link TextLanguage}.
+         */
+        public TextLanguage build() {
+            return new TextLanguage(mStartIndex, mEndIndex, mLanguageConfidence);
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
new file mode 100644 (file)
index 0000000..3172c13
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.view.textclassifier.TextClassifier.EntityType;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Information about where text selection should be.
+ */
+public final class TextSelection {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final List<String> mEntities;
+
+    private TextSelection(
+            int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntities = mEntityConfidence.getEntities();
+    }
+
+    /**
+     * 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 the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntities.size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntities.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextSelection {%d, %d, %s}",
+                mStartIndex, mEndIndex, mEntityConfidence);
+    }
+
+    /**
+     * Builder used to build {@link TextSelection} objects.
+     */
+    public static final class Builder {
+
+        private final int mStartIndex;
+        private final int mEndIndex;
+        @NonNull private final EntityConfidence<String> mEntityConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Creates a builder used to build {@link TextSelection} objects.
+         *
+         * @param startIndex the start index of the text selection.
+         * @param endIndex the end index of the text selection. Must be greater than startIndex
+         */
+        public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex > startIndex);
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * Sets an entity type for the classified text and assigns a confidence score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mEntityConfidence.setEntityType(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Builds and returns {@link TextSelection} object.
+         */
+        public TextSelection build() {
+            return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence);
+        }
+    }
+}
index 2fc8ec9..f7f9a81 100644 (file)
@@ -60,8 +60,6 @@ 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;
@@ -108,6 +106,8 @@ import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassificationResult;
+import android.view.textclassifier.TextSelection;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.TextView.Drawables;
 import android.widget.TextView.OnEditorActionListener;
@@ -149,7 +149,7 @@ 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.
-    // 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_ASSIST = 1;
     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;
@@ -238,6 +238,8 @@ public class Editor {
     private boolean mPreserveSelection;
     private boolean mRestartActionModeOnNextRefresh;
 
+    private TextClassificationResult mTextClassificationResult;
+
     boolean mIsBeingLongClicked;
 
     private SuggestionsPopupWindow mSuggestionsPopupWindow;
@@ -1889,7 +1891,7 @@ public class Editor {
             mInsertionPointCursorController.invalidateHandle();
         }
         if (mTextActionMode != null) {
-            mTextActionMode.invalidate();
+            invalidateActionMode(getTextClassifierInfo(false));
         }
     }
 
@@ -1982,12 +1984,12 @@ public class Editor {
                 if (mRestartActionModeOnNextRefresh) {
                     // To avoid distraction, newly start action mode only when selection action
                     // mode is being restarted.
-                    startSelectionActionMode();
+                    startSelectionActionMode(getTextClassifierInfo(true));
                 }
             } else if (selectionController == null || !selectionController.isActive()) {
                 // Insertion action mode is active. Avoid dismissing the selection.
                 stopTextActionModeWithPreservingSelection();
-                startSelectionActionMode();
+                startSelectionActionMode(getTextClassifierInfo(true));
             } else {
                 mTextActionMode.invalidateContentRect();
             }
@@ -2031,7 +2033,8 @@ public class Editor {
      *
      * @return true if the selection mode was actually started.
      */
-    boolean startSelectionActionMode() {
+    boolean startSelectionActionMode(@Nullable TextClassificationResult textClassificationResult) {
+        mTextClassificationResult = textClassificationResult;
         boolean selectionStarted = startSelectionActionModeInternal();
         if (selectionStarted) {
             getSelectionController().show();
@@ -2040,6 +2043,40 @@ public class Editor {
         return selectionStarted;
     }
 
+    private boolean startSelectionActionModeWithTextAssistant() {
+        return startSelectionActionMode(getTextClassifierInfo(true));
+    }
+
+    private void invalidateActionMode(TextClassificationResult textClassificationResult) {
+        mTextClassificationResult = textClassificationResult;
+        mTextActionMode.invalidate();
+    }
+
+    // TODO: Make this a non-blocking call.
+    private TextClassificationResult getTextClassifierInfo(boolean updateSelection) {
+        // TODO: Trim the text so that only text necessary to provide context of the selected
+        // text is sent to the assistant.
+        final int trimStartIndex = 0;
+        final int trimEndIndex = mTextView.getText().length();
+        CharSequence trimmedText =
+                mTextView.getText().subSequence(trimStartIndex, trimEndIndex);
+        int startIndex = mTextView.getSelectionStart() - trimStartIndex;
+        int endIndex = mTextView.getSelectionEnd() - trimStartIndex;
+
+        if (updateSelection) {
+            TextSelection textSelection = mTextView.getTextClassifier()
+                    .suggestSelection(trimmedText, startIndex, endIndex);
+            startIndex = Math.max(0, textSelection.getSelectionStartIndex() + trimStartIndex);
+            endIndex = Math.min(mTextView.getText().length(),
+                    textSelection.getSelectionEndIndex() + trimStartIndex);
+            Selection.setSelection((Spannable) mTextView.getText(), startIndex, endIndex);
+            return getTextClassifierInfo(false);
+        }
+
+        return mTextView.getTextClassifier()
+                .getTextClassificationResult(trimmedText, startIndex, endIndex);
+    }
+
     /**
      * If the TextView allows text selection, selects the current word when no existing selection
      * was available and starts a drag.
@@ -2086,7 +2123,7 @@ public class Editor {
         }
         if (mTextActionMode != null) {
             // Text action mode is already started
-            mTextActionMode.invalidate();
+            invalidateActionMode(getTextClassifierInfo(false));
             return false;
         }
 
@@ -3744,8 +3781,7 @@ public class Editor {
         private final Path mSelectionPath = new Path();
         private final RectF mSelectionBounds = new RectF();
         private final boolean mHasSelection;
-
-        private int mHandleHeight;
+        private final int mHandleHeight;
 
         public TextActionModeCallback(boolean hasSelection) {
             mHasSelection = hasSelection;
@@ -3765,18 +3801,19 @@ public class Editor {
                 if (insertionController != null) {
                     insertionController.getHandle();
                     mHandleHeight = mSelectHandleCenter.getMinimumHeight();
+                } else {
+                    mHandleHeight = 0;
                 }
             }
         }
 
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            TextClassification textClassification = updateSelectionWithTextAssistant();
-
             mode.setTitle(null);
             mode.setSubtitle(null);
             mode.setTitleOptionalHint(true);
-            populateMenuWithItems(menu, textClassification);
+            populateMenuWithItems(menu);
+            updateAssistMenuItem(menu, mTextClassificationResult);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3802,30 +3839,13 @@ 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, TextClassification textClassification) {
+        private void populateMenuWithItems(Menu menu) {
             if (mTextView.canCut()) {
                 menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT,
                         com.android.internal.R.string.cut)
@@ -3855,13 +3875,13 @@ public class Editor {
 
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
-            updateAssistMenuItem(menu, textClassification);
         }
 
         @Override
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
+            updateAssistMenuItem(menu, mTextClassificationResult);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3894,10 +3914,16 @@ 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.
+        private void updateAssistMenuItem(
+                Menu menu, TextClassificationResult textClassificationResult) {
+            menu.removeItem(TextView.ID_ASSIST);
+            if (textClassificationResult != null
+                    && textClassificationResult.getIcon() != null
+                    && textClassificationResult.getOnClickListener() != null) {
+                menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, null)
+                        .setIcon(textClassificationResult.getIcon())
+                        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+            }
         }
 
         @Override
@@ -3909,6 +3935,10 @@ public class Editor {
             if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
                 return true;
             }
+            if (TextView.ID_ASSIST == item.getItemId() && mTextClassificationResult != null) {
+                mTextClassificationResult.getOnClickListener().onClick(mTextView);
+                stopTextActionMode();
+            }
             return mTextView.onTextContextMenuItem(item.getItemId());
         }
 
@@ -3916,6 +3946,7 @@ public class Editor {
         public void onDestroyActionMode(ActionMode mode) {
             // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
             mTextActionMode = null;
+            mTextClassificationResult = null;
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
                 customCallback.onDestroyActionMode(mode);
@@ -4733,7 +4764,7 @@ public class Editor {
             }
             positionAtCursorOffset(offset, false);
             if (mTextActionMode != null) {
-                mTextActionMode.invalidate();
+                invalidateActionMode(getTextClassifierInfo(false));
             }
         }
 
@@ -4817,7 +4848,7 @@ public class Editor {
             }
             updateDrawable();
             if (mTextActionMode != null) {
-                mTextActionMode.invalidate();
+                invalidateActionMode(getTextClassifierInfo(false));
             }
         }
 
@@ -5465,7 +5496,8 @@ public class Editor {
                     resetDragAcceleratorState();
 
                     if (mTextView.hasSelection()) {
-                        startSelectionActionMode();
+                        // TODO: Do not invoke the text assistant if this was a drag selection.
+                        startSelectionActionMode(getTextClassifierInfo(true));
                     }
                     break;
             }
index b1fc67e..2f303cd 100644 (file)
@@ -77,8 +77,6 @@ import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
 import android.text.StaticLayout;
-import android.text.TextAssistant;
-import android.text.TextClassificationManager;
 import android.text.TextDirectionHeuristic;
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
@@ -146,6 +144,8 @@ import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassificationManager;
+import android.view.textclassifier.TextClassifier;
 import android.view.textservice.SpellCheckerSubtype;
 import android.view.textservice.TextServicesManager;
 import android.widget.RemoteViews.RemoteView;
@@ -352,6 +352,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     private boolean mPreDrawRegistered;
     private boolean mPreDrawListenerDetached;
 
+    private TextClassifier mTextClassifier;
+
     // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
     // that if a user is holding down a movement key to traverse text, we shouldn't also traverse
     // the view hierarchy. On the other hand, if the user is using the movement key to traverse
@@ -9890,7 +9892,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                         Selection.setSelection((Spannable) text, start, end);
                         // Make sure selection mode is engaged.
                         if (mEditor != null) {
-                            mEditor.startSelectionActionMode();
+                            mEditor.startSelectionActionMode(null);
                         }
                         return true;
                     }
@@ -10034,6 +10036,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     static final int ID_SHARE = android.R.id.shareText;
     static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
     static final int ID_REPLACE = android.R.id.replaceText;
+    static final int ID_ASSIST = android.R.id.textAssist;
 
     /**
      * Called when a context menu option for the text view is selected.  Currently
@@ -10258,33 +10261,30 @@ 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.
+     * Sets the {@link TextClassifier} for this TextView.
      */
-    public void setTextAssistant(TextAssistant textAssistant) {
-        mTextAssistant = textAssistant;
+    public void setTextClassifier(@Nullable TextClassifier textClassifier) {
+        mTextClassifier = textClassifier;
     }
 
     /**
-     * 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.
+     * Returns the {@link TextClassifier} used by this TextView.
+     * If no TextClassifier has been set, this TextView uses the default set by the
+     * {@link TextClassificationManager}.
      */
-    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 the TextClassificationManager.
-            mTextAssistant = mContext.getSystemService(TextClassificationManager.class);
+    @NonNull
+    public TextClassifier getTextClassifier() {
+        if (mTextClassifier == null) {
+            TextClassificationManager tcm =
+                    mContext.getSystemService(TextClassificationManager.class);
+            if (tcm != null) {
+                mTextClassifier = tcm.getDefaultTextClassifier();
+            } else {
+                mTextClassifier = TextClassifier.NO_OP;
+            }
         }
-        return  mTextAssistant;
+        return mTextClassifier;
     }
 
     /**
index f351b70..613616f 100644 (file)
@@ -97,6 +97,7 @@
   <item type="id" name="redo" />
   <item type="id" name="replaceText" />
   <item type="id" name="shareText" />
+  <item type="id" name="textAssist" />
   <item type="id" name="selection_start_handle" />
   <item type="id" name="selection_end_handle" />
   <item type="id" name="insertion_handle" />
index 060c59e..6c24e0a 100644 (file)
     </public-group>
 
     <public-group type="id" first-id="0x01020041">
+        <public name="textAssist" />
     </public-group>
 
     <public type="attr" name="primaryContentAlpha" />