15cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen/*
25cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Copyright (C) 2014 The Android Open Source Project
35cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
45cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Licensed under the Apache License, Version 2.0 (the "License");
55cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * you may not use this file except in compliance with the License.
65cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * You may obtain a copy of the License at
75cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
85cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *      http://www.apache.org/licenses/LICENSE-2.0
95cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
105cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Unless required by applicable law or agreed to in writing, software
115cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * distributed under the License is distributed on an "AS IS" BASIS,
125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * See the License for the specific language governing permissions and
145cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * limitations under the License.
155cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen */
165cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
175cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenpackage android.app;
185cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
198e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermakimport android.annotation.IntDef;
204b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yinimport android.annotation.NonNull;
214b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yinimport android.annotation.Nullable;
225cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.content.ClipData;
235cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.content.ClipDescription;
245cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.content.Intent;
25472a3b330a926c9d86a685dc0debf71037ea279bShane Brennanimport android.net.Uri;
265cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.os.Bundle;
275cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.os.Parcel;
285cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenimport android.os.Parcelable;
29472a3b330a926c9d86a685dc0debf71037ea279bShane Brennanimport android.util.ArraySet;
306cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
318e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermakimport java.lang.annotation.Retention;
328e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermakimport java.lang.annotation.RetentionPolicy;
33472a3b330a926c9d86a685dc0debf71037ea279bShane Brennanimport java.util.HashMap;
34472a3b330a926c9d86a685dc0debf71037ea279bShane Brennanimport java.util.Map;
35472a3b330a926c9d86a685dc0debf71037ea279bShane Brennanimport java.util.Set;
365cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
375cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen/**
385cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * A {@code RemoteInput} object specifies input to be collected from a user to be passed along with
395cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * an intent inside a {@link android.app.PendingIntent} that is sent.
405cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Always use {@link RemoteInput.Builder} to create instances of this class.
415cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * <p class="note"> See
42edc2f84df2f5be7747eaf029311061e45a3d04b8Cindy Kuang * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#direct">Replying
43edc2f84df2f5be7747eaf029311061e45a3d04b8Cindy Kuang * to notifications</a> for more information on how to use this class.
445cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
455cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * <p>The following example adds a {@code RemoteInput} to a {@link Notification.Action},
465cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * sets the result key as {@code quick_reply}, and sets the label as {@code Quick reply}.
475cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Users are prompted to input a response when they trigger the action. The results are sent along
485cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * with the intent and can be retrieved with the result key (provided to the {@link Builder}
495cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * constructor) from the Bundle returned by {@link #getResultsFromIntent}.
505cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
515cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * <pre class="prettyprint">
525cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
535cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Notification.Action action = new Notification.Action.Builder(
545cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *         R.drawable.reply, &quot;Reply&quot;, actionIntent)
555cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *         <b>.addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
565cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *                 .setLabel("Quick reply").build()</b>)
575cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *         .build();</pre>
585cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
595cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * <p>When the {@link android.app.PendingIntent} is fired, the intent inside will contain the
605cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * input results if collected. To access these results, use the {@link #getResultsFromIntent}
615cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * function. The result values will present under the result key passed to the {@link Builder}
625cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * constructor.
635cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *
645cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * <pre class="prettyprint">
655cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
665cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * Bundle results = RemoteInput.getResultsFromIntent(intent);
675cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * if (results != null) {
685cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen *     CharSequence quickReplyResult = results.getCharSequence(KEY_QUICK_REPLY_TEXT);
695cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen * }</pre>
705cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen */
715cadc3b00aa775a63518383046c902b130e09b4cGriff Hazenpublic final class RemoteInput implements Parcelable {
725cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /** Label used to denote the clip data type used for remote input transport */
735cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
745cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
75472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    /** Extra added to a clip data intent object to hold the text results bundle. */
765cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
775cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
78472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    /** Extra added to a clip data intent object to hold the data results bundle. */
79472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
80472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            "android.remoteinput.dataTypeResultsData";
81472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
828e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    /** Extra added to a clip data intent object identifying the {@link Source} of the results. */
836cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    private static final String EXTRA_RESULTS_SOURCE = "android.remoteinput.resultsSource";
846cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
858e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    /** @hide */
868e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_FREE_FORM_INPUT, SOURCE_CHOICE})
878e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    @Retention(RetentionPolicy.SOURCE)
888e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    public @interface Source {}
898e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak
906cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    /** The user manually entered the data. */
916cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    public static final int SOURCE_FREE_FORM_INPUT = 0;
926cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
936cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    /** The user selected one of the choices from {@link #getChoices}. */
946cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    public static final int SOURCE_CHOICE = 1;
956cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
96c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen    // Flags bitwise-ored to mFlags
97c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen    private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
98c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen
99c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen    // Default value for flags integer
100c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen    private static final int DEFAULT_FLAGS = FLAG_ALLOW_FREE_FORM_INPUT;
101c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen
1025cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private final String mResultKey;
1035cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private final CharSequence mLabel;
1045cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private final CharSequence[] mChoices;
105c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen    private final int mFlags;
1065cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private final Bundle mExtras;
107472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    private final ArraySet<String> mAllowedDataTypes;
1085cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1095cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
110472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            int flags, Bundle extras, ArraySet<String> allowedDataTypes) {
1115cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        this.mResultKey = resultKey;
1125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        this.mLabel = label;
1135cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        this.mChoices = choices;
114c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        this.mFlags = flags;
1155cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        this.mExtras = extras;
116472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        this.mAllowedDataTypes = allowedDataTypes;
1175cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1185cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1195cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1205cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Get the key that the result of this input will be set in from the Bundle returned by
1215cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * {@link #getResultsFromIntent} when the {@link android.app.PendingIntent} is sent.
1225cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1235cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public String getResultKey() {
1245cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        return mResultKey;
1255cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1265cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1275cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1285cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Get the label to display to users when collecting this input.
1295cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1305cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public CharSequence getLabel() {
1315cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        return mLabel;
1325cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1335cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1345cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1355cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Get possible input choices. This can be {@code null} if there are no choices to present.
1365cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1375cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public CharSequence[] getChoices() {
1385cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        return mChoices;
1395cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1405cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
141fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan    /**
142fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * Get possible non-textual inputs that are accepted.
143fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * This can be {@code null} if the input does not accept non-textual values.
144fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * See {@link Builder#setAllowDataType}.
145fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     */
146472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    public Set<String> getAllowedDataTypes() {
147472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return mAllowedDataTypes;
148472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
149472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
150472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    /**
151472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
152472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
153472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * non-null and not empty.
154472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     */
155472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    public boolean isDataOnly() {
156472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return !getAllowFreeFormInput()
157472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                && (getChoices() == null || getChoices().length == 0)
158472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                && !getAllowedDataTypes().isEmpty();
159472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
160472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
1615cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1625cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Get whether or not users can provide an arbitrary value for
1635cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * input. If you set this to {@code false}, users must select one of the
1645cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * choices in {@link #getChoices}. An {@link IllegalArgumentException} is thrown
1655cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * if you set this to false and {@link #getChoices} returns {@code null} or empty.
1665cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1675cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public boolean getAllowFreeFormInput() {
168c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        return (mFlags & FLAG_ALLOW_FREE_FORM_INPUT) != 0;
1695cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1705cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1715cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1725cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Get additional metadata carried around with this remote input.
1735cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1745cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public Bundle getExtras() {
1755cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        return mExtras;
1765cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
1775cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1785cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
1795cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * Builder class for {@link RemoteInput} objects.
1805cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
1815cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public static final class Builder {
1825cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        private final String mResultKey;
1834b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        private final ArraySet<String> mAllowedDataTypes = new ArraySet<>();
1844b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        private final Bundle mExtras = new Bundle();
1855cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        private CharSequence mLabel;
1865cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        private CharSequence[] mChoices;
187c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        private int mFlags = DEFAULT_FLAGS;
1885cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
1895cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
1905cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Create a builder object for {@link RemoteInput} objects.
1914b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *
1925cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @param resultKey the Bundle key that refers to this input when collected from the user
1935cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
1944b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        public Builder(@NonNull String resultKey) {
1955cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            if (resultKey == null) {
1965cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                throw new IllegalArgumentException("Result key can't be null");
1975cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            }
1985cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            mResultKey = resultKey;
1995cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
2005cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
2015cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
2025cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Set a label to be displayed to the user when collecting this input.
2034b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *
2044b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         * @param label The label to show to users when they input a response
2055cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @return this object for method chaining
2065cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
2074b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
2084b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        public Builder setLabel(@Nullable CharSequence label) {
2095cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            mLabel = Notification.safeCharSequence(label);
2105cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return this;
2115cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
2125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
2135cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
2145cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Specifies choices available to the user to satisfy this input.
2154b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *
2164b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         * <p>Note: Starting in Android P, these choices will always be shown on phones if the app's
2174b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         * target SDK is >= P. However, these choices may also be rendered on other types of devices
2184b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         * regardless of target SDK.
2194b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *
2205cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @param choices an array of pre-defined choices for users input.
2215cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         *        You must provide a non-null and non-empty array if
2224b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *        you disabled free form input using {@link #setAllowFreeFormInput}
2235cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @return this object for method chaining
2245cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
2254b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
2264b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        public Builder setChoices(@Nullable CharSequence[] choices) {
2275cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            if (choices == null) {
2285cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                mChoices = null;
2295cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            } else {
2305cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                mChoices = new CharSequence[choices.length];
2315cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                for (int i = 0; i < choices.length; i++) {
2325cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                    mChoices[i] = Notification.safeCharSequence(choices[i]);
2335cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                }
2345cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            }
2355cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return this;
2365cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
2375cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
2385cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
239fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan         * Specifies whether the user can provide arbitrary values. This allows an input
240fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan         * to accept non-textual values. Examples of usage are an input that wants audio
241fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan         * or an image.
2425cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         *
243472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         * @param mimeType A mime type that results are allowed to come in.
244472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *         Be aware that text results (see {@link #setAllowFreeFormInput}
245472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *         are allowed by default. If you do not want text results you will have to
2464b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *         pass false to {@code setAllowFreeFormInput}
2474b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         * @param doAllow Whether the mime type should be allowed or not
248472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         * @return this object for method chaining
249472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         */
2504b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
2514b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        public Builder setAllowDataType(@NonNull String mimeType, boolean doAllow) {
252472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            if (doAllow) {
253472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                mAllowedDataTypes.add(mimeType);
254472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            } else {
255472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                mAllowedDataTypes.remove(mimeType);
256472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            }
257472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return this;
258472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
259472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
260472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        /**
261472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         * Specifies whether the user can provide arbitrary text values.
262472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *
263472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         * @param allowFreeFormTextInput The default is {@code true}.
264472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *         If you specify {@code false}, you must either provide a non-null
265472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *         and non-empty array to {@link #setChoices}, or enable a data result
266472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan         *         in {@code setAllowDataType}. Otherwise an
2674b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin         *         {@link IllegalArgumentException} is thrown
2685cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @return this object for method chaining
2695cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
2704b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
271472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
272472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            setFlag(mFlags, allowFreeFormTextInput);
2735cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return this;
2745cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
2755cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
2765cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
2775cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Merge additional metadata into this builder.
2785cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         *
2795cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * <p>Values within the Bundle will replace existing extras values in this Builder.
2805cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         *
2815cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * @see RemoteInput#getExtras
2825cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
2834b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
2844b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        public Builder addExtras(@NonNull Bundle extras) {
2855cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            if (extras != null) {
2865cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                mExtras.putAll(extras);
2875cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            }
2885cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return this;
2895cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
2905cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
2915cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
2925cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Get the metadata Bundle used by this Builder.
2935cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         *
2945cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * <p>The returned Bundle is shared with this Builder.
2955cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
2964b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
2975cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        public Bundle getExtras() {
2985cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return mExtras;
2995cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
3005cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
301c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        private void setFlag(int mask, boolean value) {
302c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen            if (value) {
303c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen                mFlags |= mask;
304c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen            } else {
305c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen                mFlags &= ~mask;
306c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen            }
307c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        }
308c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen
3095cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        /**
3105cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * Combine all of the options that have been set and return a new {@link RemoteInput}
3115cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         * object.
3125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen         */
3134b3a54710792d24233b77bcd6cca120b9ffe0b32Kodlee Yin        @NonNull
3145cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        public RemoteInput build() {
315472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return new RemoteInput(
316472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                    mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes);
3175cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
3185cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
3195cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
3205cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    private RemoteInput(Parcel in) {
3215cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        mResultKey = in.readString();
3225cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        mLabel = in.readCharSequence();
3235cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        mChoices = in.readCharSequenceArray();
324c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        mFlags = in.readInt();
3255cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        mExtras = in.readBundle();
326472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null);
3275cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
3285cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
3295cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
330472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Similar as {@link #getResultsFromIntent} but retrieves data results for a
331472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * specific RemoteInput result. To retrieve a value use:
332472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * <pre>
333472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * {@code
334472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Map<String, Uri> results =
335472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     *     RemoteInput.getDataResultsFromIntent(intent, REMOTE_INPUT_KEY);
336472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * if (results != null) {
337472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     *   Uri data = results.get(MIME_TYPE_OF_INTEREST);
338472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * }
339472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * }
340472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * </pre>
3415cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * @param intent The intent object that fired in response to an action or content intent
3425cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     *               which also had one or more remote input requested.
343472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * @param remoteInputResultKey The result key for the RemoteInput you want results for.
3445cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
345472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    public static Map<String, Uri> getDataResultsFromIntent(
346472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            Intent intent, String remoteInputResultKey) {
347472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
348472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (clipDataIntent == null) {
3495cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return null;
3505cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
351472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Map<String, Uri> results = new HashMap<>();
352472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Bundle extras = clipDataIntent.getExtras();
353472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        for (String key : extras.keySet()) {
354472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan          if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
355472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
356472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              if (mimeType == null || mimeType.isEmpty()) {
357472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                  continue;
358472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              }
359472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              Bundle bundle = clipDataIntent.getBundleExtra(key);
360472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              String uriStr = bundle.getString(remoteInputResultKey);
361472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              if (uriStr == null || uriStr.isEmpty()) {
362472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                  continue;
363472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              }
364472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan              results.put(mimeType, Uri.parse(uriStr));
365472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan          }
3665cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
367472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return results.isEmpty() ? null : results;
368472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
369472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
370472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    /**
371472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Get the remote input text results bundle from an intent. The returned Bundle will
372472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * contain a key/value for every result key populated with text by remote input collector.
373472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. For non-text
374472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * results use {@link #getDataResultsFromIntent}.
375472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * @param intent The intent object that fired in response to an action or content intent
376472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     *               which also had one or more remote input requested.
377472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     */
378472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    public static Bundle getResultsFromIntent(Intent intent) {
379472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
380472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (clipDataIntent == null) {
381472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return null;
3825cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
383472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
3845cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
3855cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
3865cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    /**
387472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * Populate an intent object with the text results gathered from remote input. This method
3885cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * should only be called by remote input collection services when sending results to a
3895cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * pending intent.
3905cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * @param remoteInputs The remote inputs for which results are being provided
3915cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * @param intent The intent to add remote inputs to. The {@link ClipData}
3925cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     *               field of the intent will be modified to contain the results.
3935cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     * @param results A bundle holding the remote input results. This bundle should
3945cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     *                be populated with keys matching the result keys specified in
395472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     *                {@code remoteInputs} with values being the CharSequence results per key.
3965cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen     */
3975cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
3985cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            Bundle results) {
399472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
400472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (clipDataIntent == null) {
401472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            clipDataIntent = new Intent();  // First time we've added a result.
402472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
403472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Bundle resultsBundle = clipDataIntent.getBundleExtra(EXTRA_RESULTS_DATA);
404472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (resultsBundle == null) {
405472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            resultsBundle = new Bundle();
406472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
4075cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        for (RemoteInput remoteInput : remoteInputs) {
4085cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            Object result = results.get(remoteInput.getResultKey());
4095cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            if (result instanceof CharSequence) {
4105cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen                resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
4115cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            }
4125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
413472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        clipDataIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
414472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
415472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
416472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
417472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    /**
418fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * Same as {@link #addResultsToIntent} but for setting data results. This is used
419fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * for inputs that accept non-textual results (see {@link Builder#setAllowDataType}).
420fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * Only one result can be provided for every mime type accepted by the RemoteInput.
421fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * If multiple inputs of the same mime type are expected then multiple RemoteInputs
422fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     * should be used.
423fa458a23314018753e9b7f3c647f0f13f9b8f3cfShane Brennan     *
424472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * @param remoteInput The remote input for which results are being provided
425472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * @param intent The intent to add remote input results to. The {@link ClipData}
426472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     *               field of the intent will be modified to contain the results.
427472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     * @param results A map of mime type to the Uri result for that mime type.
428472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan     */
429472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
430472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            Map<String, Uri> results) {
431472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
432472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (clipDataIntent == null) {
433472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            clipDataIntent = new Intent();  // First time we've added a result.
434472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
435472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        for (Map.Entry<String, Uri> entry : results.entrySet()) {
436472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            String mimeType = entry.getKey();
437472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            Uri uri = entry.getValue();
438472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            if (mimeType == null) {
439472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                continue;
440472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            }
441472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            Bundle resultsBundle =
442472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                    clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
443472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            if (resultsBundle == null) {
444472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan                resultsBundle = new Bundle();
445472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            }
446472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
447472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
448472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
449472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
450472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
451472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
452472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
4536cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    /**
4546cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * Set the source of the RemoteInput results. This method should only be called by remote
4556cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * input collection services (e.g.
4566cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * {@link android.service.notification.NotificationListenerService})
4576cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * when sending results to a pending intent.
4586cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *
4596cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @see #SOURCE_FREE_FORM_INPUT
4606cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @see #SOURCE_CHOICE
4616cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *
4626cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @param intent The intent to add remote input source to. The {@link ClipData}
4636cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *               field of the intent will be modified to contain the source.
4646cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @param source The source of the results.
4656cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     */
4668e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    public static void setResultsSource(Intent intent, @Source int source) {
4676cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
4686cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        if (clipDataIntent == null) {
4696cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak            clipDataIntent = new Intent();  // First time we've added a result.
4706cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        }
4716cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        clipDataIntent.putExtra(EXTRA_RESULTS_SOURCE, source);
4726cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
4736cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    }
4746cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
4756cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    /**
4766cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * Get the source of the RemoteInput results.
4776cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *
4786cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @see #SOURCE_FREE_FORM_INPUT
4796cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @see #SOURCE_CHOICE
4806cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *
4816cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @param intent The intent object that fired in response to an action or content intent
4826cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     *               which also had one or more remote input requested.
4836cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * @return The source of the results. If no source was set, {@link #SOURCE_FREE_FORM_INPUT} will
4846cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     * be returned.
4856cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak     */
4868e2731bfeffeba32345f8b14d70dae3b8ba17353Petr Cermak    @Source
4876cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    public static int getResultsSource(Intent intent) {
4886cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
4896cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        if (clipDataIntent == null) {
4906cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak            return SOURCE_FREE_FORM_INPUT;
4916cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        }
4926cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak        return clipDataIntent.getExtras().getInt(EXTRA_RESULTS_SOURCE, SOURCE_FREE_FORM_INPUT);
4936cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak    }
4946cb667cb12eb040f0a7f68ee48f2adb39250c1efPetr Cermak
495472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    private static String getExtraResultsKeyForData(String mimeType) {
496472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
4975cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
4985cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
4995cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    @Override
5005cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public int describeContents() {
5015cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        return 0;
5025cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
5035cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
5045cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    @Override
5055cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public void writeToParcel(Parcel out, int flags) {
5065cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        out.writeString(mResultKey);
5075cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        out.writeCharSequence(mLabel);
5085cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        out.writeCharSequenceArray(mChoices);
509c3104157d8f12238b0ac8cf6c6f963dadb44167cGriff Hazen        out.writeInt(mFlags);
5105cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        out.writeBundle(mExtras);
511472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        out.writeArraySet(mAllowedDataTypes);
5125cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    }
5135cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
5145cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() {
5155cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        @Override
5165cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        public RemoteInput createFromParcel(Parcel in) {
5175cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return new RemoteInput(in);
5185cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
5195cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen
5205cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        @Override
5215cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        public RemoteInput[] newArray(int size) {
5225cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen            return new RemoteInput[size];
5235cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen        }
5245cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen    };
525472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan
526472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    private static Intent getClipDataIntentFromIntent(Intent intent) {
527472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        ClipData clipData = intent.getClipData();
528472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (clipData == null) {
529472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return null;
530472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
531472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        ClipDescription clipDescription = clipData.getDescription();
532472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
533472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return null;
534472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
535472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        if (!clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
536472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan            return null;
537472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        }
538472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan        return clipData.getItemAt(0).getIntent();
539472a3b330a926c9d86a685dc0debf71037ea279bShane Brennan    }
5405cadc3b00aa775a63518383046c902b130e09b4cGriff Hazen}
541