Merge "Add support for audio-focused notifications."
diff --git a/api/current.txt b/api/current.txt
index b812f1b..8d281a2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5027,6 +5027,7 @@
field public static final int DEFAULT_LIGHTS = 4; // 0x4
field public static final int DEFAULT_SOUND = 1; // 0x1
field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5110,6 +5111,7 @@
method public android.app.Notification.Action clone();
method public int describeContents();
method public boolean getAllowGeneratedReplies();
+ method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
method public android.os.Bundle getExtras();
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
@@ -5576,14 +5578,18 @@
}
public final class RemoteInput implements android.os.Parcelable {
+ method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
method public int describeContents();
method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String> getAllowedDataTypes();
method public java.lang.CharSequence[] getChoices();
+ method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
method public android.os.Bundle getExtras();
method public java.lang.CharSequence getLabel();
method public java.lang.String getResultKey();
method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+ method public boolean isDataOnly();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5595,6 +5601,7 @@
method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
method public android.app.RemoteInput build();
method public android.os.Bundle getExtras();
+ method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
diff --git a/api/system-current.txt b/api/system-current.txt
index cbb7f86..d7a8fc5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5185,6 +5185,7 @@
field public static final int DEFAULT_LIGHTS = 4; // 0x4
field public static final int DEFAULT_SOUND = 1; // 0x1
field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5270,6 +5271,7 @@
method public android.app.Notification.Action clone();
method public int describeContents();
method public boolean getAllowGeneratedReplies();
+ method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
method public android.os.Bundle getExtras();
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
@@ -5761,14 +5763,18 @@
}
public final class RemoteInput implements android.os.Parcelable {
+ method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
method public int describeContents();
method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String> getAllowedDataTypes();
method public java.lang.CharSequence[] getChoices();
+ method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
method public android.os.Bundle getExtras();
method public java.lang.CharSequence getLabel();
method public java.lang.String getResultKey();
method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+ method public boolean isDataOnly();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5780,6 +5786,7 @@
method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
method public android.app.RemoteInput build();
method public android.os.Bundle getExtras();
+ method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
diff --git a/api/test-current.txt b/api/test-current.txt
index 8e2f781..807d6bd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5037,6 +5037,7 @@
field public static final int DEFAULT_LIGHTS = 4; // 0x4
field public static final int DEFAULT_SOUND = 1; // 0x1
field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5120,6 +5121,7 @@
method public android.app.Notification.Action clone();
method public int describeContents();
method public boolean getAllowGeneratedReplies();
+ method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
method public android.os.Bundle getExtras();
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
@@ -5587,14 +5589,18 @@
}
public final class RemoteInput implements android.os.Parcelable {
+ method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
method public int describeContents();
method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String> getAllowedDataTypes();
method public java.lang.CharSequence[] getChoices();
+ method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
method public android.os.Bundle getExtras();
method public java.lang.CharSequence getLabel();
method public java.lang.String getResultKey();
method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+ method public boolean isDataOnly();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5606,6 +5612,7 @@
method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
method public android.app.RemoteInput build();
method public android.os.Bundle getExtras();
+ method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c6f0b66..ab0b68d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -988,6 +988,32 @@
*/
public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
+ /**
+ * {@link #extras} key: the audio contents of this notification.
+ *
+ * This is for use when rendering the notification on an audio-focused interface;
+ * the audio contents are a complete sound sample that contains the contents/body of the
+ * notification. This may be used in substitute of a Text-to-Speech reading of the
+ * notification. For example if the notification represents a voice message this should point
+ * to the audio of that message.
+ *
+ * The data stored under this key should be a String representation of a Uri that contains the
+ * audio contents in one of the following formats: WAV, PCM 16-bit, AMR-WB.
+ *
+ * This extra is unnecessary if you are using {@code MessagingStyle} since each {@code Message}
+ * has a field for holding data URI. That field can be used for audio.
+ * See {@code Message#setData}.
+ *
+ * Example usage:
+ * <pre>
+ * {@code
+ * Notification.Builder myBuilder = (build your Notification as normal);
+ * myBuilder.getExtras().putString(EXTRA_AUDIO_CONTENTS_URI, myAudioUri.toString());
+ * }
+ * </pre>
+ */
+ public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+
/** @hide */
@SystemApi
public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
@@ -1007,6 +1033,21 @@
* to attach actions.
*/
public static class Action implements Parcelable {
+ /**
+ * {@link #extras} key: Keys to a {@link Parcelable} {@link ArrayList} of
+ * {@link RemoteInput}s.
+ *
+ * This is intended for {@link RemoteInput}s that only accept data, meaning
+ * {@link RemoteInput#getAllowFreeFormInput} is false, {@link RemoteInput#getChoices}
+ * is null or empty, and {@link RemoteInput#getAllowedDataTypes is non-null and not
+ * empty. These {@link RemoteInput}s will be ignored by devices that do not
+ * support non-text-based {@link RemoteInput}s. See {@link Builder#build}.
+ *
+ * You can test if a RemoteInput matches these constraints using
+ * {@link RemoteInput#isDataOnly}.
+ */
+ private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS";
+
private final Bundle mExtras;
private Icon mIcon;
private final RemoteInput[] mRemoteInputs;
@@ -1097,13 +1138,28 @@
/**
* Get the list of inputs to be collected from the user when this action is sent.
- * May return null if no remote inputs were added.
+ * May return null if no remote inputs were added. Only returns inputs which accept
+ * a text input. For inputs which only accept data use {@link #getDataOnlyRemoteInputs}.
*/
public RemoteInput[] getRemoteInputs() {
return mRemoteInputs;
}
/**
+ * Get the list of inputs to be collected from the user that ONLY accept data when this
+ * action is sent. These remote inputs are guaranteed to return true on a call to
+ * {@link RemoteInput#isDataOnly}.
+ *
+ * May return null if no data-only remote inputs were added.
+ *
+ * This method exists so that legacy RemoteInput collectors that pre-date the addition
+ * of non-textual RemoteInputs do not access these remote inputs.
+ */
+ public RemoteInput[] getDataOnlyRemoteInputs() {
+ return (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+ }
+
+ /**
* Builder class for {@link Action} objects.
*/
public static final class Builder {
@@ -1226,9 +1282,32 @@
* @return the built action
*/
public Action build() {
- RemoteInput[] remoteInputs = mRemoteInputs != null
- ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
- return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs,
+ ArrayList<RemoteInput> dataOnlyInputs = new ArrayList<>();
+ RemoteInput[] previousDataInputs =
+ (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+ if (previousDataInputs == null) {
+ for (RemoteInput input : previousDataInputs) {
+ dataOnlyInputs.add(input);
+ }
+ }
+ List<RemoteInput> textInputs = new ArrayList<>();
+ if (mRemoteInputs != null) {
+ for (RemoteInput input : mRemoteInputs) {
+ if (input.isDataOnly()) {
+ dataOnlyInputs.add(input);
+ } else {
+ textInputs.add(input);
+ }
+ }
+ }
+ if (!dataOnlyInputs.isEmpty()) {
+ RemoteInput[] dataInputsArr =
+ dataOnlyInputs.toArray(new RemoteInput[dataOnlyInputs.size()]);
+ mExtras.putParcelableArray(EXTRA_DATA_ONLY_INPUTS, dataInputsArr);
+ }
+ RemoteInput[] textInputsArr = textInputs.isEmpty()
+ ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
+ return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
mAllowGeneratedReplies);
}
}
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 11420c5..d1dc859 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -19,9 +19,14 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArraySet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
/**
* A {@code RemoteInput} object specifies input to be collected from a user to be passed along with
@@ -61,9 +66,13 @@
/** Label used to denote the clip data type used for remote input transport */
public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
- /** Extra added to a clip data intent object to hold the results bundle. */
+ /** Extra added to a clip data intent object to hold the text results bundle. */
public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ /** Extra added to a clip data intent object to hold the data results bundle. */
+ private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+ "android.remoteinput.dataTypeResultsData";
+
// Flags bitwise-ored to mFlags
private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
@@ -75,14 +84,16 @@
private final CharSequence[] mChoices;
private final int mFlags;
private final Bundle mExtras;
+ private final ArraySet<String> mAllowedDataTypes;
private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
- int flags, Bundle extras) {
+ int flags, Bundle extras, ArraySet<String> allowedDataTypes) {
this.mResultKey = resultKey;
this.mLabel = label;
this.mChoices = choices;
this.mFlags = flags;
this.mExtras = extras;
+ this.mAllowedDataTypes = allowedDataTypes;
}
/**
@@ -107,6 +118,21 @@
return mChoices;
}
+ public Set<String> getAllowedDataTypes() {
+ return mAllowedDataTypes;
+ }
+
+ /**
+ * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
+ * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
+ * non-null and not empty.
+ */
+ public boolean isDataOnly() {
+ return !getAllowFreeFormInput()
+ && (getChoices() == null || getChoices().length == 0)
+ && !getAllowedDataTypes().isEmpty();
+ }
+
/**
* Get whether or not users can provide an arbitrary value for
* input. If you set this to {@code false}, users must select one of the
@@ -133,6 +159,7 @@
private CharSequence[] mChoices;
private int mFlags = DEFAULT_FLAGS;
private Bundle mExtras = new Bundle();
+ private final ArraySet<String> mAllowedDataTypes = new ArraySet<>();
/**
* Create a builder object for {@link RemoteInput} objects.
@@ -177,14 +204,34 @@
/**
* Specifies whether the user can provide arbitrary values.
*
- * @param allowFreeFormInput The default is {@code true}.
- * If you specify {@code false}, you must provide a non-null
- * and non-empty array to {@link #setChoices} or an
+ * @param mimeType A mime type that results are allowed to come in.
+ * Be aware that text results (see {@link #setAllowFreeFormInput}
+ * are allowed by default. If you do not want text results you will have to
+ * pass false to {@code setAllowFreeFormInput}.
+ * @param doAllow Whether the mime type should be allowed or not.
+ * @return this object for method chaining
+ */
+ public Builder setAllowDataType(String mimeType, boolean doAllow) {
+ if (doAllow) {
+ mAllowedDataTypes.add(mimeType);
+ } else {
+ mAllowedDataTypes.remove(mimeType);
+ }
+ return this;
+ }
+
+ /**
+ * Specifies whether the user can provide arbitrary text values.
+ *
+ * @param allowFreeFormTextInput The default is {@code true}.
+ * If you specify {@code false}, you must either provide a non-null
+ * and non-empty array to {@link #setChoices}, or enable a data result
+ * in {@code setAllowDataType}. Otherwise an
* {@link IllegalArgumentException} is thrown.
* @return this object for method chaining
*/
- public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
- setFlag(mFlags, allowFreeFormInput);
+ public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
+ setFlag(mFlags, allowFreeFormTextInput);
return this;
}
@@ -224,7 +271,8 @@
* object.
*/
public RemoteInput build() {
- return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mExtras);
+ return new RemoteInput(
+ mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes);
}
}
@@ -234,32 +282,68 @@
mChoices = in.readCharSequenceArray();
mFlags = in.readInt();
mExtras = in.readBundle();
+ mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null);
}
/**
- * Get the remote input results bundle from an intent. The returned Bundle will
- * contain a key/value for every result key populated by remote input collector.
- * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
+ * Similar as {@link #getResultsFromIntent} but retrieves data results for a
+ * specific RemoteInput result. To retrieve a value use:
+ * <pre>
+ * {@code
+ * Map<String, Uri> results =
+ * RemoteInput.getDataResultsFromIntent(intent, REMOTE_INPUT_KEY);
+ * if (results != null) {
+ * Uri data = results.get(MIME_TYPE_OF_INTEREST);
+ * }
+ * }
+ * </pre>
+ * @param intent The intent object that fired in response to an action or content intent
+ * which also had one or more remote input requested.
+ * @param remoteInputResultKey The result key for the RemoteInput you want results for.
+ */
+ public static Map<String, Uri> getDataResultsFromIntent(
+ Intent intent, String remoteInputResultKey) {
+ Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+ if (clipDataIntent == null) {
+ return null;
+ }
+ Map<String, Uri> results = new HashMap<>();
+ Bundle extras = clipDataIntent.getExtras();
+ for (String key : extras.keySet()) {
+ if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
+ String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
+ if (mimeType == null || mimeType.isEmpty()) {
+ continue;
+ }
+ Bundle bundle = clipDataIntent.getBundleExtra(key);
+ String uriStr = bundle.getString(remoteInputResultKey);
+ if (uriStr == null || uriStr.isEmpty()) {
+ continue;
+ }
+ results.put(mimeType, Uri.parse(uriStr));
+ }
+ }
+ return results.isEmpty() ? null : results;
+ }
+
+ /**
+ * Get the remote input text results bundle from an intent. The returned Bundle will
+ * contain a key/value for every result key populated with text by remote input collector.
+ * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. For non-text
+ * results use {@link #getDataResultsFromIntent}.
* @param intent The intent object that fired in response to an action or content intent
* which also had one or more remote input requested.
*/
public static Bundle getResultsFromIntent(Intent intent) {
- ClipData clipData = intent.getClipData();
- if (clipData == null) {
+ Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+ if (clipDataIntent == null) {
return null;
}
- ClipDescription clipDescription = clipData.getDescription();
- if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
- return null;
- }
- if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
- return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA);
- }
- return null;
+ return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
}
/**
- * Populate an intent object with the results gathered from remote input. This method
+ * Populate an intent object with the text results gathered from remote input. This method
* should only be called by remote input collection services when sending results to a
* pending intent.
* @param remoteInputs The remote inputs for which results are being provided
@@ -267,20 +351,61 @@
* field of the intent will be modified to contain the results.
* @param results A bundle holding the remote input results. This bundle should
* be populated with keys matching the result keys specified in
- * {@code remoteInputs} with values being the result per key.
+ * {@code remoteInputs} with values being the CharSequence results per key.
*/
public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
Bundle results) {
- Bundle resultsBundle = new Bundle();
+ Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+ if (clipDataIntent == null) {
+ clipDataIntent = new Intent(); // First time we've added a result.
+ }
+ Bundle resultsBundle = clipDataIntent.getBundleExtra(EXTRA_RESULTS_DATA);
+ if (resultsBundle == null) {
+ resultsBundle = new Bundle();
+ }
for (RemoteInput remoteInput : remoteInputs) {
Object result = results.get(remoteInput.getResultKey());
if (result instanceof CharSequence) {
resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
}
}
- Intent clipIntent = new Intent();
- clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
- intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent));
+ clipDataIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
+ intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+ }
+
+ /**
+ * Same as {@link #addResultsToIntent} but for setting data results.
+ * @param remoteInput The remote input for which results are being provided
+ * @param intent The intent to add remote input results to. The {@link ClipData}
+ * field of the intent will be modified to contain the results.
+ * @param results A map of mime type to the Uri result for that mime type.
+ */
+ public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+ Map<String, Uri> results) {
+ Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+ if (clipDataIntent == null) {
+ clipDataIntent = new Intent(); // First time we've added a result.
+ }
+ for (Map.Entry<String, Uri> entry : results.entrySet()) {
+ String mimeType = entry.getKey();
+ Uri uri = entry.getValue();
+ if (mimeType == null) {
+ continue;
+ }
+ Bundle resultsBundle =
+ clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
+ if (resultsBundle == null) {
+ resultsBundle = new Bundle();
+ }
+ resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
+
+ clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
+ }
+ intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+ }
+
+ private static String getExtraResultsKeyForData(String mimeType) {
+ return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
}
@Override
@@ -295,6 +420,7 @@
out.writeCharSequenceArray(mChoices);
out.writeInt(mFlags);
out.writeBundle(mExtras);
+ out.writeArraySet(mAllowedDataTypes);
}
public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() {
@@ -308,4 +434,19 @@
return new RemoteInput[size];
}
};
+
+ private static Intent getClipDataIntentFromIntent(Intent intent) {
+ ClipData clipData = intent.getClipData();
+ if (clipData == null) {
+ return null;
+ }
+ ClipDescription clipDescription = clipData.getDescription();
+ if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+ return null;
+ }
+ if (!clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
+ return null;
+ }
+ return clipData.getItemAt(0).getIntent();
+ }
}