All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.view.ContentInfo Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2020 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;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.ClipData;
import android.content.ClipDescription;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import android.view.inputmethod.InputContentInfo;

import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * Holds all the relevant data for a request to {@link View#performReceiveContent}.
 */
public final class ContentInfo implements Parcelable {

    /**
     * Specifies the UI through which content is being inserted. Future versions of Android may
     * support additional values.
     *
     * @hide
     */
    @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
            SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Source {}

    /**
     * Specifies that the operation was triggered by the app that contains the target view.
     */
    public static final int SOURCE_APP = 0;

    /**
     * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
     * "Paste as plain text" action in the insertion/selection menu).
     */
    public static final int SOURCE_CLIPBOARD = 1;

    /**
     * Specifies that the operation was triggered from the soft keyboard (also known as input
     * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
     * for more info.
     */
    public static final int SOURCE_INPUT_METHOD = 2;

    /**
     * Specifies that the operation was triggered by the drag/drop framework. See
     * https://developer.android.com/guide/topics/ui/drag-drop for more info.
     */
    public static final int SOURCE_DRAG_AND_DROP = 3;

    /**
     * Specifies that the operation was triggered by the autofill framework. See
     * https://developer.android.com/guide/topics/text/autofill for more info.
     */
    public static final int SOURCE_AUTOFILL = 4;

    /**
     * Specifies that the operation was triggered by a result from a
     * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
     * menu.
     */
    public static final int SOURCE_PROCESS_TEXT = 5;

    /**
     * Returns the symbolic name of the given source.
     *
     * @hide
     */
    static String sourceToString(@Source int source) {
        switch (source) {
            case SOURCE_APP: return "SOURCE_APP";
            case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
            case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
            case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
            case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
            case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
        }
        return String.valueOf(source);
    }

    /**
     * Flags to configure the insertion behavior.
     *
     * @hide
     */
    @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Flags {}

    /**
     * Flag requesting that the content should be converted to plain text prior to inserting.
     */
    public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;

    /**
     * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
     *
     * @hide
     */
    static String flagsToString(@Flags int flags) {
        if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
            return "FLAG_CONVERT_TO_PLAIN_TEXT";
        }
        return String.valueOf(flags);
    }

    @NonNull
    private final ClipData mClip;
    @Source
    private final int mSource;
    @Flags
    private final int mFlags;
    @Nullable
    private final Uri mLinkUri;
    @Nullable
    private final Bundle mExtras;
    @Nullable
    private final InputContentInfo mInputContentInfo;
    @Nullable
    private final DragAndDropPermissions mDragAndDropPermissions;

    private ContentInfo(Builder b) {
        this.mClip = Objects.requireNonNull(b.mClip);
        this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
                "source");
        this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
        this.mLinkUri = b.mLinkUri;
        this.mExtras = b.mExtras;
        this.mInputContentInfo = b.mInputContentInfo;
        this.mDragAndDropPermissions = b.mDragAndDropPermissions;
    }

    /**
     * If the content came from a source that supports proactive release of URI permissions
     * (e.g. IME), releases permissions; otherwise a no-op.
     *
     * @hide
     */
    @TestApi
    public void releasePermissions() {
        if (mInputContentInfo != null) {
            mInputContentInfo.releasePermission();
        }
        if (mDragAndDropPermissions != null) {
            mDragAndDropPermissions.release();
        }
    }

    @NonNull
    @Override
    public String toString() {
        return "ContentInfo{"
                + "clip=" + mClip
                + ", source=" + sourceToString(mSource)
                + ", flags=" + flagsToString(mFlags)
                + ", linkUri=" + mLinkUri
                + ", extras=" + mExtras
                + "}";
    }

    /**
     * The data to be inserted.
     */
    @NonNull
    public ClipData getClip() {
        return mClip;
    }

    /**
     * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
     * may pass additional values.
     */
    @Source
    public int getSource() {
        return mSource;
    }

    /**
     * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
     */
    @Flags
    public int getFlags() {
        return mFlags;
    }

    /**
     * Optional http/https URI for the content that may be provided by the IME. This is only
     * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
     * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
     * IME.
     */
    @Nullable
    public Uri getLinkUri() {
        return mLinkUri;
    }

    /**
     * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
     * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
     * the IME.
     */
    @Nullable
    @SuppressLint("NullableCollection")
    public Bundle getExtras() {
        return mExtras;
    }

    /**
     * Partitions this content based on the given predicate.
     *
     * 

This function classifies the content and organizes it into a pair, grouping the items * that matched vs didn't match the predicate. * *

Except for the {@link ClipData} items, the returned objects will contain all the same * metadata as this {@link ContentInfo}. * * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which * partition to place it into. * @return A pair containing the partitioned content. The pair's first object will have the * content that matched the predicate, or null if none of the items matched. The pair's * second object will have the content that didn't match the predicate, or null if all of * the items matched. * * @hide */ @TestApi @NonNull public Pair partition( @NonNull Predicate itemPredicate) { if (mClip.getItemCount() == 1) { boolean matched = itemPredicate.test(mClip.getItemAt(0)); return Pair.create(matched ? this : null, matched ? null : this); } ArrayList acceptedItems = new ArrayList<>(); ArrayList remainingItems = new ArrayList<>(); for (int i = 0; i < mClip.getItemCount(); i++) { ClipData.Item item = mClip.getItemAt(i); if (itemPredicate.test(item)) { acceptedItems.add(item); } else { remainingItems.add(item); } } if (acceptedItems.isEmpty()) { return Pair.create(null, this); } if (remainingItems.isEmpty()) { return Pair.create(this, null); } ContentInfo accepted = new Builder(this) .setClip(new ClipData(new ClipDescription(mClip.getDescription()), acceptedItems)) .build(); ContentInfo remaining = new Builder(this) .setClip(new ClipData(new ClipDescription(mClip.getDescription()), remainingItems)) .build(); return Pair.create(accepted, remaining); } /** * Builder for {@link ContentInfo}. */ public static final class Builder { @NonNull private ClipData mClip; @Source private int mSource; @Flags private int mFlags; @Nullable private Uri mLinkUri; @Nullable private Bundle mExtras; @Nullable private InputContentInfo mInputContentInfo; @Nullable private DragAndDropPermissions mDragAndDropPermissions; /** * Creates a new builder initialized with the data from the given builder. */ public Builder(@NonNull ContentInfo other) { mClip = other.mClip; mSource = other.mSource; mFlags = other.mFlags; mLinkUri = other.mLinkUri; mExtras = other.mExtras; mInputContentInfo = other.mInputContentInfo; mDragAndDropPermissions = other.mDragAndDropPermissions; } /** * Creates a new builder. * @param clip The data to insert. * @param source The source of the operation. See {@code SOURCE_} constants. */ public Builder(@NonNull ClipData clip, @Source int source) { mClip = clip; mSource = source; } /** * Sets the data to be inserted. * @param clip The data to insert. * @return this builder */ @NonNull public Builder setClip(@NonNull ClipData clip) { mClip = clip; return this; } /** * Sets the source of the operation. * @param source The source of the operation. See {@code SOURCE_} constants. * @return this builder */ @NonNull public Builder setSource(@Source int source) { mSource = source; return this; } /** * Sets flags that control content insertion behavior. * @param flags Optional flags to configure the insertion behavior. Use 0 for default * behavior. See {@code FLAG_} constants. * @return this builder */ @NonNull public Builder setFlags(@Flags int flags) { mFlags = flags; return this; } /** * Sets the http/https URI for the content. See * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info. * @param linkUri Optional http/https URI for the content. * @return this builder */ @NonNull public Builder setLinkUri(@Nullable Uri linkUri) { mLinkUri = linkUri; return this; } /** * Sets additional metadata. * @param extras Optional bundle with additional metadata. * @return this builder */ @NonNull public Builder setExtras(@SuppressLint("NullableCollection") @Nullable Bundle extras) { mExtras = extras; return this; } /** * Set the {@link InputContentInfo} object if the content is coming from the IME. This can * be used for proactive cleanup of permissions. * * @hide */ @TestApi @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setInputContentInfo(@Nullable InputContentInfo inputContentInfo) { mInputContentInfo = inputContentInfo; return this; } /** * Set the {@link DragAndDropPermissions} object if the content is coming via drag-and-drop. * This can be used for proactive cleanup of permissions. * * @hide */ @TestApi @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setDragAndDropPermissions(@Nullable DragAndDropPermissions permissions) { mDragAndDropPermissions = permissions; return this; } /** * @return A new {@link ContentInfo} instance with the data from this builder. */ @NonNull public ContentInfo build() { return new ContentInfo(this); } } /** * {@inheritDoc} */ @Override public int describeContents() { return 0; } /** * Writes this object into the given parcel. * * @param dest The parcel to write into. * @param flags The flags to use for parceling. */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { mClip.writeToParcel(dest, flags); dest.writeInt(mSource); dest.writeInt(mFlags); Uri.writeToParcel(dest, mLinkUri); dest.writeBundle(mExtras); if (mInputContentInfo == null) { dest.writeInt(0); } else { dest.writeInt(1); mInputContentInfo.writeToParcel(dest, flags); } if (mDragAndDropPermissions == null) { dest.writeInt(0); } else { dest.writeInt(1); mDragAndDropPermissions.writeToParcel(dest, flags); } } /** * Creates {@link ContentInfo} instances from parcels. */ @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public ContentInfo createFromParcel(Parcel parcel) { ClipData clip = ClipData.CREATOR.createFromParcel(parcel); int source = parcel.readInt(); int flags = parcel.readInt(); Uri linkUri = Uri.CREATOR.createFromParcel(parcel); Bundle extras = parcel.readBundle(); InputContentInfo inputContentInfo = null; if (parcel.readInt() != 0) { inputContentInfo = InputContentInfo.CREATOR.createFromParcel(parcel); } DragAndDropPermissions dragAndDropPermissions = null; if (parcel.readInt() != 0) { dragAndDropPermissions = DragAndDropPermissions.CREATOR.createFromParcel(parcel); } return new ContentInfo.Builder(clip, source) .setFlags(flags) .setLinkUri(linkUri) .setExtras(extras) .setInputContentInfo(inputContentInfo) .setDragAndDropPermissions(dragAndDropPermissions) .build(); } @Override public ContentInfo[] newArray(int size) { return new ContentInfo[size]; } }; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy