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
This commit is contained in:
Nikita Dubrovsky
2020-09-09 15:45:38 -07:00
parent 677c97ddf8
commit e8f7c4ba7c
9 changed files with 103 additions and 10 deletions

View File

@@ -7492,6 +7492,7 @@ package android.app.assist {
method public int getMaxTextEms();
method public int getMaxTextLength();
method public int getMinTextEms();
method @Nullable public String[] getOnReceiveContentMimeTypes();
method public int getScrollX();
method public int getScrollY();
method @Nullable public CharSequence getText();
@@ -48686,6 +48687,7 @@ package android.view {
method public void setMaxTextEms(int);
method public void setMaxTextLength(int);
method public void setMinTextEms(int);
method public void setOnReceiveContentMimeTypes(@Nullable String[]);
method public abstract void setOpaque(boolean);
method public abstract void setSelected(boolean);
method public abstract void setText(CharSequence);

View File

@@ -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);
}
@@ -1526,6 +1537,15 @@ public class AssistStructure implements Parcelable {
return mLocaleList;
}
/**
* 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.
@@ -2145,6 +2165,11 @@ public class AssistStructure implements Parcelable {
mNode.mImportantForAutofill = mode;
}
@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);

View File

@@ -8821,6 +8821,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
structure.setAutofillValue(getAutofillValue());
}
structure.setImportantForAutofill(getImportantForAutofill());
structure.setOnReceiveContentMimeTypes(getOnReceiveContentMimeTypes());
}
int ignoredParentLeft = 0;

View File

@@ -371,6 +371,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.
*

View File

@@ -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);
}
@@ -911,6 +928,11 @@ public final class ViewNode extends AssistStructure.ViewNode {
mNode.mAutofillType = type;
}
@Override
public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
mNode.mOnReceiveContentMimeTypes = mimeTypes;
}
@Override
public void setAutofillHints(String[] hints) {
mNode.mAutofillHints = hints;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -87,7 +87,7 @@ public class TextViewOnReceiveContentTest {
}
@Test
public void testGetEditorInfoMimeTypes_fallbackToCommitContent() throws Throwable {
public void testGetFallbackMimeTypesForAutofill() throws Throwable {
// Configure the EditText with an EditorInfo/InputConnection that supports some image MIME
// types.
String[] mimeTypes = {"image/gif", "image/png"};
@@ -99,11 +99,12 @@ public class TextViewOnReceiveContentTest {
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
// Assert that the default listener returns the MIME types declared in the EditorInfo.
assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isEqualTo(mimeTypes);
assertThat(mDefaultReceiver.getFallbackMimeTypesForAutofill(mEditText)).isEqualTo(
mimeTypes);
}
@Test
public void testGetEditorInfoMimeTypes_fallbackToCommitContent_noMimeTypesInEditorInfo()
public void testGetFallbackMimeTypesForAutofill_noMimeTypesInEditorInfo()
throws Throwable {
// Configure the EditText with an EditorInfo/InputConnection that doesn't declare any MIME
// types.
@@ -115,7 +116,7 @@ public class TextViewOnReceiveContentTest {
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
// Assert that the default listener returns null as the MIME types.
assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isNull();
assertThat(mDefaultReceiver.getFallbackMimeTypesForAutofill(mEditText)).isNull();
}
@Test