summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorNikita Dubrovsky <dubrovsky@google.com>2020-09-09 15:45:38 -0700
committerNikita Dubrovsky <dubrovsky@google.com>2021-01-11 20:57:48 +0000
commite8f7c4ba7c7a39c7294eed0a37e9b69ca93310f6 (patch)
tree916c0d4fd3d73266805ee3cf31debc2e9a12178c /core/java/android
parent677c97ddf8cf663c73673b9f454fbedd726e3150 (diff)
Add MIME types to ViewStructure and autofill/cc ViewNode classes
Bug: 168253885 Test: atest FrameworksCoreTests:TextViewOnReceiveContentTest Test: Manual CTS-Coverage-Bug: 170893906 Change-Id: Iac8f73a7a022f20f59ecef9be89e3189ca106e4c
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/assist/AssistStructure.java29
-rw-r--r--core/java/android/view/View.java1
-rw-r--r--core/java/android/view/ViewStructure.java8
-rw-r--r--core/java/android/view/contentcapture/ViewNode.java22
-rw-r--r--core/java/android/widget/Editor.java15
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/android/widget/TextViewOnReceiveContentListener.java15
7 files changed, 96 insertions, 6 deletions
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0f7fac4eefa5..65a21640bb98 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -672,6 +672,7 @@ public class AssistStructure implements Parcelable {
static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
static final int FLAGS_OPAQUE = 0x00008000;
+ static final int FLAGS_HAS_MIME_TYPES = 0x80000000;
static final int FLAGS_HAS_MATRIX = 0x40000000;
static final int FLAGS_HAS_ALPHA = 0x20000000;
static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -715,6 +716,7 @@ public class AssistStructure implements Parcelable {
String mWebDomain;
Bundle mExtras;
LocaleList mLocaleList;
+ String[] mOnReceiveContentMimeTypes;
ViewNode[] mChildren;
@@ -880,6 +882,9 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
mLocaleList = in.readParcelable(null);
}
+ if ((flags & FLAGS_HAS_MIME_TYPES) != 0) {
+ mOnReceiveContentMimeTypes = in.readStringArray();
+ }
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
mExtras = in.readBundle();
}
@@ -939,6 +944,9 @@ public class AssistStructure implements Parcelable {
if (mLocaleList != null) {
flags |= FLAGS_HAS_LOCALE_LIST;
}
+ if (mOnReceiveContentMimeTypes != null) {
+ flags |= FLAGS_HAS_MIME_TYPES;
+ }
if (mExtras != null) {
flags |= FLAGS_HAS_EXTRAS;
}
@@ -1109,6 +1117,9 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
out.writeParcelable(mLocaleList, 0);
}
+ if ((flags & FLAGS_HAS_MIME_TYPES) != 0) {
+ out.writeStringArray(mOnReceiveContentMimeTypes);
+ }
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
out.writeBundle(mExtras);
}
@@ -1527,6 +1538,15 @@ public class AssistStructure implements Parcelable {
}
/**
+ * Returns the MIME types accepted by {@link View#performReceiveContent} for this view. See
+ * {@link View#getOnReceiveContentMimeTypes()} for details.
+ */
+ @Nullable
+ public String[] getOnReceiveContentMimeTypes() {
+ return mOnReceiveContentMimeTypes;
+ }
+
+ /**
* Returns any text associated with the node that is displayed to the user, or null
* if there is none.
*/
@@ -2146,6 +2166,11 @@ public class AssistStructure implements Parcelable {
}
@Override
+ public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
+ mNode.mOnReceiveContentMimeTypes = mimeTypes;
+ }
+
+ @Override
public void setInputType(int inputType) {
mNode.mInputType = inputType;
}
@@ -2422,6 +2447,10 @@ public class AssistStructure implements Parcelable {
if (localeList != null) {
Log.i(TAG, prefix + " LocaleList: " + localeList);
}
+ String[] mimeTypes = node.getOnReceiveContentMimeTypes();
+ if (mimeTypes != null) {
+ Log.i(TAG, prefix + " MIME types: " + Arrays.toString(mimeTypes));
+ }
String hint = node.getHint();
if (hint != null) {
Log.i(TAG, prefix + " Hint: " + hint);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0f5321548f95..e8584dac90c8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8821,6 +8821,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
structure.setAutofillValue(getAutofillValue());
}
structure.setImportantForAutofill(getImportantForAutofill());
+ structure.setOnReceiveContentMimeTypes(getOnReceiveContentMimeTypes());
}
int ignoredParentLeft = 0;
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 29ce231d5d87..f5aa97a88608 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -372,6 +372,14 @@ public abstract class ViewStructure {
public void setImportantForAutofill(@AutofillImportance int mode) {}
/**
+ * Sets the MIME types accepted by this view. See {@link View#getOnReceiveContentMimeTypes()}.
+ *
+ * <p>Should only be set when the node is used for Autofill or Content Capture purposes - it
+ * will be ignored when used for Assist.
+ */
+ public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {}
+
+ /**
* Sets the {@link android.text.InputType} bits of this node.
*
* @param inputType inputType bits as defined by {@link android.text.InputType}.
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index e731d4b76fb9..4e9c229e03a0 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -81,6 +81,7 @@ public final class ViewNode extends AssistStructure.ViewNode {
private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35;
+ private static final long FLAGS_HAS_MIME_TYPES = 1L << 36;
/** Flags used to optimize what's written to the parcel */
private long mFlags;
@@ -113,6 +114,7 @@ public final class ViewNode extends AssistStructure.ViewNode {
private String[] mAutofillHints;
private AutofillValue mAutofillValue;
private CharSequence[] mAutofillOptions;
+ private String[] mOnReceiveContentMimeTypes;
/** @hide */
public ViewNode() {
@@ -169,6 +171,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
mLocaleList = parcel.readParcelable(null);
}
+ if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
+ mOnReceiveContentMimeTypes = parcel.readStringArray();
+ }
if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
mInputType = parcel.readInt();
}
@@ -463,6 +468,12 @@ public final class ViewNode extends AssistStructure.ViewNode {
return mAutofillOptions;
}
+ @Override
+ @Nullable
+ public String[] getOnReceiveContentMimeTypes() {
+ return mOnReceiveContentMimeTypes;
+ }
+
@Nullable
@Override
public LocaleList getLocaleList() {
@@ -508,6 +519,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if (mLocaleList != null) {
nodeFlags |= FLAGS_HAS_LOCALE_LIST;
}
+ if (mOnReceiveContentMimeTypes != null) {
+ nodeFlags |= FLAGS_HAS_MIME_TYPES;
+ }
if (mInputType != 0) {
nodeFlags |= FLAGS_HAS_INPUT_TYPE;
}
@@ -584,6 +598,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
parcel.writeParcelable(mLocaleList, 0);
}
+ if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
+ parcel.writeStringArray(mOnReceiveContentMimeTypes);
+ }
if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
parcel.writeInt(mInputType);
}
@@ -912,6 +929,11 @@ public final class ViewNode extends AssistStructure.ViewNode {
}
@Override
+ public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
+ mNode.mOnReceiveContentMimeTypes = mimeTypes;
+ }
+
+ @Override
public void setAutofillHints(String[] hints) {
mNode.mAutofillHints = hints;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0025d1e2a853..9ffb4bfbb9c1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -99,6 +99,7 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.OnReceiveContentListener;
import android.view.SubMenu;
import android.view.View;
import android.view.View.DragShadowBuilder;
@@ -588,8 +589,18 @@ public class Editor {
mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
}
- @VisibleForTesting
- public @NonNull TextViewOnReceiveContentListener getDefaultOnReceiveContentListener() {
+ /**
+ * Returns the default handler for receiving content in an editable {@link TextView}. This
+ * listener impl is used to encapsulate the default behavior but it is not part of the public
+ * API. If an app wants to execute the default platform behavior for receiving content, it
+ * should call {@link View#onReceiveContent}. Alternatively, if an app implements a custom
+ * listener for receiving content and wants to delegate some of the content to be handled by
+ * the platform, it should return the corresponding content from its listener. See
+ * {@link View#setOnReceiveContentListener} and {@link OnReceiveContentListener} for more info.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ @NonNull
+ public TextViewOnReceiveContentListener getDefaultOnReceiveContentListener() {
return mDefaultOnReceiveContentListener;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4edfc5f309b2..2a21c3aa2e57 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11686,6 +11686,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
}
+ String[] mimeTypes = getOnReceiveContentMimeTypes();
+ if (mimeTypes == null && mEditor != null) {
+ // If the app hasn't set a listener for receiving content on this view (ie,
+ // getOnReceiveContentMimeTypes() returns null), check if it implements the
+ // keyboard image API and, if possible, use those MIME types as fallback.
+ // This fallback is only in place for autofill, not other mechanisms for
+ // inserting content. See AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_LISTENER
+ // in TextViewOnReceiveContentListener for more info.
+ mimeTypes = mEditor.getDefaultOnReceiveContentListener()
+ .getFallbackMimeTypesForAutofill(this);
+ }
+ structure.setOnReceiveContentMimeTypes(mimeTypes);
}
if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
diff --git a/core/java/android/widget/TextViewOnReceiveContentListener.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 8cef1061c423..91fac5511807 100644
--- a/core/java/android/widget/TextViewOnReceiveContentListener.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -60,7 +60,7 @@ import java.util.Arrays;
*
* @hide
*/
-@VisibleForTesting
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final class TextViewOnReceiveContentListener implements OnReceiveContentListener {
private static final String LOG_TAG = "ReceiveContent";
@@ -261,10 +261,17 @@ public final class TextViewOnReceiveContentListener implements OnReceiveContentL
mInputConnectionInfo = null;
}
- /** @hide */
- @VisibleForTesting
+ /**
+ * Returns the MIME types accepted by {@link View#performReceiveContent} for the given view,
+ * <strong>for autofill purposes</strong>. This will be non-null only if fallback to the
+ * keyboard image API {@link #isUsageOfImeCommitContentEnabled is enabled} and the view has an
+ * {@link InputConnection} with {@link EditorInfo#contentMimeTypes} populated.
+ *
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@Nullable
- public String[] getEditorInfoMimeTypes(@NonNull TextView view) {
+ public String[] getFallbackMimeTypesForAutofill(@NonNull TextView view) {
if (!isUsageOfImeCommitContentEnabled(view)) {
return null;
}