Merge "Allow conversations to be demoted out of the conversation space"

This commit is contained in:
Julia Reynolds
2020-01-16 22:23:08 +00:00
committed by Android (Google) Code Review
11 changed files with 106 additions and 23 deletions

View File

@@ -105,6 +105,7 @@ public final class NotificationChannel implements Parcelable {
private static final String ATT_ORIG_IMP = "orig_imp";
private static final String ATT_PARENT_CHANNEL = "parent";
private static final String ATT_CONVERSATION_ID = "conv_id";
private static final String ATT_DEMOTE = "dem";
private static final String DELIMITER = ",";
/**
@@ -194,6 +195,7 @@ public final class NotificationChannel implements Parcelable {
private boolean mImportanceLockedDefaultApp;
private String mParentId = null;
private String mConversationId = null;
private boolean mDemoted = false;
/**
* Creates a notification channel.
@@ -260,6 +262,7 @@ public final class NotificationChannel implements Parcelable {
mOriginalImportance = in.readInt();
mParentId = in.readString();
mConversationId = in.readString();
mDemoted = in.readBoolean();
}
@Override
@@ -317,6 +320,7 @@ public final class NotificationChannel implements Parcelable {
dest.writeInt(mOriginalImportance);
dest.writeString(mParentId);
dest.writeString(mConversationId);
dest.writeBoolean(mDemoted);
}
/**
@@ -386,8 +390,6 @@ public final class NotificationChannel implements Parcelable {
return input;
}
// Modifiable by apps on channel creation.
/**
* @hide
*/
@@ -395,6 +397,8 @@ public final class NotificationChannel implements Parcelable {
mId = id;
}
// Modifiable by apps on channel creation.
/**
* Sets what group this channel belongs to.
*
@@ -766,6 +770,20 @@ public final class NotificationChannel implements Parcelable {
mOriginalImportance = importance;
}
/**
* @hide
*/
public void setDemoted(boolean demoted) {
mDemoted = demoted;
}
/**
* @hide
*/
public boolean isDemoted() {
return mDemoted;
}
/**
* Returns whether the user has chosen the importance of this channel, either to affirm the
* initial selection from the app, or changed it to be higher or lower.
@@ -829,6 +847,7 @@ public final class NotificationChannel implements Parcelable {
setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE));
setConversationId(parser.getAttributeValue(null, ATT_PARENT_CHANNEL),
parser.getAttributeValue(null, ATT_CONVERSATION_ID));
setDemoted(safeBool(parser, ATT_DEMOTE, false));
}
@Nullable
@@ -959,6 +978,9 @@ public final class NotificationChannel implements Parcelable {
if (getConversationId() != null) {
out.attribute(null, ATT_CONVERSATION_ID, getConversationId());
}
if (isDemoted()) {
out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted()));
}
// mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
// truth and so aren't written to this xml file
@@ -1118,7 +1140,8 @@ public final class NotificationChannel implements Parcelable {
&& mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp
&& mOriginalImportance == that.mOriginalImportance
&& Objects.equals(getParentChannelId(), that.getParentChannelId())
&& Objects.equals(getConversationId(), that.getConversationId());
&& Objects.equals(getConversationId(), that.getConversationId())
&& isDemoted() == that.isDemoted();
}
@Override
@@ -1129,7 +1152,7 @@ public final class NotificationChannel implements Parcelable {
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance,
mParentId, mConversationId);
mParentId, mConversationId, mDemoted);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
}
@@ -1176,7 +1199,8 @@ public final class NotificationChannel implements Parcelable {
+ ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ ", mOriginalImp=" + mOriginalImportance
+ ", mParent=" + mParentId
+ ", mConversationId=" + mConversationId;
+ ", mConversationId=" + mConversationId
+ ", mDemoted=" + mDemoted;
}
/** @hide */

View File

@@ -61,7 +61,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
DEFAULT_FLAGS.put("settings_conditionals", "false");
DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
}
/**

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_MIN
import android.service.notification.NotificationListenerService.Ranking
@@ -191,9 +192,9 @@ open class NotificationRankingManager @Inject constructor(
}
private fun NotificationEntry.isPeopleNotification() =
sbn.isPeopleNotification()
private fun StatusBarNotification.isPeopleNotification() =
peopleNotificationIdentifier.isPeopleNotification(this)
sbn.isPeopleNotification(channel)
private fun StatusBarNotification.isPeopleNotification(channel: NotificationChannel) =
peopleNotificationIdentifier.isPeopleNotification(this, channel)
private fun NotificationEntry.isHighPriority() =
highPriorityProvider.isHighPriority(this)

View File

@@ -99,7 +99,8 @@ public class HighPriorityProvider {
}
private boolean isPeopleNotification(NotificationEntry entry) {
return mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn());
return mPeopleNotificationIdentifier.isPeopleNotification(
entry.getSbn(), entry.getChannel());
}
private boolean hasUserSetImportance(NotificationEntry entry) {

View File

@@ -18,13 +18,14 @@ package com.android.systemui.statusbar.notification.people
import android.app.Notification
import android.content.Context
import android.app.NotificationChannel
import android.service.notification.StatusBarNotification
import android.util.FeatureFlagUtils
import javax.inject.Inject
import javax.inject.Singleton
interface PeopleNotificationIdentifier {
fun isPeopleNotification(sbn: StatusBarNotification): Boolean
fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel): Boolean
}
@Singleton
@@ -33,12 +34,13 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
private val context: Context
) : PeopleNotificationIdentifier {
override fun isPeopleNotification(sbn: StatusBarNotification) =
(sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
override fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel) =
((sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
(sbn.notification.shortcutId != null ||
FeatureFlagUtils.isEnabled(
context,
FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ
))) ||
personExtractor.isPersonNotification(sbn)
personExtractor.isPersonNotification(sbn)) &&
!channel.isDemoted
}

View File

@@ -25,6 +25,7 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_BUBBLE;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_DEMOTE;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_FAVORITE;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_HOME;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_MUTE;
@@ -61,6 +62,7 @@ import android.util.Slog;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -151,6 +153,11 @@ public class NotificationConversationInfo extends LinearLayout implements
closeControls(v, true);
};
private OnClickListener mOnDemoteClick = v -> {
mSelectedAction = ACTION_DEMOTE;
closeControls(v, true);
};
public NotificationConversationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -295,6 +302,8 @@ public class NotificationConversationInfo extends LinearLayout implements
mContext.getDrawable(R.drawable.ic_notifications_alert), null, null, null);
}
ImageButton demote = findViewById(R.id.demote);
demote.setOnClickListener(mOnDemoteClick);
}
private void bindHeader() {
@@ -609,7 +618,7 @@ public class NotificationConversationInfo extends LinearLayout implements
}
break;
case ACTION_DEMOTE:
// TODO: when demotion status field exists on notificationchannel
mChannelToUpdate.setDemoted(!mChannelToUpdate.isDemoted());
break;
}

View File

@@ -571,7 +571,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
private NotificationEntry createNotification() {
Notification.Builder n = new Notification.Builder(mContext, "")
Notification.Builder n = new Notification.Builder(mContext, "id")
.setSmallIcon(R.drawable.ic_person)
.setContentTitle("Title")
.setContentText("Text");
@@ -582,6 +582,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
.setUid(TEST_UID)
.setId(mId++)
.setNotification(n.build())
.setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
.setUser(new UserHandle(ActivityManager.getCurrentUser()))
.build();
}
@@ -616,7 +617,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Test
public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
Assert.sMainLooper = TestableLooper.get(this).getLooper();
Notification.Builder n = new Notification.Builder(mContext, "")
Notification.Builder n = new Notification.Builder(mContext, "di")
.setSmallIcon(R.drawable.ic_person)
.setContentTitle("Title")
.setContentText("Text");
@@ -628,6 +629,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
.setId(mId++)
.setNotification(n.build())
.setUser(new UserHandle(ActivityManager.getCurrentUser()))
.setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
.build();
mEntryManager.addActiveNotificationForTest(mEntry);

View File

@@ -60,7 +60,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
final NotificationEntry entry = new NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -75,7 +76,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(true);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -90,7 +92,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
final NotificationEntry entry = new NotificationEntryBuilder()
.setNotification(notification)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -106,7 +109,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -122,7 +126,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_MIN)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(false);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));
@@ -144,7 +149,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setChannel(channel)
.build();
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
.thenReturn(true);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
@@ -81,6 +82,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setNotification(
Notification.Builder(mContext, "test")
.build())
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -94,6 +96,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setNotification(
Notification.Builder(mContext, "test")
.build())
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -116,6 +119,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setOpPkg("pkg")
.setTag("tag")
.setNotification(aN)
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -130,6 +134,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setOpPkg("pkg2")
.setTag("tag")
.setNotification(bN)
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -149,6 +154,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setTag("tag")
.setNotification(notif)
.setUser(mContext.user)
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setOverrideGroupKey("")
.build()
@@ -168,6 +174,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setTag("tag")
.setNotification(notif)
.setUser(mContext.user)
.setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setOverrideGroupKey("")
.build()

View File

@@ -62,6 +62,7 @@ import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
@@ -683,6 +684,34 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
assertFalse(captor.getValue().canBypassDnd());
}
@Test
public void testDemote() throws Exception {
mNotificationInfo.bindNotification(
mShortcutManager,
mLauncherApps,
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
TEST_PACKAGE_NAME,
mNotificationChannel,
mEntry,
null,
null,
null,
true);
ImageButton demote = mNotificationInfo.findViewById(R.id.demote);
demote.performClick();
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> captor =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), anyInt(), captor.capture());
assertTrue(captor.getValue().isDemoted());
}
@Test
public void testMute_mute() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);

View File

@@ -227,6 +227,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(expected.getLightColor(), actual.getLightColor());
assertEquals(expected.getParentChannelId(), actual.getParentChannelId());
assertEquals(expected.getConversationId(), actual.getConversationId());
assertEquals(expected.isDemoted(), actual.isDemoted());
}
private void compareChannelsParentChild(NotificationChannel parent,
@@ -355,6 +356,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
channel2.setLightColor(Color.BLUE);
channel2.setConversationId("id1", "conversation");
channel2.setDemoted(true);
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);