summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt8
-rw-r--r--core/java/android/content/ClipDescription.java19
-rw-r--r--core/java/android/view/OnReceiveContentCallback.java81
-rw-r--r--core/java/android/view/View.java84
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java28
-rw-r--r--core/java/android/widget/TextView.java68
-rw-r--r--core/java/android/widget/TextViewOnReceiveContentCallback.java37
-rw-r--r--core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java6
-rw-r--r--non-updatable-api/current.txt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java61
10 files changed, 211 insertions, 189 deletions
diff --git a/api/current.txt b/api/current.txt
index b35940449f9e..1807283f1ed2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -53778,7 +53778,6 @@ package android.view {
}
public interface OnReceiveContentCallback<T extends android.view.View> {
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
}
@@ -54356,7 +54355,7 @@ package android.view {
method @IdRes public int getNextFocusRightId();
method @IdRes public int getNextFocusUpId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
- method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
+ method @Nullable public String[] getOnReceiveContentMimeTypes();
method @ColorInt public int getOutlineAmbientShadowColor();
method public android.view.ViewOutlineProvider getOutlineProvider();
method @ColorInt public int getOutlineSpotShadowColor();
@@ -54551,6 +54550,7 @@ package android.view {
method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
+ method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
method public void onRtlPropertiesChanged(int);
@@ -54708,7 +54708,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
- method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
+ method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -61538,7 +61538,6 @@ package android.widget {
method public int getMinWidth();
method public final android.text.method.MovementMethod getMovementMethod();
method public int getOffsetForPosition(float, float);
- method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
method public android.text.TextPaint getPaint();
method public int getPaintFlags();
method public String getPrivateImeOptions();
@@ -61727,7 +61726,6 @@ package android.widget {
public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
ctor public TextViewOnReceiveContentCallback();
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
}
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 38ab8aa2dcbc..f9e6308515cf 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -217,6 +218,24 @@ public class ClipDescription implements Parcelable {
}
/**
+ * Check whether the clip description contains any of the given MIME types.
+ *
+ * @param targetMimeTypes The target MIME types. May use patterns.
+ * @return Returns true if at least one of the MIME types in the clip description matches at
+ * least one of the target MIME types, else false.
+ *
+ * @hide
+ */
+ public boolean hasMimeType(@NonNull String[] targetMimeTypes) {
+ for (String targetMimeType : targetMimeTypes) {
+ if (hasMimeType(targetMimeType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Filter the clip description MIME types by the given MIME type. Returns
* all MIME types in the clip that match the given MIME type.
*
diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentCallback.java
index a217ff642ab7..d74938c1d1fd 100644
--- a/core/java/android/view/OnReceiveContentCallback.java
+++ b/core/java/android/view/OnReceiveContentCallback.java
@@ -19,9 +19,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.content.ClipData;
-import android.content.ClipDescription;
import android.net.Uri;
import android.os.Bundle;
@@ -30,11 +28,10 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
-import java.util.Set;
/**
- * Callback for apps to implement handling for insertion of content. "Content" here refers to both
- * text and non-text (plain/styled text, HTML, images, videos, audio files, etc).
+ * Callback for apps to implement handling for insertion of content. Content may be both text and
+ * non-text (plain/styled text, HTML, images, videos, audio files, etc).
*
* <p>This callback can be attached to different types of UI components using
* {@link View#setOnReceiveContentCallback}.
@@ -45,32 +42,38 @@ import java.util.Set;
*
* <p>Example implementation:<br>
* <pre class="prettyprint">
+ * // (1) Define the callback
* public class MyOnReceiveContentCallback implements OnReceiveContentCallback&lt;TextView&gt; {
- *
- * private static final Set&lt;String&gt; SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(
+ * public static final Set&lt;String&gt; MIME_TYPES = Collections.unmodifiableSet(
* Set.of("image/*", "video/*"));
*
- * &#64;NonNull
- * &#64;Override
- * public Set&lt;String&gt; getSupportedMimeTypes() {
- * return SUPPORTED_MIME_TYPES;
- * }
- *
* &#64;Override
* public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
* // ... app-specific logic to handle the content in the payload ...
* }
* }
+ *
+ * // (2) Register the callback
+ * public class MyActivity extends Activity {
+ * &#64;Override
+ * public void onCreate(Bundle savedInstanceState) {
+ * // ...
+ *
+ * EditText myInput = findViewById(R.id.my_input);
+ * myInput.setOnReceiveContentCallback(
+ * MyOnReceiveContentCallback.MIME_TYPES,
+ * new MyOnReceiveContentCallback());
+ * }
* </pre>
*
- * @param <T> The type of {@link View} with which this receiver can be associated.
+ * @param <T> The type of {@link View} with which this callback can be associated.
*/
public interface OnReceiveContentCallback<T extends View> {
/**
* Receive the given content.
*
- * <p>This function will only be invoked if the MIME type of the content is in the set of
- * types returned by {@link #getSupportedMimeTypes}.
+ * <p>This method is only invoked for content whose MIME type matches a type specified via
+ * {@link View#setOnReceiveContentCallback}.
*
* <p>For text, if the view has a selection, the selection should be overwritten by the clip; if
* there's no selection, this method should insert the content at the current cursor position.
@@ -81,54 +84,14 @@ public interface OnReceiveContentCallback<T extends View> {
* @param view The view where the content insertion was requested.
* @param payload The content to insert and related metadata.
*
- * @return Returns true if some or all of the content is accepted for insertion. If accepted,
- * actual insertion may be handled asynchronously in the background and may or may not result in
- * successful insertion. For example, the app may not end up inserting an accepted item if it
+ * @return Returns true if the content was handled in some way, false otherwise. Actual
+ * insertion may be processed asynchronously in the background and may or may not succeed even
+ * if this method returns true. For example, an app may not end up inserting an item if it
* exceeds the app's size limit for that type of content.
*/
boolean onReceiveContent(@NonNull T view, @NonNull Payload payload);
/**
- * Returns the MIME types that can be handled by this callback.
- *
- * <p>The {@link #onReceiveContent} callback method will only be invoked if the MIME type of the
- * content is in the set of supported types returned here.
- *
- * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
- * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
- * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has
- * a {@link OnReceiveContentCallback} set and the MIME types returned from this function don't
- * include "image/gif".
- *
- * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
- * MIME types. As a result, you should always write your MIME types with lower case letters, or
- * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
- * case.</em>
- *
- * @param view The target view.
- * @return An immutable set with the MIME types supported by this callback. The returned MIME
- * types may contain wildcards such as "text/*", "image/*", etc.
- */
- @SuppressLint("CallbackMethodName")
- @NonNull
- Set<String> getSupportedMimeTypes(@NonNull T view);
-
- /**
- * Returns true if at least one of the MIME types of the given clip is
- * {@link #getSupportedMimeTypes supported} by this receiver.
- *
- * @hide
- */
- default boolean supports(@NonNull T view, @NonNull ClipDescription description) {
- for (String supportedMimeType : getSupportedMimeTypes(view)) {
- if (description.hasMimeType(supportedMimeType)) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Holds all the relevant data for a request to {@link OnReceiveContentCallback}.
*/
final class Payload {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bda368ecb3a2..ac628e145eee 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -47,6 +47,7 @@ import android.annotation.UiThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AutofillOptions;
import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
@@ -143,6 +144,7 @@ import android.widget.ScrollBarDrawable;
import com.android.internal.R;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.Preconditions;
import com.android.internal.view.ScrollCaptureInternal;
import com.android.internal.view.TooltipPopup;
import com.android.internal.view.menu.MenuBuilder;
@@ -5243,7 +5245,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE;
@Nullable
- private OnReceiveContentCallback<? extends View> mOnReceiveContentCallback;
+ private String[] mOnReceiveContentMimeTypes;
+ @Nullable
+ private OnReceiveContentCallback mOnReceiveContentCallback;
/**
* Simple constructor to use when creating a view from code.
@@ -9001,36 +9005,78 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Returns the callback used for handling insertion of content into this view. See
- * {@link #setOnReceiveContentCallback} for more info.
- *
- * @return The callback for handling insertion of content. Returns null if no callback has been
- * {@link #setOnReceiveContentCallback set}.
- */
- @Nullable
- public OnReceiveContentCallback<? extends View> getOnReceiveContentCallback() {
- return mOnReceiveContentCallback;
- }
-
- /**
* Sets the callback to handle insertion of content into this view.
*
* <p>Depending on the view, this callback may be invoked for scenarios such as content
* insertion from the IME, Autofill, etc.
*
- * <p>The callback will only be invoked if the MIME type of the content is
- * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
- * If the content type is not supported by the callback, the default platform handling will be
- * executed instead.
+ * <p>This callback is only invoked for content whose MIME type matches a type specified via
+ * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the
+ * default platform handling will be executed instead (no-op for the default {@link View}).
*
+ * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
+ * MIME types. As a result, you should always write your MIME types with lower case letters, or
+ * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
+ * case.</em>
+ *
+ * @param mimeTypes The type of content for which the callback should be invoked. This may use
+ * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null
+ * callback is passed in.
* @param callback The callback to use. This can be null to reset to the default behavior.
*/
- public void setOnReceiveContentCallback(
- @Nullable OnReceiveContentCallback<? extends View> callback) {
+ @SuppressWarnings("rawtypes")
+ public void setOnReceiveContentCallback(@Nullable String[] mimeTypes,
+ @Nullable OnReceiveContentCallback callback) {
+ if (callback != null) {
+ Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0,
+ "When the callback is set, MIME types must also be set");
+ }
+ mOnReceiveContentMimeTypes = mimeTypes;
mOnReceiveContentCallback = callback;
}
/**
+ * Receives the given content. The default implementation invokes the callback set via
+ * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not
+ * support the given content (based on the MIME type), returns false.
+ *
+ * @param payload The content to insert and related metadata.
+ *
+ * @return Returns true if the content was handled in some way, false otherwise. Actual
+ * insertion may be processed asynchronously in the background and may or may not succeed even
+ * if this method returns true. For example, an app may not end up inserting an item if it
+ * exceeds the app's size limit for that type of content.
+ */
+ public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
+ ClipDescription description = payload.getClip().getDescription();
+ if (mOnReceiveContentCallback != null && mOnReceiveContentMimeTypes != null
+ && description.hasMimeType(mOnReceiveContentMimeTypes)) {
+ return mOnReceiveContentCallback.onReceiveContent(this, payload);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the MIME types that can be handled by {@link #onReceiveContent} for this view, as
+ * configured via {@link #setOnReceiveContentCallback}. By default returns null.
+ *
+ * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
+ * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
+ * soft keyboard may choose to hide its UI for inserting GIFs for a particular input field if
+ * the MIME types returned here for that field don't include "image/gif".
+ *
+ * <p>Note: Comparisons of MIME types should be performed using utilities such as
+ * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to
+ * correctly handle patterns (e.g. "text/*").
+ *
+ * @return The MIME types supported by {@link #onReceiveContent} for this view. The returned
+ * MIME types may contain wildcards such as "text/*", "image/*", etc.
+ */
+ public @Nullable String[] getOnReceiveContentMimeTypes() {
+ return mOnReceiveContentMimeTypes;
+ }
+
+ /**
* Automatically fills the content of this view with the {@code value}.
*
* <p>Views support the Autofill Framework mainly by:
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index e0711132f459..093dfb4e196e 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -22,6 +22,7 @@ import android.annotation.CallSuper;
import android.annotation.IntRange;
import android.annotation.Nullable;
import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -918,23 +919,18 @@ public class BaseInputConnection implements InputConnection {
}
/**
- * Default implementation which invokes the target view's {@link OnReceiveContentCallback} if
- * it is {@link View#setOnReceiveContentCallback set} and supports the MIME type of the given
- * content; otherwise, simply returns false.
+ * Default implementation which invokes {@link View#onReceiveContent} on the target view if the
+ * MIME type of the content matches one of the MIME types returned by
+ * {@link View#getOnReceiveContentMimeTypes()}. If the MIME type of the content is not matched,
+ * returns false without any side effects.
*/
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
- @SuppressWarnings("unchecked") final OnReceiveContentCallback<View> receiver =
- (OnReceiveContentCallback<View>) mTargetView.getOnReceiveContentCallback();
- if (receiver == null) {
+ ClipDescription description = inputContentInfo.getDescription();
+ final String[] viewMimeTypes = mTargetView.getOnReceiveContentMimeTypes();
+ if (viewMimeTypes == null || !description.hasMimeType(viewMimeTypes)) {
if (DEBUG) {
- Log.d(TAG, "Can't insert content from IME; no callback");
- }
- return false;
- }
- if (!receiver.supports(mTargetView, inputContentInfo.getDescription())) {
- if (DEBUG) {
- Log.d(TAG, "Can't insert content from IME; callback doesn't support MIME type: "
- + inputContentInfo.getDescription());
+ Log.d(TAG, "Can't insert content from IME; unsupported MIME type: content="
+ + description + ", viewMimeTypes=" + viewMimeTypes);
}
return false;
}
@@ -946,13 +942,13 @@ public class BaseInputConnection implements InputConnection {
return false;
}
}
- final ClipData clip = new ClipData(inputContentInfo.getDescription(),
+ final ClipData clip = new ClipData(description,
new ClipData.Item(inputContentInfo.getContentUri()));
final OnReceiveContentCallback.Payload payload =
new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD)
.setLinkUri(inputContentInfo.getLinkUri())
.setExtras(opts)
.build();
- return receiver.onReceiveContent(mTargetView, payload);
+ return mTargetView.onReceiveContent(payload);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3fc0f4efd608..5280a48596b4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8747,12 +8747,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.initialSelEnd = getSelectionEnd();
outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
outAttrs.setInitialSurroundingText(mText);
- // If a custom `OnReceiveContentCallback` is set, pass its supported MIME types.
- OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
- if (receiver != null) {
- outAttrs.contentMimeTypes = receiver.getSupportedMimeTypes(this)
- .toArray(new String[0]);
- }
+ outAttrs.contentMimeTypes = getOnReceiveContentMimeTypes();
return ic;
}
}
@@ -13735,20 +13730,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Returns the callback used for handling insertion of content into this view. See
- * {@link #setOnReceiveContentCallback} for more info.
- *
- * @return The callback for handling insertion of content. Returns null if no callback has been
- * {@link #setOnReceiveContentCallback set}.
- */
- @SuppressWarnings("unchecked")
- @Nullable
- @Override
- public OnReceiveContentCallback<TextView> getOnReceiveContentCallback() {
- return (OnReceiveContentCallback<TextView>) super.getOnReceiveContentCallback();
- }
-
- /**
* Sets the callback to handle insertion of content into this view.
*
* <p>This callback will be invoked for the following scenarios:
@@ -13761,32 +13742,51 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* <li>{@link Intent#ACTION_PROCESS_TEXT} replacement
* </ol>
*
- * <p>The callback will only be invoked if the MIME type of the content is
- * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
- * If the content type is not supported by the callback, the default platform handling will be
- * executed instead.
+ * <p>This callback is only invoked for content whose MIME type matches a type specified via
+ * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the
+ * default platform handling will be executed instead (no-op for the default {@link View}).
+ *
+ * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
+ * MIME types. As a result, you should always write your MIME types with lower case letters, or
+ * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
+ * case.</em>
*
+ * @param mimeTypes The type of content for which the callback should be invoked. This may use
+ * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null
+ * callback is passed in.
* @param callback The callback to use. This can be null to reset to the default behavior.
*/
+ @SuppressWarnings("rawtypes")
@Override
public void setOnReceiveContentCallback(
- @Nullable OnReceiveContentCallback<? extends View> callback) {
- super.setOnReceiveContentCallback(callback);
+ @Nullable String[] mimeTypes,
+ @Nullable OnReceiveContentCallback callback) {
+ super.setOnReceiveContentCallback(mimeTypes, callback);
}
/**
- * Handles the request to insert content using the configured callback or the default callback.
+ * Receives the given content. The default implementation invokes the callback set via
+ * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not
+ * support the given content (based on the MIME type), executes the default platform handling
+ * (e.g. coerces content to text if the source is
+ * {@link OnReceiveContentCallback.Payload#SOURCE_CLIPBOARD} and this is an editable
+ * {@link TextView}).
*
- * @hide
+ * @param payload The content to insert and related metadata.
+ *
+ * @return Returns true if the content was handled in some way, false otherwise. Actual
+ * insertion may be processed asynchronously in the background and may or may not succeed even
+ * if this method returns true. For example, an app may not end up inserting an item if it
+ * exceeds the app's size limit for that type of content.
*/
- void onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
- OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
- ClipDescription description = payload.getClip().getDescription();
- if (receiver != null && receiver.supports(this, description)) {
- receiver.onReceiveContent(this, payload);
+ @Override
+ public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
+ if (super.onReceiveContent(payload)) {
+ return true;
} else if (mEditor != null) {
- mEditor.getDefaultOnReceiveContentCallback().onReceiveContent(this, payload);
+ return mEditor.getDefaultOnReceiveContentCallback().onReceiveContent(this, payload);
}
+ return false;
}
private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
diff --git a/core/java/android/widget/TextViewOnReceiveContentCallback.java b/core/java/android/widget/TextViewOnReceiveContentCallback.java
index d7c95b7eae86..7ed70ec18a7b 100644
--- a/core/java/android/widget/TextViewOnReceiveContentCallback.java
+++ b/core/java/android/widget/TextViewOnReceiveContentCallback.java
@@ -20,12 +20,12 @@ import static android.content.ContentResolver.SCHEME_CONTENT;
import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
import static java.util.Collections.singleton;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
@@ -72,16 +72,6 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
@Nullable private InputConnectionInfo mInputConnectionInfo;
@Nullable private ArraySet<String> mCachedSupportedMimeTypes;
- @SuppressLint("CallbackMethodName")
- @NonNull
- @Override
- public Set<String> getSupportedMimeTypes(@NonNull TextView view) {
- if (!isUsageOfImeCommitContentEnabled(view)) {
- return MIME_TYPES_ALL_TEXT;
- }
- return getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes();
- }
-
@Override
public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
@@ -90,6 +80,11 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
ClipData clip = payload.getClip();
@Source int source = payload.getSource();
@Flags int flags = payload.getFlags();
+ if (source == SOURCE_INPUT_METHOD) {
+ // InputConnection.commitContent() should only be used for non-text input which is not
+ // supported by the default implementation.
+ return false;
+ }
if (source == SOURCE_AUTOFILL) {
return onReceiveForAutofill(view, clip, flags);
}
@@ -123,7 +118,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
}
}
}
- return true;
+ return didFirst;
}
private static void replaceSelection(@NonNull Editable editable,
@@ -160,7 +155,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
@NonNull ClipData clip, @Flags int flags) {
final CharSequence text = coerceToText(clip, textView.getContext(), flags);
if (text.length() == 0) {
- return true;
+ return false;
}
replaceSelection((Editable) textView.getText(), text);
return true;
@@ -205,7 +200,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
* non-text content.
*/
private static boolean isUsageOfImeCommitContentEnabled(@NonNull View view) {
- if (view.getOnReceiveContentCallback() != null) {
+ if (view.getOnReceiveContentMimeTypes() != null) {
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
Log.v(LOG_TAG, "Fallback to commitContent disabled (custom callback is set)");
}
@@ -267,6 +262,17 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
mInputConnectionInfo = null;
}
+ // TODO(b/168253885): Use this to populate the assist structure for Autofill
+
+ /** @hide */
+ @VisibleForTesting
+ public Set<String> getMimeTypes(TextView view) {
+ if (!isUsageOfImeCommitContentEnabled(view)) {
+ return MIME_TYPES_ALL_TEXT;
+ }
+ return getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes();
+ }
+
private Set<String> getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes() {
InputConnectionInfo icInfo = mInputConnectionInfo;
if (icInfo == null) {
@@ -291,7 +297,8 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
}
/**
- * We want to avoid creating a new set on every invocation of {@link #getSupportedMimeTypes}.
+ * We want to avoid creating a new set on every invocation of
+ * {@link #getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes()}.
* This method will check if the cached set of MIME types matches the data in the given array
* from {@link EditorInfo} or if a new set should be created. The custom logic is needed for
* comparing the data because the set contains the additional "text/*" MIME type.
diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java
index 5112326ea0b6..ef659af6c570 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java
@@ -66,8 +66,8 @@ import org.mockito.Mockito;
* {@link android.widget.cts.TextViewOnReceiveContentCallbackTest}. This class tests some internal
* implementation details, e.g. fallback to the keyboard image API.
*/
-@RunWith(AndroidJUnit4.class)
@MediumTest
+@RunWith(AndroidJUnit4.class)
public class TextViewOnReceiveContentCallbackTest {
private static final Uri SAMPLE_CONTENT_URI = Uri.parse("content://com.example/path");
@@ -101,7 +101,7 @@ public class TextViewOnReceiveContentCallbackTest {
// Assert that the callback returns the MIME types declared in the EditorInfo in addition to
// the default.
- assertThat(mDefaultCallback.getSupportedMimeTypes(mEditText)).containsExactly(
+ assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly(
"text/*", "image/gif", "image/png");
}
@@ -118,7 +118,7 @@ public class TextViewOnReceiveContentCallbackTest {
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
// Assert that the callback returns the default MIME types.
- assertThat(mDefaultCallback.getSupportedMimeTypes(mEditText)).containsExactly("text/*");
+ assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly("text/*");
}
@Test
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 8adedf5779d1..262e836d20e0 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -51897,7 +51897,6 @@ package android.view {
}
public interface OnReceiveContentCallback<T extends android.view.View> {
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
}
@@ -52475,7 +52474,7 @@ package android.view {
method @IdRes public int getNextFocusRightId();
method @IdRes public int getNextFocusUpId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
- method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
+ method @Nullable public String[] getOnReceiveContentMimeTypes();
method @ColorInt public int getOutlineAmbientShadowColor();
method public android.view.ViewOutlineProvider getOutlineProvider();
method @ColorInt public int getOutlineSpotShadowColor();
@@ -52670,6 +52669,7 @@ package android.view {
method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
+ method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
method public void onRtlPropertiesChanged(int);
@@ -52827,7 +52827,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
- method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
+ method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -59657,7 +59657,6 @@ package android.widget {
method public int getMinWidth();
method public final android.text.method.MovementMethod getMovementMethod();
method public int getOffsetForPosition(float, float);
- method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
method public android.text.TextPaint getPaint();
method public int getPaintFlags();
method public String getPrivateImeOptions();
@@ -59846,7 +59845,6 @@ package android.widget {
public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
ctor public TextViewOnReceiveContentCallback();
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index c84589a9e142..4552026ced4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,9 +73,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.Set;
import java.util.function.Consumer;
/**
@@ -315,7 +313,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mRemoteInputs = remoteInputs;
mRemoteInput = remoteInput;
mEditText.setHint(mRemoteInput.getLabel());
- mEditText.mSupportedMimeTypes = remoteInput.getAllowedDataTypes();
+ mEditText.mSupportedMimeTypes = (remoteInput.getAllowedDataTypes() == null) ? null
+ : remoteInput.getAllowedDataTypes().toArray(new String[0]);
mEntry.editedSuggestionInfo = editedSuggestionInfo;
if (editedSuggestionInfo != null) {
@@ -574,7 +573,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
boolean mShowImeOnInputConnection;
private LightBarController mLightBarController;
UserHandle mUser;
- private Set<String> mSupportedMimeTypes;
+ private String[] mSupportedMimeTypes;
public RemoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -585,35 +584,31 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- setOnReceiveContentCallback(new OnReceiveContentCallback<View>() {
- @Override
- public boolean onReceiveContent(@NonNull View view, @NonNull Payload payload) {
- ClipData clip = payload.getClip();
- if (clip.getItemCount() == 0) {
- return false;
- }
- Uri contentUri = clip.getItemAt(0).getUri();
- ClipDescription description = clip.getDescription();
- String mimeType = null;
- if (description.getMimeTypeCount() > 0) {
- mimeType = description.getMimeType(0);
- }
- if (mimeType != null) {
- Intent dataIntent = mRemoteInputView
- .prepareRemoteInputFromData(mimeType, contentUri);
- mRemoteInputView.sendRemoteInput(dataIntent);
- }
- return true;
- }
-
- @NonNull
- @Override
- public Set<String> getSupportedMimeTypes(@NonNull View view) {
- return mSupportedMimeTypes != null
- ? mSupportedMimeTypes
- : Collections.emptySet();
- }
- });
+ if (mSupportedMimeTypes != null && mSupportedMimeTypes.length > 0) {
+ setOnReceiveContentCallback(mSupportedMimeTypes,
+ new OnReceiveContentCallback<View>() {
+ @Override
+ public boolean onReceiveContent(@NonNull View view,
+ @NonNull Payload payload) {
+ ClipData clip = payload.getClip();
+ if (clip.getItemCount() == 0) {
+ return false;
+ }
+ Uri contentUri = clip.getItemAt(0).getUri();
+ ClipDescription description = clip.getDescription();
+ String mimeType = null;
+ if (description.getMimeTypeCount() > 0) {
+ mimeType = description.getMimeType(0);
+ }
+ if (mimeType != null) {
+ Intent dataIntent = mRemoteInputView
+ .prepareRemoteInputFromData(mimeType, contentUri);
+ mRemoteInputView.sendRemoteInput(dataIntent);
+ }
+ return true;
+ }
+ });
+ }
}
private void defocusIfNeeded(boolean animate) {