Merge "Show RemoteInput images in notification history."

This commit is contained in:
TreeHugger Robot
2020-01-22 22:05:00 +00:00
committed by Android (Google) Code Review
9 changed files with 286 additions and 54 deletions

View File

@@ -1004,6 +1004,31 @@ public class Notification implements Parcelable
*/
public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
/**
* {@link #extras} key: this is a remote input history which can include media messages
* in addition to text, as supplied to
* {@link Builder#setRemoteInputHistory(RemoteInputHistoryItem[])} or
* {@link Builder#setRemoteInputHistory(CharSequence[])}.
*
* SystemUI can populate this through
* {@link Builder#setRemoteInputHistory(RemoteInputHistoryItem[])} with the most recent inputs
* that have been sent through a {@link RemoteInput} of this Notification. These items can
* represent either media content (specified by a URI and a MIME type) or a text message
* (described by a CharSequence).
*
* To maintain compatibility, this can also be set by apps with
* {@link Builder#setRemoteInputHistory(CharSequence[])}, which will create a
* {@link RemoteInputHistoryItem} for each of the provided text-only messages.
*
* The extra with this key is of type {@link RemoteInputHistoryItem[]} and contains the most
* recent entry at the 0 index, the second most recent at the 1 index, etc.
*
* @see Builder#setRemoteInputHistory(RemoteInputHistoryItem[])
* @hide
*/
public static final String EXTRA_REMOTE_INPUT_HISTORY_ITEMS = "android.remoteInputHistoryItems";
/**
* {@link #extras} key: boolean as supplied to
* {@link Builder#setShowRemoteInputSpinner(boolean)}.
@@ -3833,12 +3858,37 @@ public class Notification implements Parcelable
if (text == null) {
mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, null);
} else {
final int N = Math.min(MAX_REPLY_HISTORY, text.length);
CharSequence[] safe = new CharSequence[N];
for (int i = 0; i < N; i++) {
final int itemCount = Math.min(MAX_REPLY_HISTORY, text.length);
CharSequence[] safe = new CharSequence[itemCount];
RemoteInputHistoryItem[] items = new RemoteInputHistoryItem[itemCount];
for (int i = 0; i < itemCount; i++) {
safe[i] = safeCharSequence(text[i]);
items[i] = new RemoteInputHistoryItem(text[i]);
}
mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, safe);
// Also add these messages as structured history items.
mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, items);
}
return this;
}
/**
* Set the remote input history, with support for embedding URIs and mime types for
* images and other media.
* @hide
*/
@NonNull
public Builder setRemoteInputHistory(RemoteInputHistoryItem[] items) {
if (items == null) {
mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, null);
} else {
final int itemCount = Math.min(MAX_REPLY_HISTORY, items.length);
RemoteInputHistoryItem[] history = new RemoteInputHistoryItem[itemCount];
for (int i = 0; i < itemCount; i++) {
history[i] = items[i];
}
mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, history);
}
return this;
}
@@ -5246,16 +5296,17 @@ public class Notification implements Parcelable
big.setViewVisibility(R.id.actions_container, View.GONE);
}
CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
if (validRemoteInput && replyText != null
&& replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
RemoteInputHistoryItem[] replyText = (RemoteInputHistoryItem[])
mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
if (validRemoteInput && replyText != null && replyText.length > 0
&& !TextUtils.isEmpty(replyText[0].getText())
&& p.maxRemoteInputHistory > 0) {
boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
big.setViewVisibility(R.id.notification_material_reply_text_1_container,
View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_1,
processTextSpans(replyText[0]));
processTextSpans(replyText[0].getText()));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_1, p);
big.setViewVisibility(R.id.notification_material_reply_progress,
showSpinner ? View.VISIBLE : View.GONE);
@@ -5264,19 +5315,19 @@ public class Notification implements Parcelable
ColorStateList.valueOf(
isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p)));
if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])
if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
&& p.maxRemoteInputHistory > 1) {
big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_2,
processTextSpans(replyText[1]));
processTextSpans(replyText[1].getText()));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_2, p);
if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])
if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2].getText())
&& p.maxRemoteInputHistory > 2) {
big.setViewVisibility(
R.id.notification_material_reply_text_3, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_3,
processTextSpans(replyText[2]));
processTextSpans(replyText[2].getText()));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_3, p);
}
}
@@ -7517,7 +7568,7 @@ public class Notification implements Parcelable
@Nullable
private final Person mSender;
/** True if this message was generated from the extra
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}
*/
private final boolean mRemoteInputHistory;
@@ -7569,7 +7620,7 @@ public class Notification implements Parcelable
* Should be <code>null</code> for messages by the current user, in which case
* the platform will insert the user set in {@code MessagingStyle(Person)}.
* @param remoteInputHistory True if the messages was generated from the extra
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}.
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}.
* <p>
* The person provided should contain an Icon, set with
* {@link Person.Builder#setIcon(Icon)} and also have a name provided
@@ -7676,7 +7727,7 @@ public class Notification implements Parcelable
/**
* @return True if the message was generated from
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}.
* {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}.
* @hide
*/
public boolean isRemoteInputHistory() {
@@ -7906,8 +7957,8 @@ public class Notification implements Parcelable
if (mBuilder.mActions.size() > 0) {
maxRows--;
}
CharSequence[] remoteInputHistory = mBuilder.mN.extras.getCharSequenceArray(
EXTRA_REMOTE_INPUT_HISTORY);
RemoteInputHistoryItem[] remoteInputHistory = (RemoteInputHistoryItem[])
mBuilder.mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
if (remoteInputHistory != null
&& remoteInputHistory.length > NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION) {
// Let's remove some messages to make room for the remote input history.

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Stores historical input from a RemoteInput attached to a Notification.
*
* History items represent either a text message (specified by providing a CharSequence,
* or a media message (specified by providing a URI and a MIME type). Media messages must also
* include text to insert when the image cannot be loaded, ex. when URI read permission has not been
* granted correctly.
*
* @hide
*/
public class RemoteInputHistoryItem implements Parcelable {
private CharSequence mText;
private String mMimeType;
private Uri mUri;
public RemoteInputHistoryItem(String mimeType, Uri uri, CharSequence backupText) {
this.mMimeType = mimeType;
this.mUri = uri;
this.mText = Notification.safeCharSequence(backupText);
}
public RemoteInputHistoryItem(CharSequence text) {
this.mText = Notification.safeCharSequence(text);
}
protected RemoteInputHistoryItem(Parcel in) {
mText = in.readCharSequence();
mMimeType = in.readStringNoHelper();
mUri = in.readParcelable(Uri.class.getClassLoader());
}
public static final Creator<RemoteInputHistoryItem> CREATOR =
new Creator<RemoteInputHistoryItem>() {
@Override
public RemoteInputHistoryItem createFromParcel(Parcel in) {
return new RemoteInputHistoryItem(in);
}
@Override
public RemoteInputHistoryItem[] newArray(int size) {
return new RemoteInputHistoryItem[size];
}
};
public CharSequence getText() {
return mText;
}
public String getMimeType() {
return mMimeType;
}
public Uri getUri() {
return mUri;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mText);
dest.writeStringNoHelper(mMimeType);
dest.writeParcelable(mUri, flags);
}
}

View File

@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.app.Notification;
import android.app.Person;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -161,8 +162,9 @@ public class MessagingLayout extends FrameLayout implements ImageMessageConsumer
if (headerText != null) {
mConversationTitle = headerText.getText();
}
addRemoteInputHistoryToMessages(newMessages,
extras.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY));
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
addRemoteInputHistoryToMessages(newMessages, history);
boolean showSpinner =
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
bind(newMessages, newHistoricMessages, showSpinner);
@@ -175,14 +177,18 @@ public class MessagingLayout extends FrameLayout implements ImageMessageConsumer
private void addRemoteInputHistoryToMessages(
List<Notification.MessagingStyle.Message> newMessages,
CharSequence[] remoteInputHistory) {
RemoteInputHistoryItem[] remoteInputHistory) {
if (remoteInputHistory == null || remoteInputHistory.length == 0) {
return;
}
for (int i = remoteInputHistory.length - 1; i >= 0; i--) {
CharSequence message = remoteInputHistory[i];
newMessages.add(new Notification.MessagingStyle.Message(
message, 0, (Person) null, true /* remoteHistory */));
RemoteInputHistoryItem historyMessage = remoteInputHistory[i];
Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
historyMessage.getText(), 0, (Person) null, true /* remoteHistory */);
if (historyMessage.getUri() != null) {
message.setData(historyMessage.getMimeType(), historyMessage.getUri());
}
newMessages.add(message);
}
}

View File

@@ -194,6 +194,10 @@
<!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
<string name="global_action_screenshot">Screenshot</string>
<!-- text to show in place of RemoteInput images when they cannot be shown.
[CHAR LIMIT=50] -->
<string name="remote_input_image_insertion_text">Image inserted</string>
<!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
<string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
<!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->

View File

@@ -25,8 +25,10 @@ import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -345,7 +347,8 @@ public class NotificationRemoteInputManager implements Dumpable {
});
mSmartReplyController.setCallback((entry, reply) -> {
StatusBarNotification newSbn =
rebuildNotificationWithRemoteInput(entry, reply, true /* showSpinner */);
rebuildNotificationWithRemoteInput(entry, reply, true /* showSpinner */,
null /* mimeType */, null /* uri */);
mEntryManager.updateNotification(newSbn, null /* ranking */);
});
}
@@ -527,28 +530,36 @@ public class NotificationRemoteInputManager implements Dumpable {
StatusBarNotification rebuildNotificationForCanceledSmartReplies(
NotificationEntry entry) {
return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
false /* showSpinner */);
false /* showSpinner */, null /* mimeType */, null /* uri */);
}
@VisibleForTesting
StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
CharSequence remoteInputText, boolean showSpinner) {
CharSequence remoteInputText, boolean showSpinner, String mimeType, Uri uri) {
StatusBarNotification sbn = entry.getSbn();
Notification.Builder b = Notification.Builder
.recoverBuilder(mContext, sbn.getNotification().clone());
if (remoteInputText != null) {
CharSequence[] oldHistory = sbn.getNotification().extras
.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
CharSequence[] newHistory;
if (oldHistory == null) {
newHistory = new CharSequence[1];
if (remoteInputText != null || uri != null) {
RemoteInputHistoryItem[] oldHistoryItems = (RemoteInputHistoryItem[])
sbn.getNotification().extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
RemoteInputHistoryItem[] newHistoryItems;
if (oldHistoryItems == null) {
newHistoryItems = new RemoteInputHistoryItem[1];
} else {
newHistory = new CharSequence[oldHistory.length + 1];
System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
newHistoryItems = new RemoteInputHistoryItem[oldHistoryItems.length + 1];
System.arraycopy(oldHistoryItems, 0, newHistoryItems, 1, oldHistoryItems.length);
}
newHistory[0] = String.valueOf(remoteInputText);
b.setRemoteInputHistory(newHistory);
RemoteInputHistoryItem newItem;
if (uri != null) {
newItem = new RemoteInputHistoryItem(mimeType, uri, remoteInputText);
} else {
newItem = new RemoteInputHistoryItem(remoteInputText);
}
newHistoryItems[0] = newItem;
b.setRemoteInputHistory(newHistoryItems);
}
b.setShowRemoteInputSpinner(showSpinner);
b.setHideSmartReplies(true);
@@ -631,8 +642,11 @@ public class NotificationRemoteInputManager implements Dumpable {
if (TextUtils.isEmpty(remoteInputText)) {
remoteInputText = entry.remoteInputTextWhenReset;
}
String remoteInputMimeType = entry.remoteInputMimeType;
Uri remoteInputUri = entry.remoteInputUri;
StatusBarNotification newSbn = rebuildNotificationWithRemoteInput(entry,
remoteInputText, false /* showSpinner */);
remoteInputText, false /* showSpinner */, remoteInputMimeType,
remoteInputUri);
entry.onRemoteInputInserted();
if (newSbn == null) {

View File

@@ -37,8 +37,10 @@ import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
import android.app.NotificationManager.Policy;
import android.app.Person;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService.Ranking;
@@ -120,6 +122,8 @@ public final class NotificationEntry extends ListEntry {
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
public CharSequence remoteInputText;
public String remoteInputMimeType;
public Uri remoteInputUri;
private Notification.BubbleMetadata mBubbleMetadata;
/**
@@ -595,8 +599,8 @@ public final class NotificationEntry extends ListEntry {
return false;
}
Bundle extras = mSbn.getNotification().extras;
CharSequence[] replyTexts = extras.getCharSequenceArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY);
RemoteInputHistoryItem[] replyTexts = (RemoteInputHistoryItem[]) extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
if (!ArrayUtils.isEmpty(replyTexts)) {
return true;
}

View File

@@ -80,7 +80,15 @@ public class NotificationInlineImageResolver implements ImageResolver {
public Drawable loadImage(Uri uri) {
Drawable result = null;
try {
result = hasCache() ? mImageCache.get(uri) : resolveImage(uri);
if (hasCache()) {
// if the uri isn't currently cached, try caching it first
if (!mImageCache.hasEntry(uri)) {
mImageCache.preload((uri));
}
result = mImageCache.get(uri);
} else {
result = resolveImage(uri);
}
} catch (IOException | SecurityException ex) {
Log.d(TAG, "loadImage: Can't load image from " + uri, ex);
}

View File

@@ -161,6 +161,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
results);
mEntry.remoteInputText = mEditText.getText();
mEntry.remoteInputUri = null;
mEntry.remoteInputMimeType = null;
if (mEntry.editedSuggestionInfo == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT);
} else {
@@ -177,6 +182,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addDataResultToIntent(mRemoteInput, fillInIntent, results);
mEntry.remoteInputText = mContext.getString(R.string.remote_input_image_insertion_text);
mEntry.remoteInputMimeType = contentType;
mEntry.remoteInputUri = data;
return fillInIntent;
}
@@ -184,7 +193,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
mEntry.remoteInputText = mEditText.getText();
mEntry.lastRemoteInputSent = SystemClock.elapsedRealtime();
mController.addSpinning(mEntry.getKey(), mToken);
mController.removeRemoteInput(mEntry, mToken);

View File

@@ -10,7 +10,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
@@ -149,14 +151,31 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
assertTrue(mRemoteInputManager.getEntriesKeptForRemoteInputActive().isEmpty());
}
@Test
public void testRebuildWithRemoteInput_noExistingInput_image() {
Uri uri = mock(Uri.class);
String mimeType = "image/jpeg";
String text = "image inserted";
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mEntry, text, false, mimeType, uri);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
assertEquals(1, messages.length);
assertEquals(text, messages[0].getText());
assertEquals(mimeType, messages[0].getMimeType());
assertEquals(uri, messages[0].getUri());
}
@Test
public void testRebuildWithRemoteInput_noExistingInputNoSpinner() {
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
CharSequence[] messages = newSbn.getNotification().extras
.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mEntry, "A Reply", false, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
assertEquals(1, messages.length);
assertEquals("A Reply", messages[0]);
assertEquals("A Reply", messages[0].getText());
assertFalse(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
assertTrue(newSbn.getNotification().extras
@@ -166,11 +185,12 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
@Test
public void testRebuildWithRemoteInput_noExistingInputWithSpinner() {
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", true);
CharSequence[] messages = newSbn.getNotification().extras
.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mEntry, "A Reply", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
assertEquals(1, messages.length);
assertEquals("A Reply", messages[0]);
assertEquals("A Reply", messages[0].getText());
assertTrue(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
assertTrue(newSbn.getNotification().extras
@@ -181,18 +201,45 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
public void testRebuildWithRemoteInput_withExistingInput() {
// Setup a notification entry with 1 remote input.
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mEntry, "A Reply", false, null, null);
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(newSbn)
.build();
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true);
CharSequence[] messages = newSbn.getNotification().extras
.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(
entry, "Reply 2", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
assertEquals(2, messages.length);
assertEquals("Reply 2", messages[0]);
assertEquals("A Reply", messages[1]);
assertEquals("Reply 2", messages[0].getText());
assertEquals("A Reply", messages[1].getText());
}
@Test
public void testRebuildWithRemoteInput_withExistingInput_image() {
// Setup a notification entry with 1 remote input.
Uri uri = mock(Uri.class);
String mimeType = "image/jpeg";
String text = "image inserted";
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mEntry, text, false, mimeType, uri);
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(newSbn)
.build();
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(
entry, "Reply 2", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
assertEquals(2, messages.length);
assertEquals("Reply 2", messages[0].getText());
assertEquals(text, messages[1].getText());
assertEquals(mimeType, messages[1].getMimeType());
assertEquals(uri, messages[1].getUri());
}
@Test