Migrate to using fixed permissions

When deciding which app/group/channel level fields are editable. If
an app has a fixed notification permission, no importance type fields
(including blocking, importance, minimizing, popping on screen, or
prioirty conversions) can be edited.

Test: Robotests
Bug: 194833441
Change-Id: Idc198ea05cd2ab6e43387ae4e8290f446ccfa0c6
This commit is contained in:
Julia Reynolds
2021-10-29 08:19:10 -04:00
parent e3f34ef7db
commit a024c10517
21 changed files with 272 additions and 211 deletions

View File

@@ -16,6 +16,9 @@
package com.android.settings.notification;
import static android.os.UserHandle.USER_SYSTEM;
import static android.provider.Settings.*;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -24,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.app.role.RoleManager;
import android.app.usage.UsageEvents;
import android.bluetooth.BluetoothAdapter;
@@ -33,6 +37,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Parcel;
import android.provider.Settings;
import com.android.settings.notification.NotificationBackend.AppRow;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -63,11 +68,16 @@ public class NotificationBackendTest {
@Mock
CachedBluetoothDeviceManager mCbm;
ComponentName mCn = new ComponentName("a", "b");
@Mock
INotificationManager mInm;
NotificationBackend mNotificationBackend;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mBm.getCachedDeviceManager()).thenReturn(mCbm);
mNotificationBackend = new NotificationBackend();
mNotificationBackend.setNm(mInm);
}
@Test
@@ -101,6 +111,46 @@ public class NotificationBackendTest {
assertTrue(appRow.systemApp);
}
@Test
public void testMarkAppRow_fixedPermission() throws Exception {
Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
PackageInfo pi = new PackageInfo();
pi.packageName = "test";
pi.applicationInfo = new ApplicationInfo();
pi.applicationInfo.packageName = "test";
pi.applicationInfo.uid = 123;
when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(true);
AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application,
mock(PackageManager.class), mock(RoleManager.class), pi);
assertTrue(appRow.systemApp);
assertTrue(appRow.lockedImportance);
}
@Test
public void testMarkAppRow_notFixedPermission() throws Exception {
Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
PackageInfo pi = new PackageInfo();
pi.packageName = "test";
pi.applicationInfo = new ApplicationInfo();
pi.applicationInfo.packageName = "test";
pi.applicationInfo.uid = 123;
when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false);
AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application,
mock(PackageManager.class), mock(RoleManager.class), pi);
assertFalse(appRow.systemApp);
assertFalse(appRow.lockedImportance);
}
@Test
public void testMarkAppRow_notDefaultPackage() {
PackageInfo pi = new PackageInfo();

View File

@@ -165,20 +165,6 @@ public class AllowSoundPreferenceControllerTest {
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_notBlockable_oem() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getId()).thenReturn("");
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_configurable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();

View File

@@ -217,20 +217,6 @@ public class BadgePreferenceControllerTest {
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_channelNotBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getId()).thenReturn("");
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();

View File

@@ -200,68 +200,40 @@ public class BlockPreferenceControllerTest {
}
@Test
public void testIsEnabled_lockedApp() {
public void testIsEnabled_cannotBlockAppOrGroupOrChannel() {
mController.setOverrideCanBlock(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
appRow.systemApp = true;
mController.onResume(appRow, null, null, null, null, null, null);
mController.updateState(mPreference);
assertFalse(mPreference.getSwitchBar().isEnabled());
}
@Test
public void testIsEnabled_GroupNotBlockable() {
public void testIsEnabled_importanceLocked_app() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
mController.onResume(appRow, null, mock(NotificationChannelGroup.class), null, null, null,
null);
mController.updateState(mPreference);
assertFalse(mPreference.getSwitchBar().isEnabled());
}
@Test
public void testIsEnabled_systemAppNotBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
mController.onResume(appRow, null, null, null, null, null, null);
mController.updateState(mPreference);
assertFalse(mPreference.getSwitchBar().isEnabled());
}
@Test
public void testIsEnabled_systemAppBlockable() {
public void testIsEnabled_importanceLocked_group() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
channel.setBlockable(true);
mController.onResume(appRow, channel, null, null, null, null, null);
mController.onResume(
appRow, null, new NotificationChannelGroup("a", "a"), null, null, null, null);
mController.updateState(mPreference);
assertTrue(mPreference.getSwitchBar().isEnabled());
}
@Test
public void testIsEnabled_lockedChannel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
mController.updateState(mPreference);
assertFalse(mPreference.getSwitchBar().isEnabled());
}
@Test
public void testIsEnabled_defaultAppChannel() {
public void testIsEnabled_importanceLocked_channel() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
mController.onResume(appRow, new NotificationChannel("a", "a", IMPORTANCE_LOW), null, null,
null, null, null);
mController.updateState(mPreference);
assertFalse(mPreference.getSwitchBar().isEnabled());
}

View File

@@ -297,21 +297,6 @@ public class BubblePreferenceControllerTest {
assertFalse(pref.isEnabled());
}
@Test
public void updateState_channel_channelNotBlockable() {
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.pkg = "a";
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void updateState_channel() {
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);

View File

@@ -146,9 +146,9 @@ public class ConversationPriorityPreferenceControllerTest {
@Test
public void testUpdateState_notConfigurable() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -159,26 +159,10 @@ public class ConversationPriorityPreferenceControllerTest {
}
@Test
public void testUpdateState_systemButConfigurable() {
public void testUpdateState_Configurable() {
mController.setOverrideCanConfigure(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(false);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new ConversationPriorityPreference(mContext, null);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_defaultApp() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);

View File

@@ -138,8 +138,8 @@ public class DndPreferenceControllerTest {
@Test
public void testUpdateState_notBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);

View File

@@ -166,9 +166,9 @@ public class HighImportancePreferenceControllerTest {
@Test
public void testUpdateState_notConfigurable() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -179,26 +179,10 @@ public class HighImportancePreferenceControllerTest {
}
@Test
public void testUpdateState_systemButConfigurable() {
public void testUpdateState_Configurable() {
mController.setOverrideCanConfigure(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(false);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_defaultApp() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);

View File

@@ -183,9 +183,9 @@ public class ImportancePreferenceControllerTest {
@Test
public void testUpdateState_notConfigurable() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -196,26 +196,10 @@ public class ImportancePreferenceControllerTest {
}
@Test
public void testUpdateState_systemButConfigurable() {
public void testUpdateState_Configurable() {
mController.setOverrideCanConfigure(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(false);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new ImportancePreference(mContext, null);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_defaultApp() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);

View File

@@ -181,19 +181,6 @@ public class LightsPreferenceControllerTest {
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_notBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_lightsOn() {
NotificationChannel channel = mock(NotificationChannel.class);

View File

@@ -166,9 +166,9 @@ public class MinImportancePreferenceControllerTest {
@Test
public void testUpdateState_notConfigurable() {
mController.setOverrideCanConfigure(false);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -179,26 +179,11 @@ public class MinImportancePreferenceControllerTest {
}
@Test
public void testUpdateState_systemButConfigurable() {
public void testUpdateState_Configurable() {
mController.setOverrideCanConfigure(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(false);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_defaultApp() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.systemApp = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
when(channel.isBlockable()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null, null, null, null);

View File

@@ -22,6 +22,7 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.os.UserHandle.USER_SYSTEM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -38,6 +39,7 @@ import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;
import androidx.preference.Preference;
@@ -221,6 +223,109 @@ public class NotificationPreferenceControllerTest {
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
}
@Test
public void testIsChannelBlockable_postMigration_locked() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
assertFalse(mController.isChannelBlockable());
}
@Test
public void testIsChannelBlockable_postMigration_locked_butChannelOff() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
mController.onResume(appRow, channel, null, null, null, null, null);
assertTrue(mController.isChannelBlockable());
}
@Test
public void testIsChannelBlockable_postMigration_locked_butChannelBlockable() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isBlockable()).thenReturn(true);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
assertTrue(mController.isChannelBlockable());
}
@Test
public void testIsChannelGroupBlockable_postMigration_locked() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannelGroup channelGroup = mock(NotificationChannelGroup.class);
mController.onResume(appRow, null, channelGroup, null, null, null, null);
assertFalse(mController.isChannelGroupBlockable());
}
@Test
public void testIsChannelGroupBlockable_postMigration_locked_butChannelGroupOff() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
NotificationChannelGroup channelGroup = mock(NotificationChannelGroup.class);
when(channelGroup.isBlocked()).thenReturn(true);
mController.onResume(appRow, null, channelGroup, null, null, null, null);
assertTrue(mController.isChannelGroupBlockable());
}
@Test
public void testIsAppBlockable_postMigration_locked() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
appRow.banned = false;
mController.onResume(appRow, null, null, null, null, null, null);
assertFalse(mController.isAppBlockable());
}
@Test
public void testIsAppBlockable_postMigration_locked_butAppOff() {
Settings.Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
mController = new TestPreferenceController(mContext, mBackend);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedImportance = true;
appRow.banned = true;
mController.onResume(appRow, null, null, null, null, null, null);
assertFalse(mController.isAppBlockable());
}
@Test
public void testIsBlockable_oemAllowlist() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();

View File

@@ -182,20 +182,6 @@ public class SoundPreferenceControllerTest {
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_notBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
Preference pref = new NotificationSoundPreference(mContext, attributeSet);
mController.updateState(pref);
assertTrue(pref.isEnabled());
}
@Test
public void testUpdateState_configurable() {
Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI;

View File

@@ -162,10 +162,9 @@ public class VibrationPreferenceControllerTest {
}
@Test
public void testUpdateState_notBlockable() {
public void testUpdateState_blockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.isImportanceLockedByOEM()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);