File: ContentInfo.java

package info (click to toggle)
android-platform-frameworks-base 1%3A14~beta1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 326,084 kB
  • sloc: java: 2,032,373; xml: 343,016; cpp: 304,181; python: 3,683; ansic: 2,090; sh: 1,871; makefile: 120; sed: 19
file content (496 lines) | stat: -rw-r--r-- 16,315 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
/*
 * 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.
     *
     * <p>This function classifies the content and organizes it into a pair, grouping the items
     * that matched vs didn't match the predicate.
     *
     * <p>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<ContentInfo, ContentInfo> partition(
            @NonNull Predicate<ClipData.Item> itemPredicate) {
        if (mClip.getItemCount() == 1) {
            boolean matched = itemPredicate.test(mClip.getItemAt(0));
            return Pair.create(matched ? this : null, matched ? null : this);
        }
        ArrayList<ClipData.Item> acceptedItems = new ArrayList<>();
        ArrayList<ClipData.Item> 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<ContentInfo> CREATOR =
            new Parcelable.Creator<ContentInfo>() {
        @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];
        }
    };
}