diff --git a/res/values/strings.xml b/res/values/strings.xml index 5e4cac6b69c..d09851a3241 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7976,6 +7976,32 @@ When work profile is locked + + + Notifications on lockscreen + + + Show alerting and silent notifications + + + Show alerting notifications only + + + Don\u2019t show notifications + + + Sensitive notifications + + + Show sensitive content when locked + + + Sensitive work profile notifications + + + Show sensitive work profile content when locked + diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index 687fe832cbe..224a9107414 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -26,27 +26,52 @@ settings:controller="com.android.settings.widget.VideoPreferenceController" android:persistent="false" /> - + + - + + + + + + + + + + + + android:key="lock_screen_redact" + android:title="@string/lock_screen_notifs_redact" + android:summary="@string/lock_screen_notifs_redact_summary" + settings:controller="com.android.settings.notification.RedactNotificationPreferenceController" /> + + + - - - - + - - - - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java index 5f9cf5fc25a..d21be1607bc 100644 --- a/src/com/android/settings/notification/ConfigureNotificationSettings.java +++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java @@ -57,17 +57,9 @@ public class ConfigureNotificationSettings extends DashboardFragment implements OnActivityResultListener { private static final String TAG = "ConfigNotiSettings"; - @VisibleForTesting - static final String KEY_LOCKSCREEN = "lock_screen_notifications"; - @VisibleForTesting - static final String KEY_LOCKSCREEN_WORK_PROFILE_HEADER = - "lock_screen_notifications_profile_header"; - @VisibleForTesting - static final String KEY_LOCKSCREEN_WORK_PROFILE = "lock_screen_notifications_profile"; @VisibleForTesting static final String KEY_SWIPE_DOWN = "gesture_swipe_down_fingerprint_notifications"; - @VisibleForTesting - static final String KEY_NOTIFICATION_ASSISTANT = "notification_assistant"; + static final String KEY_LOCKSCREEN = "lock_screen_notifications"; private static final String KEY_NOTI_DEFAULT_RINGTONE = "notification_default_ringtone"; private static final int REQUEST_CODE = 200; @@ -100,25 +92,18 @@ public class ConfigureNotificationSettings extends DashboardFragment implements } else { app = null; } - return buildPreferenceControllers(context, getSettingsLifecycle(), app, this); + return buildPreferenceControllers(context, app, this); } private static List buildPreferenceControllers(Context context, - Lifecycle lifecycle, Application app, Fragment host) { + Application app, Fragment host) { final List controllers = new ArrayList<>(); - final LockScreenNotificationPreferenceController lockScreenNotificationController = - new LockScreenNotificationPreferenceController(context, - KEY_LOCKSCREEN, - KEY_LOCKSCREEN_WORK_PROFILE_HEADER, - KEY_LOCKSCREEN_WORK_PROFILE); - if (lifecycle != null) { - lifecycle.addObserver(lockScreenNotificationController); - } controllers.add(new RecentNotifyingAppsPreferenceController( context, new NotificationBackend(), IUsageStatsManager.Stub.asInterface( ServiceManager.getService(Context.USAGE_STATS_SERVICE)), context.getSystemService(UserManager.class), app, host)); - controllers.add(lockScreenNotificationController); + controllers.add(new ShowOnLockScreenNotificationPreferenceController( + context, KEY_LOCKSCREEN)); controllers.add(new NotificationRingtonePreferenceController(context) { @Override public String getPreferenceKey() { @@ -245,7 +230,7 @@ public class ConfigureNotificationSettings extends DashboardFragment implements @Override public List createPreferenceControllers( Context context) { - return buildPreferenceControllers(context, null, null, null); + return buildPreferenceControllers(context, null, null); } @Override diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java index d5e17233a72..8b5b7617fe9 100644 --- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java +++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java @@ -71,7 +71,7 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC static final String KEY_DIVIDER = "all_notifications_divider"; @VisibleForTesting static final String KEY_SEE_ALL = "all_notifications"; - private static final int SHOW_RECENT_APP_COUNT = 5; + private static final int SHOW_RECENT_APP_COUNT = 3; private static final int DAYS = 3; private static final Set SKIP_SYSTEM_PACKAGES = new ArraySet<>(); diff --git a/src/com/android/settings/notification/RedactNotificationPreferenceController.java b/src/com/android/settings/notification/RedactNotificationPreferenceController.java new file mode 100644 index 00000000000..94d7fc1f0d1 --- /dev/null +++ b/src/com/android/settings/notification/RedactNotificationPreferenceController.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 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.settings.notification; + +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; + +import android.app.KeyguardManager; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.Utils; +import com.android.settings.core.TogglePreferenceController; +import com.android.settings.overlay.FeatureFactory; + +public class RedactNotificationPreferenceController extends TogglePreferenceController { + + private static final String TAG = "LockScreenNotifPref"; + + static final String KEY_LOCKSCREEN_REDACT = "lock_screen_redact"; + static final String KEY_LOCKSCREEN_WORK_PROFILE_REDACT = "lock_screen_work_redact"; + + private DevicePolicyManager mDpm; + private UserManager mUm; + private KeyguardManager mKm; + private final int mProfileUserId; + + public RedactNotificationPreferenceController(Context context, String settingKey) { + super(context, settingKey); + + mUm = context.getSystemService(UserManager.class); + mDpm = context.getSystemService(DevicePolicyManager.class); + mKm = context.getSystemService(KeyguardManager.class); + + mProfileUserId = Utils.getManagedProfileId(mUm, UserHandle.myUserId()); + } + + @Override + public boolean isChecked() { + int userId = KEY_LOCKSCREEN_REDACT.equals(getPreferenceKey()) + ? UserHandle.myUserId() : mProfileUserId; + + return getAllowPrivateNotifications(userId); + } + + @Override + public boolean setChecked(boolean isChecked) { + int userId = KEY_LOCKSCREEN_REDACT.equals(getPreferenceKey()) + ? UserHandle.myUserId() : mProfileUserId; + + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, isChecked ? 1 : 0, userId); + return true; + } + + @Override + public int getAvailabilityStatus() { + // hide work profile setting if no work profile + if (KEY_LOCKSCREEN_WORK_PROFILE_REDACT.equals(getPreferenceKey()) + && mProfileUserId == UserHandle.USER_NULL) { + return CONDITIONALLY_UNAVAILABLE; + } + + int userId = KEY_LOCKSCREEN_REDACT.equals(getPreferenceKey()) + ? UserHandle.myUserId() : mProfileUserId; + + // hide if lockscreen isn't secure for this user + final LockPatternUtils utils = FeatureFactory.getFactory(mContext) + .getSecurityFeatureProvider() + .getLockPatternUtils(mContext); + if (!utils.isSecure(userId)) { + return CONDITIONALLY_UNAVAILABLE; + } + + // all notifs hidden? admin doesn't allow notifs or redacted notifs? disabled + if (!getLockscreenNotificationsEnabled(userId) + || !adminAllowsNotifications(userId) + || !adminAllowsUnredactedNotifications(userId)) { + return DISABLED_DEPENDENT_SETTING; + } + + // specifically the work profile setting requires the work profile to be unlocked + if (KEY_LOCKSCREEN_WORK_PROFILE_REDACT.equals(getPreferenceKey())) { + if (mKm.isDeviceLocked(mProfileUserId)) { + return DISABLED_DEPENDENT_SETTING; + } + } + + return AVAILABLE; + } + + private boolean adminAllowsNotifications(int userId) { + final int dpmFlags = mDpm.getKeyguardDisabledFeatures(null/* admin */, userId); + return (dpmFlags & KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0; + } + + private boolean adminAllowsUnredactedNotifications(int userId) { + final int dpmFlags = mDpm.getKeyguardDisabledFeatures(null/* admin */, userId); + return (dpmFlags & KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0; + } + + private boolean getAllowPrivateNotifications(int userId) { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1, userId) != 0; + } + + private boolean getLockscreenNotificationsEnabled(int userId) { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, userId) != 0; + } +} diff --git a/src/com/android/settings/notification/ShowOnLockScreenNotificationPreferenceController.java b/src/com/android/settings/notification/ShowOnLockScreenNotificationPreferenceController.java new file mode 100644 index 00000000000..5d08ac796d1 --- /dev/null +++ b/src/com/android/settings/notification/ShowOnLockScreenNotificationPreferenceController.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2019 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.settings.notification; + +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; + +import com.android.settings.R; +import com.android.settings.RestrictedListPreference; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtilsInternal; +import com.android.settingslib.core.AbstractPreferenceController; + +import com.google.common.annotations.VisibleForTesting; + +import java.util.ArrayList; + +import androidx.preference.Preference; + +public class ShowOnLockScreenNotificationPreferenceController extends AbstractPreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { + + private static final String TAG = "LockScreenNotifPref"; + + private final String mSettingKey; + private DevicePolicyManager mDpm; + + public ShowOnLockScreenNotificationPreferenceController(Context context, String settingKey) { + super(context); + mSettingKey = settingKey; + mDpm = context.getSystemService(DevicePolicyManager.class); + } + + @VisibleForTesting + void setDpm(DevicePolicyManager dpm) { + mDpm = dpm; + } + + @Override + public String getPreferenceKey() { + return mSettingKey; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void updateState(Preference preference) { + RestrictedListPreference pref = (RestrictedListPreference) preference; + pref.clearRestrictedItems(); + ArrayList entries = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + + String showAllEntry = + mContext.getString(R.string.lock_screen_notifs_show_all); + String showAllEntryValue = + Integer.toString(R.string.lock_screen_notifs_show_all); + entries.add(showAllEntry); + values.add(showAllEntryValue); + setRestrictedIfNotificationFeaturesDisabled(pref, showAllEntry, showAllEntryValue, + KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); + + String alertingEntry = mContext.getString(R.string.lock_screen_notifs_show_alerting); + String alertingEntryValue = Integer.toString(R.string.lock_screen_notifs_show_alerting); + entries.add(alertingEntry); + values.add(alertingEntryValue); + setRestrictedIfNotificationFeaturesDisabled(pref, alertingEntry, alertingEntryValue, + KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); + + entries.add(mContext.getString(R.string.lock_screen_notifs_show_none)); + values.add(Integer.toString(R.string.lock_screen_notifs_show_none)); + + pref.setEntries(entries.toArray(new CharSequence[entries.size()])); + pref.setEntryValues(values.toArray(new CharSequence[values.size()])); + + if (!adminAllowsNotifications() || !getLockscreenNotificationsEnabled()) { + pref.setValue(Integer.toString(R.string.lock_screen_notifs_show_none)); + } else if (!getLockscreenSilentNotificationsEnabled()) { + pref.setValue(Integer.toString(R.string.lock_screen_notifs_show_alerting)); + } else { + pref.setValue(Integer.toString(R.string.lock_screen_notifs_show_all)); + } + + pref.setOnPreferenceChangeListener(this); + + refreshSummary(preference); + } + + @Override + public CharSequence getSummary() { + if (!adminAllowsNotifications() || !getLockscreenNotificationsEnabled()) { + return mContext.getString(R.string.lock_screen_notifs_show_none); + } else if (!getLockscreenSilentNotificationsEnabled()) { + return mContext.getString(R.string.lock_screen_notifs_show_alerting); + } else { + return mContext.getString(R.string.lock_screen_notifs_show_all); + } + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final int val = Integer.parseInt((String) newValue); + final boolean enabled = val != R.string.lock_screen_notifs_show_none; + final boolean show = val == R.string.lock_screen_notifs_show_all; + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, show ? 1 : 0); + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, enabled ? 1 : 0); + refreshSummary(preference); + return true; + } + + private void setRestrictedIfNotificationFeaturesDisabled(RestrictedListPreference pref, + CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures) { + RestrictedLockUtils.EnforcedAdmin admin = + RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled( + mContext, keyguardNotificationFeatures, UserHandle.myUserId()); + if (admin != null && pref != null) { + RestrictedListPreference.RestrictedItem item = + new RestrictedListPreference.RestrictedItem(entry, entryValue, admin); + pref.addRestrictedItem(item); + } + } + + private boolean adminAllowsNotifications() { + final int dpmFlags = mDpm.getKeyguardDisabledFeatures(null/* admin */); + return (dpmFlags & KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0; + } + + private boolean getLockscreenNotificationsEnabled() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; + } + + private boolean getLockscreenSilentNotificationsEnabled() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0) != 0; + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ConfigureNotificationSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ConfigureNotificationSettingsTest.java index 69102971f17..523b496f648 100644 --- a/tests/robotests/src/com/android/settings/notification/ConfigureNotificationSettingsTest.java +++ b/tests/robotests/src/com/android/settings/notification/ConfigureNotificationSettingsTest.java @@ -16,14 +16,7 @@ package com.android.settings.notification; -import static com.android.settings.notification.ConfigureNotificationSettings.KEY_LOCKSCREEN; -import static com.android.settings.notification.ConfigureNotificationSettings - .KEY_LOCKSCREEN_WORK_PROFILE; -import static com.android.settings.notification.ConfigureNotificationSettings - .KEY_LOCKSCREEN_WORK_PROFILE_HEADER; -import static com.android.settings.notification.ConfigureNotificationSettings.KEY_SWIPE_DOWN; -import static com.android.settings.notification.ConfigureNotificationSettings - .SUMMARY_PROVIDER_FACTORY; +import static com.android.settings.notification.ConfigureNotificationSettings.SUMMARY_PROVIDER_FACTORY; import static com.google.common.truth.Truth.assertThat; @@ -37,8 +30,6 @@ import android.app.Activity; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.notification.ConfigureNotificationSettings.SummaryProvider; -import com.android.settings.testutils.shadow.ShadowLockPatternUtils; -import com.android.settings.testutils.shadow.ShadowUtils; import org.junit.Before; import org.junit.Test; @@ -46,10 +37,6 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.List; @RunWith(RobolectricTestRunner.class) public class ConfigureNotificationSettingsTest { @@ -61,20 +48,6 @@ public class ConfigureNotificationSettingsTest { mActivity = spy(Robolectric.buildActivity(Activity.class).get()); } - @Test - @Config(shadows = { - ShadowUtils.class, - ShadowLockPatternUtils.class - }) - public void getNonIndexableKeys_shouldContainLockScreenPrefs() { - final List keys = ConfigureNotificationSettings.SEARCH_INDEX_DATA_PROVIDER - .getNonIndexableKeys(RuntimeEnvironment.application); - - assertThat(keys).containsAllOf( - KEY_SWIPE_DOWN, KEY_LOCKSCREEN, KEY_LOCKSCREEN_WORK_PROFILE, - KEY_LOCKSCREEN_WORK_PROFILE_HEADER); - } - @Test public void getSummary_noneBlocked() { SummaryLoader loader = mock(SummaryLoader.class); diff --git a/tests/robotests/src/com/android/settings/notification/RedactNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RedactNotificationPreferenceControllerTest.java new file mode 100644 index 00000000000..49f6bd6a420 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/RedactNotificationPreferenceControllerTest.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2019 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.settings.notification; + +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; +import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.KeyguardManager; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.service.notification.Adjustment; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.testutils.FakeFeatureFactory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.List; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +@RunWith(RobolectricTestRunner.class) +public class RedactNotificationPreferenceControllerTest { + + @Mock + private DevicePolicyManager mDpm; + @Mock + UserManager mUm; + @Mock + KeyguardManager mKm; + @Mock + private PreferenceScreen mScreen; + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private Context mMockContext; + + private Context mContext; + private RedactNotificationPreferenceController mController; + private RedactNotificationPreferenceController mWorkController; + private Preference mPreference; + private Preference mWorkPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); + when(featureFactory.securityFeatureProvider.getLockPatternUtils(mMockContext)) + .thenReturn(mLockPatternUtils); + when(mMockContext.getContentResolver()).thenReturn(mContext.getContentResolver()); + when(mMockContext.getSystemService(UserManager.class)).thenReturn(mUm); + when(mMockContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDpm); + when(mMockContext.getSystemService(KeyguardManager.class)).thenReturn(mKm); + when(mUm.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {10}); + + mController = new RedactNotificationPreferenceController( + mMockContext, RedactNotificationPreferenceController.KEY_LOCKSCREEN_REDACT); + mPreference = new Preference(mContext); + mPreference.setKey(mController.getPreferenceKey()); + when(mScreen.findPreference( + mController.getPreferenceKey())).thenReturn(mPreference); + + mWorkController = new RedactNotificationPreferenceController(mMockContext, + RedactNotificationPreferenceController.KEY_LOCKSCREEN_WORK_PROFILE_REDACT); + mWorkPreference = new Preference(mContext); + mWorkPreference.setKey(mWorkController.getPreferenceKey()); + when(mScreen.findPreference( + mWorkController.getPreferenceKey())).thenReturn(mWorkPreference); + } + + @Test + public void getAvailabilityStatus_noSecureLockscreen() { + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 10); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_noWorkProfile() { + // reset controllers with no work profile + when(mUm.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {UserHandle.USER_NULL}); + mWorkController = new RedactNotificationPreferenceController(mMockContext, + RedactNotificationPreferenceController.KEY_LOCKSCREEN_WORK_PROFILE_REDACT); + mController = new RedactNotificationPreferenceController(mMockContext, + RedactNotificationPreferenceController.KEY_LOCKSCREEN_REDACT); + + // should otherwise show + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_adminSaysNoRedaction() { + when(mDpm.getKeyguardDisabledFeatures(eq(null), anyInt())).thenReturn( + KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS); + + // should otherwise show + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 10); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_adminSaysNoNotifications() { + when(mDpm.getKeyguardDisabledFeatures(eq(null), anyInt())).thenReturn( + KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); + + // should otherwise show + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 10); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_noNotifications() { + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 0, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 0, 10); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_workProfileLocked() { + // should otherwise show + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 10); + + when(mKm.isDeviceLocked(10)).thenReturn(true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_show() { + // should otherwise show + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1, 10); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + assertThat(mWorkController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void isChecked() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 1, 0); + + assertThat(mController.isChecked()).isTrue(); + + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 0, 0); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void isChecked_work() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 1, 10); + + assertThat(mWorkController.isChecked()).isTrue(); + + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 0, 10); + + assertThat(mWorkController.isChecked()).isFalse(); + } + + @Test + public void setChecked_false() throws Exception { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 1, 0); + + mController.setChecked(false); + assertThat(Settings.Secure.getIntForUser( + mContext.getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0)) + .isEqualTo(0); + } + + @Test + public void setChecked_workProfile_false() throws Exception { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 1, 10); + + mWorkController.setChecked(false); + assertThat(Settings.Secure.getIntForUser( + mContext.getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 10)) + .isEqualTo(0); + } + + @Test + public void setChecked_true() throws Exception { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 0, 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, + 0, 10); + + mController.setChecked(true); + mWorkController.setChecked(true); + assertThat(Settings.Secure.getIntForUser( + mContext.getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 10)) + .isEqualTo(1); + assertThat(Settings.Secure.getIntForUser( + mContext.getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0)) + .isEqualTo(1); + } +} + diff --git a/tests/robotests/src/com/android/settings/notification/ShowOnLockscreenNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ShowOnLockscreenNotificationPreferenceControllerTest.java new file mode 100644 index 00000000000..6907051ea86 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ShowOnLockscreenNotificationPreferenceControllerTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2019 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.settings.notification; + +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; +import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; +import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.R; +import com.android.settings.RestrictedListPreference; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal; +import com.android.settings.testutils.shadow.ShadowUserManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; + +import androidx.preference.PreferenceScreen; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class, ShadowRestrictedLockUtilsInternal.class}) +public class ShowOnLockscreenNotificationPreferenceControllerTest { + + private Context mContext; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PreferenceScreen mScreen; + @Mock + DevicePolicyManager mDpm; + + private ShowOnLockScreenNotificationPreferenceController mController; + private RestrictedListPreference mPreference; + + private static final String KEY = "key"; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new ShowOnLockScreenNotificationPreferenceController(mContext, KEY); + mPreference = new RestrictedListPreference( + mContext, Robolectric.buildAttributeSet().build()); + mPreference.setKey(mController.getPreferenceKey()); + when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); + mController.setDpm(mDpm); + } + + @Test + public void display_shouldDisplay() { + assertThat(mPreference.isVisible()).isTrue(); + } + + @Test + public void updateState_noNotifsOnLockscreen() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 0); + // should be ignored + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 1); + + mController.updateState(mPreference); + + assertThat(mPreference.getValue()).isEqualTo( + String.valueOf(R.string.lock_screen_notifs_show_none)); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_none)); + } + + @Test + public void updateState_alertingNotifsOnLockscreen() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 0); + + mController.updateState(mPreference); + + assertThat(mPreference.getValue()).isEqualTo( + String.valueOf(R.string.lock_screen_notifs_show_alerting)); + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_alerting)); + } + + @Test + public void updateState_allNotifsOnLockscreen() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 1); + + mController.updateState(mPreference); + + assertThat(mPreference.getValue()).isEqualTo( + String.valueOf(R.string.lock_screen_notifs_show_all)); + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_all)); + } + + @Test + public void updateState_dpmSaysNo() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 1); + + when(mDpm.getKeyguardDisabledFeatures(null)) + .thenReturn(KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); + ShadowRestrictedLockUtilsInternal.setKeyguardDisabledFeatures( + KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); + + mController.updateState(mPreference); + + assertThat(mPreference.getValue()).isEqualTo( + String.valueOf(R.string.lock_screen_notifs_show_none)); + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_none)); + + assertThat(mPreference.isRestrictedForEntry( + mContext.getString(R.string.lock_screen_notifs_show_all))).isTrue(); + assertThat(mPreference.isRestrictedForEntry( + mContext.getString(R.string.lock_screen_notifs_show_alerting))).isTrue(); + } + + @Test + public void onPreferenceChange_allToAlerting() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 1); + + mController.onPreferenceChange(mPreference, + Integer.toString(R.string.lock_screen_notifs_show_alerting)); + + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)).isEqualTo(1); + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1)).isEqualTo(0); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_alerting)); + } + + @Test + public void onPreferenceChange_noneToAll() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 0); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 0); + + mController.onPreferenceChange(mPreference, + Integer.toString(R.string.lock_screen_notifs_show_all)); + + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)).isEqualTo(1); + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1)).isEqualTo(1); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_all)); + } + + @Test + public void onPreferenceChange_alertingToNone() { + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, + 1); + Settings.Secure.putInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, + 0); + + mController.onPreferenceChange(mPreference, + Integer.toString(R.string.lock_screen_notifs_show_none)); + + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)).isEqualTo(0); + assertThat(Settings.Secure.getInt(mContext.getContentResolver(), + LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1)).isEqualTo(0); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getString(R.string.lock_screen_notifs_show_none)); + } +}