messages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+ (Parcelable[]) mSbn.getNotification().extras.get(
+ Notification.EXTRA_MESSAGES));
+
+ final Notification.MessagingStyle.Message latestMessage =
+ Notification.MessagingStyle.findLatestIncomingMessage(messages);
+ Icon personIcon = null;
+ if (latestMessage != null && latestMessage.getSenderPerson() != null) {
+ personIcon = latestMessage.getSenderPerson().getIcon();
+ }
+ if (personIcon != null) {
+ image.setImageIcon(latestMessage.getSenderPerson().getIcon());
+ } else {
+ image.setImageDrawable(mPkgIcon);
+ }
+ }
+ }
+
+ private void bindPackage() {
+ ApplicationInfo info;
+ try {
+ info = mPm.getApplicationInfo(
+ mPackageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ mAppName = String.valueOf(mPm.getApplicationLabel(info));
+ mPkgIcon = mPm.getApplicationIcon(info);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ mPkgIcon = mPm.getDefaultActivityIcon();
+ }
+ ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
+ }
+
+ private void bindDelegate() {
+ TextView delegateView = findViewById(R.id.delegate_name);
+
+ if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
+ // this notification was posted by a delegate!
+ delegateView.setVisibility(View.VISIBLE);
+ } else {
+ delegateView.setVisibility(View.GONE);
+ }
+ }
+
+ private void bindGroup() {
+ // Set group information if this channel has an associated group.
+ CharSequence groupName = null;
+ if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) {
+ try {
+ final NotificationChannelGroup notificationChannelGroup =
+ mINotificationManager.getNotificationChannelGroupForPackage(
+ mNotificationChannel.getGroup(), mPackageName, mAppUid);
+ if (notificationChannelGroup != null) {
+ groupName = notificationChannelGroup.getName();
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ TextView groupNameView = findViewById(R.id.group_name);
+ View groupDivider = findViewById(R.id.group_divider);
+ if (groupName != null) {
+ groupNameView.setText(groupName);
+ groupNameView.setVisibility(VISIBLE);
+ groupDivider.setVisibility(VISIBLE);
+ } else {
+ groupNameView.setVisibility(GONE);
+ groupDivider.setVisibility(GONE);
+ }
+ }
+
+ @Override
+ public boolean post(Runnable action) {
+ if (mSkipPost) {
+ action.run();
+ return true;
+ } else {
+ return super.post(action);
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ }
+
+ @Override
+ public void onFinishedClosing() {
+ // TODO: do we need to do anything here?
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ if (mGutsContainer != null &&
+ event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ if (mGutsContainer.isExposed()) {
+ event.getText().add(mContext.getString(
+ R.string.notification_channel_controls_opened_accessibility, mAppName));
+ } else {
+ event.getText().add(mContext.getString(
+ R.string.notification_channel_controls_closed_accessibility, mAppName));
+ }
+ }
+ }
+
+ /**
+ * Closes the controls and commits the updated importance values (indirectly).
+ *
+ * Note, this will only get called once the view is dismissing. This means that the
+ * user does not have the ability to undo the action anymore.
+ */
+ @VisibleForTesting
+ void closeControls(View v, boolean save) {
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ mGutsContainer.getLocationOnScreen(parentLoc);
+ v.getLocationOnScreen(targetLoc);
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+ mGutsContainer.closeControls(x, y, save, false /* force */);
+ }
+
+ @Override
+ public void setGutsParent(NotificationGuts guts) {
+ mGutsContainer = guts;
+ }
+
+ @Override
+ public boolean willBeRemoved() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldBeSaved() {
+ return mPressedApply;
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public boolean handleCloseControls(boolean save, boolean force) {
+ return false;
+ }
+
+ @Override
+ public int getActualHeight() {
+ return getHeight();
+ }
+
+ @VisibleForTesting
+ public boolean isAnimating() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 58e7d5dc2274a..85f981853520b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -356,7 +356,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
applicationInfo);
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
- NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setSbn(mSbn)
+ .setShortcutInfo(mShortcutInfo)
+ .build();
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
new file mode 100644
index 0000000000000..c390e3933d7a2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2020 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.notification.row;
+
+import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.Person;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class PartialConversationInfoTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test_package";
+ private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
+ private static final int TEST_UID = 1;
+ private static final String TEST_CHANNEL = "test_channel";
+ private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
+
+ private TestableLooper mTestableLooper;
+ private PartialConversationInfo mInfo;
+ private NotificationChannel mNotificationChannel;
+ private NotificationChannel mDefaultNotificationChannel;
+ private Set mNotificationChannelSet = new HashSet<>();
+ private Set mDefaultNotificationChannelSet = new HashSet<>();
+ private StatusBarNotification mSbn;
+ private NotificationEntry mEntry;
+
+ @Rule
+ public MockitoRule mockito = MockitoJUnit.rule();
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private INotificationManager mMockINotificationManager;
+ @Mock
+ private PackageManager mMockPackageManager;
+
+ @Mock
+ private Icon mIcon;
+ @Mock
+ private Drawable mDrawable;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestableLooper = TestableLooper.get(this);
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+ // Inflate the layout
+ final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ mInfo = (PartialConversationInfo) layoutInflater.inflate(R.layout.partial_conversation_info,
+ null);
+ mInfo.setGutsParent(mock(NotificationGuts.class));
+ // Our view is never attached to a window so the View#post methods in NotificationInfo never
+ // get called. Setting this will skip the post and do the action immediately.
+ mInfo.mSkipPost = true;
+
+ // PackageManager must return a packageInfo and applicationInfo.
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = TEST_PACKAGE_NAME;
+ when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()))
+ .thenReturn(packageInfo);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = TEST_UID; // non-zero
+ when(mMockPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt())).thenReturn(
+ applicationInfo);
+ final PackageInfo systemPackageInfo = new PackageInfo();
+ systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME;
+ when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt()))
+ .thenReturn(systemPackageInfo);
+ when(mMockPackageManager.getPackageInfo(eq("android"), anyInt()))
+ .thenReturn(packageInfo);
+
+ // Package has one channel by default.
+ when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1);
+
+ when(mIcon.loadDrawable(any())).thenReturn(mDrawable);
+
+ // Some test channels.
+ mNotificationChannel = new NotificationChannel(
+ TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
+ mNotificationChannelSet.add(mNotificationChannel);
+ mDefaultNotificationChannel = new NotificationChannel(
+ NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
+ IMPORTANCE_LOW);
+ mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+ new Notification(), UserHandle.CURRENT, null, 0);
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ }
+
+ @Test
+ public void testBindNotification_SetsTextApplicationName() throws Exception {
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final TextView textView = mInfo.findViewById(R.id.pkg_name);
+ assertTrue(textView.getText().toString().contains("App Name"));
+ assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_groupSetsPackageIcon() {
+ mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true);
+ final Drawable iconDrawable = mock(Drawable.class);
+ when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
+ .thenReturn(iconDrawable);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+ assertEquals(iconDrawable, iconView.getDrawable());
+ }
+
+ @Test
+ public void testBindNotification_notGroupSetsMessageIcon() {
+ Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME)
+ .setStyle(new Notification.MessagingStyle(
+ new Person.Builder().setName("me").build())
+ .addMessage(new Notification.MessagingStyle.Message("hello", 0,
+ new Person.Builder().setName("friend").setIcon(mIcon).build())))
+ .build();
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+ n, UserHandle.CURRENT, null, 0);
+ mEntry.setSbn(mSbn);
+ mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+ assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable());
+ }
+
+ @Test
+ public void testBindNotification_noDelegate() {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final TextView nameView = mInfo.findViewById(R.id.delegate_name);
+ assertEquals(GONE, nameView.getVisibility());
+ final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+ assertEquals(GONE, dividerView.getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_delegate() throws Exception {
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, "other", 0, null, TEST_UID, 0,
+ new Notification(), UserHandle.CURRENT, null, 0);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = 7; // non-zero
+ when(mMockPackageManager.getApplicationInfo(eq("other"), anyInt())).thenReturn(
+ applicationInfo);
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
+
+ NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ entry,
+ null,
+ true,
+ false);
+ final TextView nameView = mInfo.findViewById(R.id.delegate_name);
+ assertEquals(VISIBLE, nameView.getVisibility());
+ assertTrue(nameView.getText().toString().contains("Proxied"));
+ }
+
+ @Test
+ public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final TextView groupNameView = mInfo.findViewById(R.id.group_name);
+ assertEquals(GONE, groupNameView.getVisibility());
+ final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+ assertEquals(GONE, dividerView.getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_SetsGroupNameIfNonNull() throws Exception {
+ mNotificationChannel.setGroup("test_group_id");
+ final NotificationChannelGroup notificationChannelGroup =
+ new NotificationChannelGroup("test_group_id", "Test Group Name");
+ when(mMockINotificationManager.getNotificationChannelGroupForPackage(
+ eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
+ .thenReturn(notificationChannelGroup);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final TextView groupNameView = mInfo.findViewById(R.id.group_name);
+ assertEquals(View.VISIBLE, groupNameView.getVisibility());
+ assertEquals("Test Group Name", groupNameView.getText());
+ final TextView dividerView = mInfo.findViewById(R.id.group_divider);
+ assertEquals(View.VISIBLE, dividerView.getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_SetsTextChannelName() {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final TextView textView = mInfo.findViewById(R.id.parent_channel_name);
+ assertEquals(TEST_CHANNEL_NAME, textView.getText());
+ }
+
+ @Test
+ public void testBindNotification_SetsOnClickListenerForSettings() {
+ final CountDownLatch latch = new CountDownLatch(1);
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ (View v, NotificationChannel c, int appUid) -> {
+ assertEquals(mNotificationChannel, c);
+ latch.countDown();
+ },
+ true,
+ false);
+
+ final View settingsButton = mInfo.findViewById(R.id.info);
+ settingsButton.performClick();
+ // Verify that listener was triggered.
+ assertEquals(0, latch.getCount());
+ }
+
+ @Test
+ public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ false);
+ final View settingsButton = mInfo.findViewById(R.id.info);
+ assertTrue(settingsButton.getVisibility() != View.VISIBLE);
+ }
+
+ @Test
+ public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ (View v, NotificationChannel c, int appUid) -> {
+ assertEquals(mNotificationChannel, c);
+ },
+ false,
+ false);
+ final View settingsButton = mInfo.findViewById(R.id.info);
+ assertTrue(settingsButton.getVisibility() != View.VISIBLE);
+ }
+
+ @Test
+ public void testBindNotification_whenAppUnblockable() {
+ mInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ true,
+ true);
+
+ assertEquals(GONE,
+ mInfo.findViewById(R.id.turn_off_notifications).getVisibility());
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
index 83ca699560336..2f60e426245dd 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
@@ -47,7 +47,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor
NotificationChannel updatedChannel = mConfig.getConversationNotificationChannel(
record.getSbn().getPackageName(),
record.getSbn().getUid(), record.getChannel().getId(),
- record.getSbn().getShortcutId(mContext), true, false);
+ record.getSbn().getShortcutId(), true, false);
record.updateNotificationChannel(updatedChannel);
return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 246a4ed3a9f3a..200e92c9c1f55 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2721,12 +2721,12 @@ public class NotificationManagerService extends SystemService {
}
return text == null ? null : String.valueOf(text);
}
-
+
protected void maybeRegisterMessageSent(NotificationRecord r) {
Context appContext = r.getSbn().getPackageContext(getContext());
- Notification.Builder nb =
+ Notification.Builder nb =
Notification.Builder.recoverBuilder(appContext, r.getNotification());
- if (nb.getStyle() instanceof Notification.MessagingStyle) {
+ if (nb.getStyle() instanceof Notification.MessagingStyle && r.getShortcutInfo() == null) {
mPreferencesHelper.setMessageSent(r.getSbn().getPackageName(), r.getUid());
handleSavePolicyFile();
}
@@ -5630,7 +5630,7 @@ public class NotificationManagerService extends SystemService {
if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
channelId = (new Notification.TvExtender(notification)).getChannelId();
}
- String shortcutId = n.getShortcutId(getContext());
+ String shortcutId = n.getShortcutId();
final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
pkg, notificationUid, channelId, shortcutId,
true /* parent ok */, false /* includeDeleted */);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e45b41df38b20..8e3de15982750 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1386,10 +1386,6 @@ public final class NotificationRecord {
|| !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
return false;
}
- if (mShortcutInfo == null && Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 1) {
- return false;
- }
if (mIsNotConversationOverride) {
return false;
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 6d7b410b0b99c..a4b99b376b304 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -116,7 +116,7 @@ public class PreferencesHelper implements RankingConfig {
private static final String ATT_ENABLED = "enabled";
private static final String ATT_USER_ALLOWED = "allowed";
private static final String ATT_HIDE_SILENT = "hide_gentle";
- private static final String ATT_SENT_MESSAGE = "sent_msg";
+ private static final String ATT_SENT_MESSAGE = "sent_invalid_msg";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -194,8 +194,6 @@ public class PreferencesHelper implements RankingConfig {
updateBadgingEnabled();
updateBubblesEnabled();
syncChannelsBypassingDnd(mContext.getUserId());
- mAllowInvalidShortcuts = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0;
}
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
@@ -1313,7 +1311,9 @@ public class PreferencesHelper implements RankingConfig {
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
- if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()) {
+ if (!TextUtils.isEmpty(nc.getConversationId())
+ && !nc.isDeleted()
+ && !nc.isDemoted()) {
ConversationChannelWrapper conversation = new ConversationChannelWrapper();
conversation.setPkg(r.pkg);
conversation.setUid(r.uid);
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 13892ba0e4804..94f69e9c73b3e 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -152,9 +152,13 @@ public class ShortcutHelper {
if (shortcutInfo == null || !shortcutInfo.isLongLived() || !shortcutInfo.isEnabled()) {
return false;
}
- return mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
+ // TODO (b/155016294) uncomment when sharing shortcuts are required
+ /*
+ mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
shortcutInfo.getPackage(), shortcutInfo.getId(), shortcutInfo.getUserId(),
SHARING_FILTER);
+ */
+ return true;
}
/**
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
index a23ade68b344f..77ce2f032a091 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -76,8 +76,6 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagEnabled_looksUpCorrectChannel() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
@@ -96,7 +94,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
NotificationChannel updatedChannel =
new NotificationChannel("a", "", IMPORTANCE_HIGH);
when(mConfig.getConversationNotificationChannel(
- any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)),
+ any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId()),
eq(true), eq(false)))
.thenReturn(updatedChannel);
@@ -106,8 +104,6 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 41748b8a893bb..d5ecfeb55e953 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6589,14 +6589,45 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testRecordMessages() throws RemoteException {
+ public void testRecordMessages_invalidMsg() throws RemoteException {
NotificationRecord nr =
generateMessageBubbleNotifRecord(mTestNotificationChannel,
- "testRecordMessages");
+ "testRecordMessages_invalidMsg");
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
assertTrue(mBinderService.hasSentMessage(PKG, mUid));
}
+
+ @Test
+ public void testRecordMessages_validMsg() throws RemoteException {
+ // Messaging notification with shortcut info
+ Notification.BubbleMetadata metadata =
+ new Notification.BubbleMetadata.Builder("id").build();
+ Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+ null /* groupKey */, false /* isSummary */);
+ nb.setShortcutId("id");
+ nb.setBubbleMetadata(metadata);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Pretend the shortcut exists
+ List shortcutInfos = new ArrayList<>();
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getPackage()).thenReturn(PKG);
+ when(info.getId()).thenReturn("id");
+ when(info.getUserId()).thenReturn(USER_SYSTEM);
+ when(info.isLongLived()).thenReturn(true);
+ when(info.isEnabled()).thenReturn(true);
+ shortcutInfos.add(info);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ assertFalse(mBinderService.hasSentMessage(PKG, mUid));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 3139bfaaf1f58..9f593ce427417 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -123,8 +123,6 @@ public class NotificationRecordTest extends UiServiceTestCase {
when(mMockContext.getResources()).thenReturn(getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.targetSdkVersion = Build.VERSION_CODES.O;
when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
@@ -1127,18 +1125,7 @@ public class NotificationRecordTest extends UiServiceTestCase {
}
@Test
- public void testIsConversation_nullShortcut() {
- StatusBarNotification sbn = getMessagingStyleNotification();
- NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
- record.setShortcutInfo(null);
-
- assertFalse(record.isConversation());
- }
-
- @Test
- public void testIsConversation_bypassShortcutFlagEnabled() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
+ public void testIsConversation_noShortcut() {
StatusBarNotification sbn = getMessagingStyleNotification();
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.setShortcutInfo(null);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index e11392bde9933..4320f1c3c8964 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3022,32 +3022,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
}
- @Test
- public void testPlaceholderConversationId_shortcutNotRequired() throws Exception {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
-
- mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
-
- final String xml = "\n"
- + "\n"
- + ""
- + ""
- + "";
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
- null);
- parser.nextTag();
- mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
- assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
- }
-
@Test
public void testPlaceholderConversationId_shortcutRequired() throws Exception {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
mAppOpsManager);
@@ -3067,8 +3043,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNormalConversationId_shortcutRequired() throws Exception {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
mAppOpsManager);
@@ -3088,8 +3062,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNoConversationId_shortcutRequired() throws Exception {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
mAppOpsManager);
@@ -3275,6 +3247,19 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
}
+ @Test
+ public void testGetConversations_noDemoted() {
+ NotificationChannel parent = new NotificationChannel("parent", "p", 1);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+ NotificationChannel channel =
+ new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT);
+ channel.setConversationId("parent", "convo");
+ channel.setDemoted(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+ assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty();
+ }
+
@Test
public void testGetConversations() {
NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index 3095c87ba2f67..eb2d9fed197fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -40,6 +40,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -184,6 +185,7 @@ public class ShortcutHelperTest extends UiServiceTestCase {
assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isNull();
}
+ @Ignore("b/155016294")
@Test
public void testGetValidShortcutInfo_notSharingShortcut() {
ShortcutInfo si = mock(ShortcutInfo.class);
@@ -229,8 +231,9 @@ public class ShortcutHelperTest extends UiServiceTestCase {
ArrayList shortcuts = new ArrayList<>();
shortcuts.add(si);
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts);
- when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
- anyString(), anyInt(), any())).thenReturn(true);
+ // TODO: b/155016294
+ //when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
+ // anyString(), anyInt(), any())).thenReturn(true);
assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM)).isSameAs(si);
}