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(),