Merge "Lock relevant fields on channel update" into oc-dev

This commit is contained in:
Julia Reynolds
2017-05-11 20:55:23 +00:00
committed by Android (Google) Code Review
3 changed files with 212 additions and 74 deletions

View File

@@ -98,21 +98,11 @@ public final class NotificationChannel implements Parcelable {
*/
public static final int USER_LOCKED_SOUND = 0x00000020;
/**
* @hide
*/
public static final int USER_LOCKED_ALLOWED = 0x00000040;
/**
* @hide
*/
public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
/**
* @hide
*/
public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 0x00000100;
/**
* @hide
*/
@@ -123,9 +113,7 @@ public final class NotificationChannel implements Parcelable {
USER_LOCKED_LIGHTS,
USER_LOCKED_VIBRATION,
USER_LOCKED_SOUND,
USER_LOCKED_ALLOWED,
USER_LOCKED_SHOW_BADGE,
USER_LOCKED_AUDIO_ATTRIBUTES
};
private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -270,6 +258,13 @@ public final class NotificationChannel implements Parcelable {
mUserLockedFields |= field;
}
/**
* @hide
*/
public void unlockFields(int field) {
mUserLockedFields &= ~field;
}
/**
* @hide
*/

View File

@@ -48,11 +48,13 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -574,12 +576,8 @@ public class RankingHelper implements RankingConfig {
updateConfig();
}
private void clearLockedFields(NotificationChannel channel) {
int clearMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
clearMask |= NotificationChannel.LOCKABLE_FIELDS[i];
}
channel.lockFields(~clearMask);
void clearLockedFields(NotificationChannel channel) {
channel.unlockFields(channel.getUserLockedFields());
}
@Override
@@ -597,6 +595,7 @@ public class RankingHelper implements RankingConfig {
if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
}
lockFieldsForUpdate(channel, updatedChannel);
r.channels.put(updatedChannel.getId(), updatedChannel);
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
@@ -805,6 +804,35 @@ public class RankingHelper implements RankingConfig {
enabled ? DEFAULT_IMPORTANCE : NotificationManager.IMPORTANCE_NONE);
}
@VisibleForTesting
void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
update.unlockFields(update.getUserLockedFields());
update.lockFields(original.getUserLockedFields());
if (original.canBypassDnd() != update.canBypassDnd()) {
update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
}
if (original.getLockscreenVisibility() != update.getLockscreenVisibility()) {
update.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
}
if (original.getImportance() != update.getImportance()) {
update.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
}
if (original.shouldShowLights() != update.shouldShowLights()
|| original.getLightColor() != update.getLightColor()) {
update.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
}
if (!Objects.equals(original.getSound(), update.getSound())) {
update.lockFields(NotificationChannel.USER_LOCKED_SOUND);
}
if (!Arrays.equals(original.getVibrationPattern(), update.getVibrationPattern())
|| original.shouldVibrate() != update.shouldVibrate()) {
update.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
}
if (original.canShowBadge() != update.canShowBadge()) {
update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
}
}
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;

View File

@@ -55,6 +55,7 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import java.io.BufferedInputStream;
@@ -90,6 +91,7 @@ public class RankingHelperTest {
@Mock NotificationUsageStats mUsageStats;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
@Mock Context mContext;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
@@ -113,60 +115,6 @@ public class RankingHelperTest {
MockitoAnnotations.initMocks(this);
UserHandle user = UserHandle.ALL;
mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
new String[] {ImportanceExtractor.class.getName()});
mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
.setGroup("G")
.setSortKey("B")
.setWhen(1200)
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
.setWhen(1201)
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
.setWhen(1202)
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
mAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build();
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
final ApplicationInfo upgrade = new ApplicationInfo();
@@ -174,6 +122,64 @@ public class RankingHelperTest {
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
when(mContext.getResources()).thenReturn(
InstrumentationRegistry.getContext().getResources());
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getApplicationInfo()).thenReturn(legacy);
mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
new String[] {ImportanceExtractor.class.getName()});
mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
.build();
mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("B")
.setGroup("G")
.setSortKey("B")
.setWhen(1200)
.build();
mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("C")
.setWhen(1201)
.build();
mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("D")
.setWhen(1202)
.build();
mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
null, System.currentTimeMillis()), getDefaultChannel());
mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
.build();
mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
mAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build();
}
private NotificationChannel getDefaultChannel() {
@@ -229,6 +235,10 @@ public class RankingHelperTest {
assertEquals(expected.getName(), actual.getName());
}
private NotificationChannel getChannel() {
return new NotificationChannel("id", "name", IMPORTANCE_LOW);
}
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -643,6 +653,112 @@ public class RankingHelperTest {
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
}
@Test
public void testClearLockedFields() throws Exception {
final NotificationChannel channel = getChannel();
mHelper.clearLockedFields(channel);
assertEquals(0, channel.getUserLockedFields());
channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_IMPORTANCE);
mHelper.clearLockedFields(channel);
assertEquals(0, channel.getUserLockedFields());
}
@Test
public void testLockFields_soundAndVibration() throws Exception {
mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
final NotificationChannel update1 = getChannel();
update1.setSound(new Uri.Builder().scheme("test").build(),
new AudioAttributes.Builder().build());
update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
mHelper.updateNotificationChannel(PKG, UID, update1);
assertEquals(NotificationChannel.USER_LOCKED_SOUND,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
NotificationChannel update2 = getChannel();
update2.enableVibration(true);
mHelper.updateNotificationChannel(PKG, UID, update2);
assertEquals(NotificationChannel.USER_LOCKED_SOUND
| NotificationChannel.USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
.getUserLockedFields());
}
@Test
public void testLockFields_vibrationAndLights() throws Exception {
mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
final NotificationChannel update1 = getChannel();
update1.setVibrationPattern(new long[]{7945, 46 ,246});
mHelper.updateNotificationChannel(PKG, UID, update1);
assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.enableLights(true);
mHelper.updateNotificationChannel(PKG, UID, update2);
assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
| NotificationChannel.USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
.getUserLockedFields());
}
@Test
public void testLockFields_lightsAndImportance() throws Exception {
mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
final NotificationChannel update1 = getChannel();
update1.setLightColor(Color.GREEN);
mHelper.updateNotificationChannel(PKG, UID, update1);
assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.setImportance(IMPORTANCE_DEFAULT);
mHelper.updateNotificationChannel(PKG, UID, update2);
assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
| NotificationChannel.USER_LOCKED_IMPORTANCE,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
.getUserLockedFields());
}
@Test
public void testLockFields_visibilityAndDndAndBadge() throws Exception {
mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
assertEquals(0,
mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
.getUserLockedFields());
final NotificationChannel update1 = getChannel();
update1.setBypassDnd(true);
mHelper.updateNotificationChannel(PKG, UID, update1);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
mHelper.updateNotificationChannel(PKG, UID, update2);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_VISIBILITY,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
.getUserLockedFields());
final NotificationChannel update3 = getChannel();
update3.setShowBadge(false);
mHelper.updateNotificationChannel(PKG, UID, update3);
assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_VISIBILITY
| NotificationChannel.USER_LOCKED_SHOW_BADGE,
mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
.getUserLockedFields());
}
@Test
public void testDeleteNonExistentChannel() throws Exception {
mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
@@ -650,8 +766,7 @@ public class RankingHelperTest {
@Test
public void testGetDeletedChannel() throws Exception {
NotificationChannel channel =
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
NotificationChannel channel = getChannel();
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);