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, "Reply", 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