Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af270ce4 authored by Winson Chung's avatar Winson Chung
Browse files

Update unhandled drag apis based on api council feedback

- Move to IntentSender instead of PendingIntent in ClipData and rename
  flags to match
- Update docs to clarify when the system will cancel the IntentSender

Bug: 325352291
Bug: 320797628
Test: atest DragDropTest DragDropControllerTests CrossAppDragAndDropTests
Change-Id: I30a470d06e296feb3d7f134c2f41e21d664ea137
parent 8d2accbc
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -10088,7 +10088,7 @@ package android.content {
    method public CharSequence coerceToText(android.content.Context);
    method public String getHtmlText();
    method public android.content.Intent getIntent();
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @Nullable public android.app.PendingIntent getPendingIntent();
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @Nullable public android.content.IntentSender getIntentSender();
    method public CharSequence getText();
    method @Nullable public android.view.textclassifier.TextLinks getTextLinks();
    method public android.net.Uri getUri();
@@ -10099,7 +10099,7 @@ package android.content {
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item build();
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setHtmlText(@Nullable String);
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setIntent(@Nullable android.content.Intent);
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setPendingIntent(@Nullable android.app.PendingIntent);
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setIntentSender(@Nullable android.content.IntentSender);
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setText(@Nullable CharSequence);
    method @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") @NonNull public android.content.ClipData.Item.Builder setUri(@Nullable android.net.Uri);
  }
@@ -53136,7 +53136,7 @@ package android.view {
    field public static final int DRAG_FLAG_GLOBAL_URI_READ = 1; // 0x1
    field public static final int DRAG_FLAG_GLOBAL_URI_WRITE = 2; // 0x2
    field public static final int DRAG_FLAG_OPAQUE = 512; // 0x200
    field @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") public static final int DRAG_FLAG_START_PENDING_INTENT_ON_UNHANDLED_DRAG = 8192; // 0x2000
    field @FlaggedApi("com.android.window.flags.delegate_unhandled_drags") public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 8192; // 0x2000
    field @Deprecated public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
    field @Deprecated public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
    field @Deprecated public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
+22 −52
Original line number Diff line number Diff line
@@ -26,8 +26,6 @@ import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.res.AssetFileDescriptor;
@@ -213,7 +211,7 @@ public class ClipData implements Parcelable {
        final CharSequence mText;
        final String mHtmlText;
        final Intent mIntent;
        final PendingIntent mPendingIntent;
        final IntentSender mIntentSender;
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        Uri mUri;
        private TextLinks mTextLinks;
@@ -225,12 +223,11 @@ public class ClipData implements Parcelable {
         * A builder for a ClipData Item.
         */
        @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
        @SuppressLint("PackageLayering")
        public static final class Builder {
            private CharSequence mText;
            private String mHtmlText;
            private Intent mIntent;
            private PendingIntent mPendingIntent;
            private IntentSender mIntentSender;
            private Uri mUri;

            /**
@@ -264,18 +261,20 @@ public class ClipData implements Parcelable {
            }

            /**
             * Sets the PendingIntent for the item to be constructed. To prevent receiving apps from
             * improperly manipulating the intent to launch another activity as this caller, the
             * provided PendingIntent must be immutable (see {@link PendingIntent#FLAG_IMMUTABLE}).
             * The system will clean up the PendingIntent when it is no longer used.
             * Sets the {@link IntentSender} for the item to be constructed. To prevent receiving
             * apps from improperly manipulating the intent to launch another activity as this
             * caller, the provided IntentSender must be immutable.
             *
             * If there is a fixed lifetime for this ClipData (ie. for drag and drop), the system
             * will cancel the IntentSender when it is no longer used.
             */
            @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
            @NonNull
            public Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
                if (pendingIntent != null && !pendingIntent.isImmutable()) {
                    throw new IllegalArgumentException("Expected pending intent to be immutable");
            public Builder setIntentSender(@Nullable IntentSender intentSender) {
                if (intentSender != null && !intentSender.isImmutable()) {
                    throw new IllegalArgumentException("Expected intent sender to be immutable");
                }
                mPendingIntent = pendingIntent;
                mIntentSender = intentSender;
                return this;
            }

@@ -295,7 +294,7 @@ public class ClipData implements Parcelable {
            @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
            @NonNull
            public Item build() {
                return new Item(mText, mHtmlText, mIntent, mPendingIntent, mUri);
                return new Item(mText, mHtmlText, mIntent, mIntentSender, mUri);
            }
        }

@@ -305,7 +304,7 @@ public class ClipData implements Parcelable {
            mText = other.mText;
            mHtmlText = other.mHtmlText;
            mIntent = other.mIntent;
            mPendingIntent = other.mPendingIntent;
            mIntentSender = other.mIntentSender;
            mUri = other.mUri;
            mActivityInfo = other.mActivityInfo;
            mTextLinks = other.mTextLinks;
@@ -366,7 +365,7 @@ public class ClipData implements Parcelable {
        /**
         * Builder ctor.
         */
        private Item(CharSequence text, String htmlText, Intent intent, PendingIntent pendingIntent,
        private Item(CharSequence text, String htmlText, Intent intent, IntentSender intentSender,
                Uri uri) {
            if (htmlText != null && text == null) {
                throw new IllegalArgumentException(
@@ -375,7 +374,7 @@ public class ClipData implements Parcelable {
            mText = text;
            mHtmlText = htmlText;
            mIntent = intent;
            mPendingIntent = pendingIntent;
            mIntentSender = intentSender;
            mUri = uri;
        }

@@ -401,12 +400,12 @@ public class ClipData implements Parcelable {
        }

        /**
         * Returns the pending intent in this Item.
         * Returns the {@link IntentSender} in this Item.
         */
        @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
        @Nullable
        public PendingIntent getPendingIntent() {
            return mPendingIntent;
        public IntentSender getIntentSender() {
            return mIntentSender;
        }

        /**
@@ -1130,35 +1129,6 @@ public class ClipData implements Parcelable {
        prepareToLeaveProcess(leavingPackage, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }

    /**
     * Checks if this clip data has a pending intent that is an activity type.
     * @hide
     */
    public boolean hasActivityPendingIntents() {
        final int size = mItems.size();
        for (int i = 0; i < size; i++) {
            final Item item = mItems.get(i);
            if (item.mPendingIntent != null && item.mPendingIntent.isActivity()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Cleans up all pending intents in the ClipData.
     * @hide
     */
    public void cleanUpPendingIntents() {
        final int size = mItems.size();
        for (int i = 0; i < size; i++) {
            final Item item = mItems.get(i);
            if (item.mPendingIntent != null) {
                item.mPendingIntent.cancel();
            }
        }
    }

    /**
     * Prepare this {@link ClipData} to leave an app process.
     *
@@ -1361,7 +1331,7 @@ public class ClipData implements Parcelable {
            TextUtils.writeToParcel(item.mText, dest, flags);
            dest.writeString8(item.mHtmlText);
            dest.writeTypedObject(item.mIntent, flags);
            dest.writeTypedObject(item.mPendingIntent, flags);
            dest.writeTypedObject(item.mIntentSender, flags);
            dest.writeTypedObject(item.mUri, flags);
            dest.writeTypedObject(mParcelItemActivityInfos ? item.mActivityInfo : null, flags);
            dest.writeTypedObject(item.mTextLinks, flags);
@@ -1381,11 +1351,11 @@ public class ClipData implements Parcelable {
            CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
            String htmlText = in.readString8();
            Intent intent = in.readTypedObject(Intent.CREATOR);
            PendingIntent pendingIntent = in.readTypedObject(PendingIntent.CREATOR);
            IntentSender intentSender = in.readTypedObject(IntentSender.CREATOR);
            Uri uri = in.readTypedObject(Uri.CREATOR);
            ActivityInfo info = in.readTypedObject(ActivityInfo.CREATOR);
            TextLinks textLinks = in.readTypedObject(TextLinks.CREATOR);
            Item item = new Item(text, htmlText, intent, pendingIntent, uri);
            Item item = new Item(text, htmlText, intent, intentSender, uri);
            item.setActivityInfo(info);
            item.setTextLinks(textLinks);
            mItems.add(item);
+41 −7
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ import android.content.ClipDescription;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentSender;
import android.content.res.ColorStateList;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -5357,16 +5358,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    /**
     * Flag indicating that an unhandled drag should be delegated to the system to be started if no
     * visible window wishes to handle the drop. When using this flag, the caller must provide
     * ClipData with an Item that contains an immutable PendingIntent to an activity to be launched
     * ClipData with an Item that contains an immutable IntentSender to an activity to be launched
     * (not a broadcast, service, etc).  See
     * {@link ClipData.Item.Builder#setPendingIntent(PendingIntent)}.
     * {@link ClipData.Item.Builder#setIntentSender(IntentSender)}.
     *
     * The system can decide to launch the intent or not based on factors like the current screen
     * size or windowing mode. If the system does not launch the intent, it will be canceled via the
     * normal drag and drop flow.
     */
    @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
    public static final int DRAG_FLAG_START_PENDING_INTENT_ON_UNHANDLED_DRAG = 1 << 13;
    public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13;
    /**
     * Vertical scroll factor cached by {@link #getVerticalScrollFactor}.
@@ -28665,10 +28666,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            if (com.android.window.flags.Flags.delegateUnhandledDrags()) {
                data.prepareToLeaveProcess(
                        (flags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) != 0);
                if ((flags & DRAG_FLAG_START_PENDING_INTENT_ON_UNHANDLED_DRAG) != 0) {
                    if (!data.hasActivityPendingIntents()) {
                if ((flags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0) {
                    if (!hasActivityPendingIntents(data)) {
                        // Reset the flag if there is no launchable activity intent
                        flags &= ~DRAG_FLAG_START_PENDING_INTENT_ON_UNHANDLED_DRAG;
                        flags &= ~DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
                        Log.w(VIEW_LOG_TAG, "startDragAndDrop called with "
                                + "DRAG_FLAG_START_INTENT_ON_UNHANDLED_DRAG but the clip data "
                                + "contains non-activity PendingIntents");
@@ -28781,7 +28782,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    mAttachInfo.mDragSurface.release();
                }
                if (mAttachInfo.mDragData != null) {
                    mAttachInfo.mDragData.cleanUpPendingIntents();
                    View.cleanUpPendingIntents(mAttachInfo.mDragData);
                }
                mAttachInfo.mDragSurface = surface;
                mAttachInfo.mDragToken = token;
@@ -28806,6 +28807,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
    }
     /**
     * Checks if this clip data has a pending intent that is an activity type.
     * @hide
     */
    static boolean hasActivityPendingIntents(ClipData data) {
        final int size = data.getItemCount();
        for (int i = 0; i < size; i++) {
            final ClipData.Item item = data.getItemAt(i);
            if (item.getIntentSender() != null) {
                final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget());
                if (pi.isActivity()) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * Cleans up all pending intents in the ClipData.
     * @hide
     */
    static void cleanUpPendingIntents(ClipData data) {
        final int size = data.getItemCount();
        for (int i = 0; i < size; i++) {
            final ClipData.Item item = data.getItemAt(i);
            if (item.getIntentSender() != null) {
                final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget());
                pi.cancel();
            }
        }
    }
    void setAccessibilityDragStarted(boolean started) {
        int pflags4 = mPrivateFlags4;
        if (started) {
+1 −1
Original line number Diff line number Diff line
@@ -8626,7 +8626,7 @@ public final class ViewRootImpl implements ViewParent,
                        mAttachInfo.mDragSurface = null;
                    }
                    if (mAttachInfo.mDragData != null) {
                        mAttachInfo.mDragData.cleanUpPendingIntents();
                        View.cleanUpPendingIntents(mAttachInfo.mDragData);
                        mAttachInfo.mDragData = null;
                    }
                }