diff --git a/res/values/strings.xml b/res/values/strings.xml index e4d0d115f0d..90c243a9508 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7668,6 +7668,18 @@ Work notifications + + Automatic Notification Prioritizer + + + Automatically silence and demote less important notifications + + + Smart actions and replies + + + Automatically add contextual notification actions and quick replies to notifications + Hide silent notification status icons diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index 38fa06043fd..e2517d5f553 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -26,6 +26,18 @@ settings:fragment="com.android.settings.notification.NotificationAssistantPicker" settings:controller="com.android.settings.notification.NotificationAssistantPreferenceController"/> + + + + capabilities = mBackend.getAssistantCapabilities(mContext.getPackageName()); + if (PRIORITIZER_KEY.equals(getPreferenceKey())) { + return capabilities.contains(Adjustment.KEY_IMPORTANCE); + } else if (SMART_KEY.equals(getPreferenceKey())) { + return capabilities.contains(Adjustment.KEY_CONTEXTUAL_ACTIONS) + && capabilities.contains(Adjustment.KEY_TEXT_REPLIES); + } + return false; + } + + @Override + public boolean setChecked(boolean isChecked) { + if (PRIORITIZER_KEY.equals(getPreferenceKey())) { + mBackend.allowAssistantCapability(Adjustment.KEY_IMPORTANCE, isChecked); + } else if (SMART_KEY.equals(getPreferenceKey())) { + mBackend.allowAssistantCapability(Adjustment.KEY_CONTEXTUAL_ACTIONS, isChecked); + mBackend.allowAssistantCapability(Adjustment.KEY_TEXT_REPLIES, isChecked); + } + return true; + } + + @Override + public int getAvailabilityStatus() { + return mBackend.getAllowedNotificationAssistant() != null + ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + } +} + + diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index ba07438cab0..42270509148 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -339,6 +339,27 @@ public class NotificationBackend { } } + public void allowAssistantCapability(String capability, boolean allowed) { + try { + if (allowed) { + sINM.allowAssistantCapability(capability); + } else { + sINM.disallowAssistantCapability(capability); + } + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + } + } + + public List getAssistantCapabilities(String pkg) { + try { + return sINM.getAllowedAssistantCapabilities(pkg); + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + } + return new ArrayList<>(); + } + protected void recordAggregatedUsageEvents(Context context, AppRow appRow) { long now = System.currentTimeMillis(); long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK); diff --git a/tests/robotests/src/com/android/settings/notification/AssistantCapabilityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AssistantCapabilityPreferenceControllerTest.java new file mode 100644 index 00000000000..182ce8ae793 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/AssistantCapabilityPreferenceControllerTest.java @@ -0,0 +1,169 @@ +/* + * 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 com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; +import static com.android.settings.notification.AssistantCapabilityPreferenceController.PRIORITIZER_KEY; +import static com.android.settings.notification.AssistantCapabilityPreferenceController.SMART_KEY; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.service.notification.Adjustment; + +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 AssistantCapabilityPreferenceControllerTest { + + @Mock + private NotificationBackend mBackend; + @Mock + private PreferenceScreen mScreen; + + private Context mContext; + private AssistantCapabilityPreferenceController mPrioritizerController; + private AssistantCapabilityPreferenceController mChipController; + private Preference mPrioritizerPreference; + private Preference mChipPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mPrioritizerController = new AssistantCapabilityPreferenceController( + mContext, PRIORITIZER_KEY); + mPrioritizerController.setBackend(mBackend); + mPrioritizerPreference = new Preference(mContext); + mPrioritizerPreference.setKey(mPrioritizerController.getPreferenceKey()); + when(mScreen.findPreference( + mPrioritizerController.getPreferenceKey())).thenReturn(mPrioritizerPreference); + mChipController = new AssistantCapabilityPreferenceController(mContext, SMART_KEY); + mChipController.setBackend(mBackend); + mChipPreference = new Preference(mContext); + mChipPreference.setKey(mChipController.getPreferenceKey()); + when(mScreen.findPreference( + mChipController.getPreferenceKey())).thenReturn(mChipPreference); + } + + @Test + public void getAvailabilityStatus_NAS() { + when(mBackend.getAllowedNotificationAssistant()).thenReturn(mock(ComponentName.class)); + assertThat(mPrioritizerController.getAvailabilityStatus()) + .isEqualTo(AVAILABLE); + assertThat(mChipController.getAvailabilityStatus()) + .isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noNAS() { + when(mBackend.getAllowedNotificationAssistant()).thenReturn(null); + assertThat(mPrioritizerController.getAvailabilityStatus()) + .isEqualTo(DISABLED_DEPENDENT_SETTING); + assertThat(mChipController.getAvailabilityStatus()) + .isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void isChecked_prioritizerSettingIsOff_false() { + List capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_USER_SENTIMENT); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mPrioritizerController.isChecked()).isFalse(); + } + + @Test + public void isChecked_prioritizerSettingIsOn_true() { + List capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_IMPORTANCE); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mPrioritizerController.isChecked()).isTrue(); + } + + @Test + public void isChecked_chipSettingIsOff_false() { + List capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_IMPORTANCE); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mChipController.isChecked()).isFalse(); + + capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_CONTEXTUAL_ACTIONS); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mChipController.isChecked()).isFalse(); + + capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_TEXT_REPLIES); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mChipController.isChecked()).isFalse(); + } + + @Test + public void isChecked_chipSettingIsOn_true() { + List capabilities = new ArrayList<>(); + capabilities.add(Adjustment.KEY_TEXT_REPLIES); + capabilities.add(Adjustment.KEY_CONTEXTUAL_ACTIONS); + when(mBackend.getAssistantCapabilities(anyString())).thenReturn(capabilities); + assertThat(mChipController.isChecked()).isTrue(); + } + + @Test + public void onPreferenceChange_prioritizerOn() { + mPrioritizerController.onPreferenceChange(mPrioritizerPreference, true); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_IMPORTANCE, true); + } + + @Test + public void onPreferenceChange_prioritizerOff() { + mPrioritizerController.onPreferenceChange(mPrioritizerPreference, false); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_IMPORTANCE, false); + } + + @Test + public void onPreferenceChange_chipsOn() { + mChipController.onPreferenceChange(mChipPreference, true); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_CONTEXTUAL_ACTIONS, true); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_TEXT_REPLIES, true); + } + + @Test + public void onPreferenceChange_chipsOff() { + mChipController.onPreferenceChange(mChipPreference, false); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_CONTEXTUAL_ACTIONS, false); + verify(mBackend).allowAssistantCapability(Adjustment.KEY_TEXT_REPLIES, false); + } +} +