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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -8821,6 +8821,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
structure.setAutofillValue(getAutofillValue());
|
||||
}
|
||||
structure.setImportantForAutofill(getImportantForAutofill());
|
||||
structure.setOnReceiveContentMimeTypes(getOnReceiveContentMimeTypes());
|
||||
}
|
||||
|
||||
int ignoredParentLeft = 0;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user