diff options
4 files changed, 335 insertions, 188 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 732130d1bf07..7151cbb3ec23 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -21,13 +21,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.content.pm.UserInfo; -import android.net.Uri; import android.os.Handler; -import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -73,12 +70,10 @@ import com.android.systemui.statusbar.policy.RemoteInputView; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.stream.Stream; import dagger.Lazy; @@ -111,6 +106,7 @@ public class NotificationRemoteInputManager implements Dumpable { protected final FeatureFlags mFeatureFlags; private final UserManager mUserManager; private final KeyguardManager mKeyguardManager; + private final RemoteInputNotificationRebuilder mRebuilder; private final StatusBarStateController mStatusBarStateController; private final RemoteInputUriController mRemoteInputUriController; private final NotificationClickNotifier mClickNotifier; @@ -288,6 +284,7 @@ public class NotificationRemoteInputManager implements Dumpable { mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mRebuilder = new RemoteInputNotificationRebuilder(context); // TODO: inject? if (!featureFlags.isNewNotifPipelineRenderingEnabled()) { mRemoteInputListener = createLegacyRemoteInputLifetimeExtender(mainHandler, notificationEntryManager, smartReplyController); @@ -371,7 +368,7 @@ public class NotificationRemoteInputManager implements Dumpable { if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { // FIXME: Don't forget to implement this in the coordinator! mSmartReplyController.setCallback((entry, reply) -> { - StatusBarNotification newSbn = rebuildNotificationForSendingSmartReply(entry, reply); + StatusBarNotification newSbn = mRebuilder.rebuildForSendingSmartReply(entry, reply); mEntryManager.updateNotification(newSbn, null /* ranking */); }); } @@ -633,80 +630,6 @@ public class NotificationRemoteInputManager implements Dumpable { } } - // FIXME: Move to a helper class and test separately - public StatusBarNotification rebuildNotificationForSendingSmartReply(NotificationEntry entry, - CharSequence reply) { - return rebuildNotificationWithRemoteInputInserted(entry, reply, - true /* showSpinner */, - null /* mimeType */, null /* uri */); - } - - // FIXME: Move to a helper class and test separately - public StatusBarNotification rebuildNotificationForCanceledSmartReplies( - NotificationEntry entry) { - return rebuildNotificationWithRemoteInputInserted(entry, null /* remoteInputTest */, - false /* showSpinner */, null /* mimeType */, null /* uri */); - } - - // FIXME: Move to a helper class and test separately - public StatusBarNotification rebuildNotificationForBasicExtension(NotificationEntry entry) { - CharSequence remoteInputText = entry.remoteInputText; - if (TextUtils.isEmpty(remoteInputText)) { - remoteInputText = entry.remoteInputTextWhenReset; - } - String remoteInputMimeType = entry.remoteInputMimeType; - Uri remoteInputUri = entry.remoteInputUri; - StatusBarNotification newSbn = rebuildNotificationWithRemoteInputInserted(entry, - remoteInputText, false /* showSpinner */, remoteInputMimeType, - remoteInputUri); - return newSbn; - } - - // FIXME: Move to a helper class and test separately - @VisibleForTesting - StatusBarNotification rebuildNotificationWithRemoteInputInserted(NotificationEntry entry, - 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 || uri != null) { - RemoteInputHistoryItem newItem = uri != null - ? new RemoteInputHistoryItem(mimeType, uri, remoteInputText) - : new RemoteInputHistoryItem(remoteInputText); - Parcelable[] oldHistoryItems = sbn.getNotification().extras - .getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); - RemoteInputHistoryItem[] newHistoryItems = oldHistoryItems != null - ? Stream.concat( - Stream.of(newItem), - Arrays.stream(oldHistoryItems).map(p -> (RemoteInputHistoryItem) p)) - .toArray(RemoteInputHistoryItem[]::new) - : new RemoteInputHistoryItem[] { newItem }; - b.setRemoteInputHistory(newHistoryItems); - } - b.setShowRemoteInputSpinner(showSpinner); - b.setHideSmartReplies(true); - - Notification newNotification = b.build(); - - // Undo any compatibility view inflation - newNotification.contentView = sbn.getNotification().contentView; - newNotification.bigContentView = sbn.getNotification().bigContentView; - newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; - - return new StatusBarNotification( - sbn.getPackageName(), - sbn.getOpPkg(), - sbn.getId(), - sbn.getTag(), - sbn.getUid(), - sbn.getInitialPid(), - newNotification, - sbn.getUser(), - sbn.getOverrideGroupKey(), - sbn.getPostTime()); - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mRemoteInputListener instanceof Dumpable) { @@ -994,7 +917,7 @@ public class NotificationRemoteInputManager implements Dumpable { public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { - StatusBarNotification newSbn = rebuildNotificationForBasicExtension(entry); + StatusBarNotification newSbn = mRebuilder.rebuildForRemoteInputReply(entry); entry.onRemoteInputInserted(); if (newSbn == null) { @@ -1035,7 +958,7 @@ public class NotificationRemoteInputManager implements Dumpable { public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { - StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry); + StatusBarNotification newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry); if (newSbn == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java new file mode 100644 index 000000000000..90abec17771c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2021 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 com.android.systemui.statusbar; + +import android.annotation.NonNull; +import android.app.Notification; +import android.app.RemoteInputHistoryItem; +import android.content.Context; +import android.net.Uri; +import android.os.Parcelable; +import android.service.notification.StatusBarNotification; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.Arrays; +import java.util.stream.Stream; + +import javax.inject.Inject; + +/** + * A helper class which will augment the notifications using arguments and other information + * accessible to the entry in order to provide intermediate remote input states. + */ +@SysUISingleton +public class RemoteInputNotificationRebuilder { + + private final Context mContext; + + @Inject + RemoteInputNotificationRebuilder(Context context) { + mContext = context; + } + + /** + * When a smart reply is sent off to the app, we insert the text into the remote input history, + * and show a spinner to indicate that the app has yet to respond. + */ + @NonNull + public StatusBarNotification rebuildForSendingSmartReply(NotificationEntry entry, + CharSequence reply) { + return rebuildWithRemoteInputInserted(entry, reply, + true /* showSpinner */, + null /* mimeType */, null /* uri */); + } + + /** + * When the app cancels a notification in response to a smart reply, we remove the spinner + * and leave the previously-added reply. This is the lifetime-extended appearance of the + * notification. + */ + @NonNull + public StatusBarNotification rebuildForCanceledSmartReplies( + NotificationEntry entry) { + return rebuildWithRemoteInputInserted(entry, null /* remoteInputTest */, + false /* showSpinner */, null /* mimeType */, null /* uri */); + } + + /** + * When the app cancels a notification in response to a remote input reply, we update the + * notification with the reply text and/or attachment. This is the lifetime-extended + * appearance of the notification. + */ + @NonNull + public StatusBarNotification rebuildForRemoteInputReply(NotificationEntry entry) { + CharSequence remoteInputText = entry.remoteInputText; + if (TextUtils.isEmpty(remoteInputText)) { + remoteInputText = entry.remoteInputTextWhenReset; + } + String remoteInputMimeType = entry.remoteInputMimeType; + Uri remoteInputUri = entry.remoteInputUri; + StatusBarNotification newSbn = rebuildWithRemoteInputInserted(entry, + remoteInputText, false /* showSpinner */, remoteInputMimeType, + remoteInputUri); + return newSbn; + } + + /** Inner method for generating the SBN */ + @VisibleForTesting + @NonNull + StatusBarNotification rebuildWithRemoteInputInserted(NotificationEntry entry, + 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 || uri != null) { + RemoteInputHistoryItem newItem = uri != null + ? new RemoteInputHistoryItem(mimeType, uri, remoteInputText) + : new RemoteInputHistoryItem(remoteInputText); + Parcelable[] oldHistoryItems = sbn.getNotification().extras + .getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); + RemoteInputHistoryItem[] newHistoryItems = oldHistoryItems != null + ? Stream.concat( + Stream.of(newItem), + Arrays.stream(oldHistoryItems).map(p -> (RemoteInputHistoryItem) p)) + .toArray(RemoteInputHistoryItem[]::new) + : new RemoteInputHistoryItem[] { newItem }; + b.setRemoteInputHistory(newHistoryItems); + } + b.setShowRemoteInputSpinner(showSpinner); + b.setHideSmartReplies(true); + + Notification newNotification = b.build(); + + // Undo any compatibility view inflation + newNotification.contentView = sbn.getNotification().contentView; + newNotification.bigContentView = sbn.getNotification().bigContentView; + newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; + + return new StatusBarNotification( + sbn.getPackageName(), + sbn.getOpPkg(), + sbn.getId(), + sbn.getTag(), + sbn.getUid(), + sbn.getInitialPid(), + newNotification, + sbn.getUser(), + sbn.getOverrideGroupKey(), + sbn.getPostTime()); + } + + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index f954460c3dcc..add5c6a7c1d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2021 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 com.android.systemui.statusbar; @@ -10,15 +25,12 @@ 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; import android.os.UserHandle; import android.service.notification.NotificationListenerService; -import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -165,109 +177,6 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mLegacyRemoteInputLifetimeExtender.getEntriesKeptForRemoteInputActive().isEmpty()); } - @Test - public void testRebuildWithRemoteInput_noExistingInput_image() { - Uri uri = mock(Uri.class); - String mimeType = "image/jpeg"; - String text = "image inserted"; - StatusBarNotification newSbn = - mRemoteInputManager.rebuildNotificationWithRemoteInputInserted( - 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.rebuildNotificationWithRemoteInputInserted( - 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].getText()); - assertFalse(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); - assertTrue(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); - } - - @Test - public void testRebuildWithRemoteInput_noExistingInputWithSpinner() { - StatusBarNotification newSbn = - mRemoteInputManager.rebuildNotificationWithRemoteInputInserted( - 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].getText()); - assertTrue(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); - assertTrue(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); - } - - @Test - public void testRebuildWithRemoteInput_withExistingInput() { - // Setup a notification entry with 1 remote input. - StatusBarNotification newSbn = - mRemoteInputManager.rebuildNotificationWithRemoteInputInserted( - mEntry, "A Reply", false, null, null); - NotificationEntry entry = new NotificationEntryBuilder() - .setSbn(newSbn) - .build(); - - // Try rebuilding to add another reply. - newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted( - 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("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.rebuildNotificationWithRemoteInputInserted( - mEntry, text, false, mimeType, uri); - NotificationEntry entry = new NotificationEntryBuilder() - .setSbn(newSbn) - .build(); - - // Try rebuilding to add another reply. - newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted( - 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 - public void testRebuildNotificationForCanceledSmartReplies() { - // Try rebuilding to remove spinner and hide buttons. - StatusBarNotification newSbn = - mRemoteInputManager.rebuildNotificationForCanceledSmartReplies(mEntry); - assertFalse(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); - assertTrue(newSbn.getNotification().extras - .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); - } - - private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager { TestableNotificationRemoteInputManager( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java new file mode 100644 index 000000000000..ce11d6a62a8c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2021 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 com.android.systemui.statusbar; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.mock; + +import android.app.Notification; +import android.app.RemoteInputHistoryItem; +import android.net.Uri; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class RemoteInputNotificationRebuilderTest extends SysuiTestCase { + private static final String TEST_PACKAGE_NAME = "test"; + private static final int TEST_UID = 0; + @Mock + private ExpandableNotificationRow mRow; + + private RemoteInputNotificationRebuilder mRebuilder; + private NotificationEntry mEntry; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mRebuilder = new RemoteInputNotificationRebuilder(mContext); + mEntry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setNotification(new Notification()) + .setUser(UserHandle.CURRENT) + .build(); + mEntry.setRow(mRow); + } + + @Test + public void testRebuildWithRemoteInput_noExistingInput_image() { + Uri uri = mock(Uri.class); + String mimeType = "image/jpeg"; + String text = "image inserted"; + StatusBarNotification newSbn = + mRebuilder.rebuildWithRemoteInputInserted( + 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 = + mRebuilder.rebuildWithRemoteInputInserted( + 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].getText()); + assertFalse(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); + assertTrue(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); + } + + @Test + public void testRebuildWithRemoteInput_noExistingInputWithSpinner() { + StatusBarNotification newSbn = + mRebuilder.rebuildWithRemoteInputInserted( + 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].getText()); + assertTrue(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); + assertTrue(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); + } + + @Test + public void testRebuildWithRemoteInput_withExistingInput() { + // Setup a notification entry with 1 remote input. + StatusBarNotification newSbn = + mRebuilder.rebuildWithRemoteInputInserted( + mEntry, "A Reply", false, null, null); + NotificationEntry entry = new NotificationEntryBuilder() + .setSbn(newSbn) + .build(); + + // Try rebuilding to add another reply. + newSbn = mRebuilder.rebuildWithRemoteInputInserted( + 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("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 = + mRebuilder.rebuildWithRemoteInputInserted( + mEntry, text, false, mimeType, uri); + NotificationEntry entry = new NotificationEntryBuilder() + .setSbn(newSbn) + .build(); + + // Try rebuilding to add another reply. + newSbn = mRebuilder.rebuildWithRemoteInputInserted( + 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 + public void testRebuildNotificationForCanceledSmartReplies() { + // Try rebuilding to remove spinner and hide buttons. + StatusBarNotification newSbn = + mRebuilder.rebuildForCanceledSmartReplies(mEntry); + assertFalse(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); + assertTrue(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)); + } +} |