Support ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS in Enhanced Notifications
Show detail settings page from the default NAS app if it implements the new intent ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS.
Test: Robotest, manually test on device
Bug: 231492005
Change-Id: I6566cd9d615331a56728613583295637982bcd3f
Merged-In: I6566cd9d615331a56728613583295637982bcd3f
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 4e58e66..96a3f85 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -156,7 +156,7 @@
android:title="@string/notification_pulse_title"
settings:controller="com.android.settings.notification.PulseNotificationPreferenceController"/>
- <SwitchPreference
+ <com.android.settingslib.PrimarySwitchPreference
android:key="notification_assistant"
android:order="23"
android:title="@string/notification_assistant_title"
diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
index a6179e5..2c02db9 100644
--- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
+++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
@@ -18,35 +18,49 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.NotificationAssistantService;
import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.PrimarySwitchPreference;
import com.google.common.annotations.VisibleForTesting;
+import java.util.List;
+
public class NotificationAssistantPreferenceController extends TogglePreferenceController {
private static final String TAG = "NASPreferenceController";
- private static final String KEY_NAS = "notification_assistant";
+ static final String KEY_NAS = "notification_assistant";
private static final int AVAILABLE = 1;
private final UserManager mUserManager;
+ private final PackageManager mPackageManager;
private Fragment mFragment;
private int mUserId = UserHandle.myUserId();
@VisibleForTesting
protected NotificationBackend mNotificationBackend;
+ private ComponentName mDefaultNASComponent;
+ private Intent mNASSettingIntent;
public NotificationAssistantPreferenceController(Context context) {
super(context, KEY_NAS);
mUserManager = UserManager.get(context);
mNotificationBackend = new NotificationBackend();
+ mPackageManager = context.getPackageManager();
+ getDefaultNASIntent();
}
+
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
@@ -55,14 +69,13 @@
@Override
public boolean isChecked() {
ComponentName acn = mNotificationBackend.getAllowedNotificationAssistant();
- ComponentName dcn = mNotificationBackend.getDefaultNotificationAssistant();
- return (acn != null && acn.equals(dcn));
+ return (acn != null && acn.equals(mDefaultNASComponent));
}
@Override
public boolean setChecked(boolean isChecked) {
ComponentName cn = isChecked
- ? mNotificationBackend.getDefaultNotificationAssistant() : null;
+ ? mDefaultNASComponent : null;
if (isChecked) {
if (mFragment == null) {
throw new IllegalStateException("No fragment to start activity");
@@ -103,8 +116,43 @@
mNotificationBackend = backend;
}
+ @VisibleForTesting
+ void getDefaultNASIntent() {
+ mDefaultNASComponent = mNotificationBackend.getDefaultNotificationAssistant();
+ if (mDefaultNASComponent != null) {
+ mNASSettingIntent = new Intent(
+ NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS);
+ mNASSettingIntent.setPackage(mDefaultNASComponent.getPackageName());
+ mNASSettingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ }
+
@Override
public boolean isSliceable() {
return (mFragment != null && mFragment instanceof ConfigureNotificationSettings);
}
+
+ private boolean isNASSettingActivityAvailable() {
+ final List<ResolveInfo> resolved = mPackageManager.queryIntentActivities(mNASSettingIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL));
+ return (resolved != null && !resolved.isEmpty());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (isNASSettingActivityAvailable()) {
+ preference.setIntent(mNASSettingIntent);
+ } else {
+ // Cannot find settings activity from the default NAS app
+ preference.setIntent(null);
+ preference.setOnPreferenceClickListener(
+ preference1 -> {
+ onPreferenceChange(preference1, !isChecked());
+ ((PrimarySwitchPreference) preference1).setChecked(isChecked());
+ return true;
+ }
+ );
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index d130711..b594667 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -16,7 +16,12 @@
package com.android.settings.notification;
+import static android.service.notification.NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -29,16 +34,24 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.UserManager;
import android.provider.Settings;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
+import com.android.settingslib.PrimarySwitchPreference;
import org.junit.Before;
import org.junit.Test;
@@ -47,9 +60,13 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class NotificationAssistantPreferenceControllerTest {
@@ -67,23 +84,48 @@
private NotificationBackend mBackend;
@Mock
private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
private NotificationAssistantPreferenceController mPreferenceController;
- ComponentName mNASComponent = new ComponentName("a", "b");
+ ComponentName mNASComponent = new ComponentName("pkgname", "clsname");
+ private PrimarySwitchPreference mPreference;
+ private ShadowApplication mShadowApplication;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
- ShadowApplication.getInstance().setSystemService(Context.USER_SERVICE, mUserManager);
+ mPreference = spy(new PrimarySwitchPreference(mContext));
+ mShadowApplication = ShadowApplication.getInstance();
+ mShadowApplication.setSystemService(Context.USER_SERVICE, mUserManager);
doReturn(mContext).when(mFragment).getContext();
when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
when(mBackend.getDefaultNotificationAssistant()).thenReturn(mNASComponent);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
mPreferenceController = new NotificationAssistantPreferenceController(mContext);
mPreferenceController.setBackend(mBackend);
mPreferenceController.setFragment(mFragment);
+ mPreferenceController.getDefaultNASIntent();
+
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference.setKey(NotificationAssistantPreferenceController.KEY_NAS);
+ screen.addPreference(mPreference);
+ mPreferenceController.displayPreference(screen);
+
when(mUserManager.getProfileIds(eq(0), anyBoolean())).thenReturn(new int[] {0, 10});
when(mUserManager.getProfileIds(eq(20), anyBoolean())).thenReturn(new int[] {20});
+
+ ActivityInfo activityInfo1 = new ActivityInfo();
+ activityInfo1.packageName = "pkgname";
+ activityInfo1.name = "name";
+ ResolveInfo resolveInfo1 = new ResolveInfo();
+ resolveInfo1.activityInfo = activityInfo1;
+ List<ResolveInfo> resolvers1 = new ArrayList<>();
+ resolvers1.add(resolveInfo1);
+ when(mPackageManager.queryIntentActivities(any(Intent.class), any()))
+ .thenReturn(resolvers1);
}
@Test
@@ -109,6 +151,34 @@
}
@Test
+ public void testUpdateState_SettingActivityAvailable() throws Exception {
+ mPreferenceController.updateState(mPreference);
+ assertNotNull(mPreference.getIntent());
+
+ mPreference.performClick();
+ Intent nextIntent = Shadows.shadowOf(
+ (Application) ApplicationProvider.getApplicationContext()).getNextStartedActivity();
+ assertEquals(nextIntent.getAction(), ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS);
+ }
+
+ @Test
+ public void testUpdateState_SettingActivityUnavailable() throws Exception {
+ when(mPackageManager.queryIntentActivities(any(Intent.class), any()))
+ .thenReturn(null);
+ mPreferenceController.updateState(mPreference);
+ assertNull(mPreference.getIntent());
+
+ mPreference.performClick();
+ Intent nextIntent = Shadows.shadowOf(
+ (Application) ApplicationProvider.getApplicationContext()).getNextStartedActivity();
+ assertNull(nextIntent);
+ // Verify a dialog is shown
+ verify(mFragmentTransaction).add(
+ any(NotificationAssistantDialogFragment.class), anyString());
+ verify(mBackend, times(0)).setNotificationAssistantGranted(any());
+ }
+
+ @Test
@Config(shadows = ShadowSecureSettings.class)
public void testMigrationFromSetting_userEnable_multiProfile() throws Exception {
Settings.Secure.putIntForUser(mContext.getContentResolver(),