New Pipeline: Remote Input 3/4: Extract notification rebuilder methods to a utility am: f744d23a2e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16167381 Change-Id: Ib80d127dfadd96c542d0ee43be32300dc356d432
This commit is contained in:
@@ -21,13 +21,10 @@ import android.app.KeyguardManager;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.RemoteInput;
|
import android.app.RemoteInput;
|
||||||
import android.app.RemoteInputHistoryItem;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -73,12 +70,10 @@ import com.android.systemui.statusbar.policy.RemoteInputView;
|
|||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
|
|
||||||
@@ -111,6 +106,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
protected final FeatureFlags mFeatureFlags;
|
protected final FeatureFlags mFeatureFlags;
|
||||||
private final UserManager mUserManager;
|
private final UserManager mUserManager;
|
||||||
private final KeyguardManager mKeyguardManager;
|
private final KeyguardManager mKeyguardManager;
|
||||||
|
private final RemoteInputNotificationRebuilder mRebuilder;
|
||||||
private final StatusBarStateController mStatusBarStateController;
|
private final StatusBarStateController mStatusBarStateController;
|
||||||
private final RemoteInputUriController mRemoteInputUriController;
|
private final RemoteInputUriController mRemoteInputUriController;
|
||||||
private final NotificationClickNotifier mClickNotifier;
|
private final NotificationClickNotifier mClickNotifier;
|
||||||
@@ -288,6 +284,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
mBarService = IStatusBarService.Stub.asInterface(
|
mBarService = IStatusBarService.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||||
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||||
|
mRebuilder = new RemoteInputNotificationRebuilder(context); // TODO: inject?
|
||||||
if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||||
mRemoteInputListener = createLegacyRemoteInputLifetimeExtender(mainHandler,
|
mRemoteInputListener = createLegacyRemoteInputLifetimeExtender(mainHandler,
|
||||||
notificationEntryManager, smartReplyController);
|
notificationEntryManager, smartReplyController);
|
||||||
@@ -371,7 +368,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
|
||||||
// FIXME: Don't forget to implement this in the coordinator!
|
// FIXME: Don't forget to implement this in the coordinator!
|
||||||
mSmartReplyController.setCallback((entry, reply) -> {
|
mSmartReplyController.setCallback((entry, reply) -> {
|
||||||
StatusBarNotification newSbn = rebuildNotificationForSendingSmartReply(entry, reply);
|
StatusBarNotification newSbn = mRebuilder.rebuildForSendingSmartReply(entry, reply);
|
||||||
mEntryManager.updateNotification(newSbn, null /* ranking */);
|
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
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
if (mRemoteInputListener instanceof Dumpable) {
|
if (mRemoteInputListener instanceof Dumpable) {
|
||||||
@@ -994,7 +917,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
public void setShouldManageLifetime(NotificationEntry entry,
|
public void setShouldManageLifetime(NotificationEntry entry,
|
||||||
boolean shouldExtend) {
|
boolean shouldExtend) {
|
||||||
if (shouldExtend) {
|
if (shouldExtend) {
|
||||||
StatusBarNotification newSbn = rebuildNotificationForBasicExtension(entry);
|
StatusBarNotification newSbn = mRebuilder.rebuildForRemoteInputReply(entry);
|
||||||
entry.onRemoteInputInserted();
|
entry.onRemoteInputInserted();
|
||||||
|
|
||||||
if (newSbn == null) {
|
if (newSbn == null) {
|
||||||
@@ -1035,7 +958,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
public void setShouldManageLifetime(NotificationEntry entry,
|
public void setShouldManageLifetime(NotificationEntry entry,
|
||||||
boolean shouldExtend) {
|
boolean shouldExtend) {
|
||||||
if (shouldExtend) {
|
if (shouldExtend) {
|
||||||
StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
|
StatusBarNotification newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry);
|
||||||
|
|
||||||
if (newSbn == null) {
|
if (newSbn == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
package com.android.systemui.statusbar;
|
||||||
|
|
||||||
@@ -10,15 +25,12 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.RemoteInputHistoryItem;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.service.notification.NotificationListenerService;
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.service.notification.StatusBarNotification;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
@@ -165,109 +177,6 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
|
|||||||
mLegacyRemoteInputLifetimeExtender.getEntriesKeptForRemoteInputActive().isEmpty());
|
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 {
|
private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
|
||||||
|
|
||||||
TestableNotificationRemoteInputManager(
|
TestableNotificationRemoteInputManager(
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user