Merge "[Settings] Fix roboletric test fail and add new test case." into udc-dev
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 56d3f0e..369c4f6 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -43,6 +43,7 @@
 import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceScreen;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.applications.AppInfoBase;
@@ -63,8 +64,8 @@
 @SearchIndexable
 public class NotificationAccessSettings extends EmptyTextSettings {
     private static final String TAG = "NotifAccessSettings";
-    private static final String ALLOWED_KEY = "allowed";
-    private static final String NOT_ALLOWED_KEY = "not_allowed";
+    static final String ALLOWED_KEY = "allowed";
+    static final String NOT_ALLOWED_KEY = "not_allowed";
     private static final int MAX_CN_LENGTH = 500;
 
     private static final ManagedServiceSettings.Config CONFIG =
@@ -80,9 +81,9 @@
                     .setEmptyText(R.string.no_notification_listeners)
                     .build();
 
-    private NotificationManager mNm;
+    @VisibleForTesting NotificationManager mNm;
     protected Context mContext;
-    private PackageManager mPm;
+    @VisibleForTesting PackageManager mPm;
     private DevicePolicyManager mDpm;
     private ServiceListing mServiceListing;
     private IconDrawableFactory mIconDrawableFactory;
@@ -102,12 +103,6 @@
                 .setNoun(CONFIG.noun)
                 .setSetting(CONFIG.setting)
                 .setTag(CONFIG.tag)
-                .setValidator(info -> {
-                    if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) {
-                        return false;
-                    }
-                    return true;
-                })
                 .build();
         mServiceListing.addCallback(this::updateList);
 
@@ -140,7 +135,8 @@
         mServiceListing.setListening(false);
     }
 
-    private void updateList(List<ServiceInfo> services) {
+    @VisibleForTesting
+    void updateList(List<ServiceInfo> services) {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         final int managedProfileId = Utils.getManagedProfileId(um, UserHandle.myUserId());
 
@@ -153,6 +149,11 @@
         services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
         for (ServiceInfo service : services) {
             final ComponentName cn = new ComponentName(service.packageName, service.name);
+            boolean isAllowed = mNm.isNotificationListenerAccessGranted(cn);
+            if (!isAllowed && cn.flattenToString().length() > MAX_CN_LENGTH) {
+                continue;
+            }
+
             CharSequence title = null;
             try {
                 title = mPm.getApplicationInfoAsUser(
@@ -200,7 +201,7 @@
                         return true;
                     });
             pref.setKey(cn.flattenToString());
-            if (mNm.isNotificationListenerAccessGranted(cn)) {
+            if (isAllowed) {
                 allowedCategory.addPreference(pref);
             } else {
                 notAllowedCategory.addPreference(pref);
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 7b7d41a..dfb4a45 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -124,6 +124,9 @@
 
     static public CharSequence getDeviceList(ICompanionDeviceManager cdm, LocalBluetoothManager lbm,
             String pkg, int userId) {
+        if (cdm == null) {
+            return "";
+        }
         boolean multiple = false;
         StringBuilder sb = new StringBuilder();
 
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
new file mode 100644
index 0000000..e644c29
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 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.notification.NotificationAccessSettings.ALLOWED_KEY;
+import static com.android.settings.notification.NotificationAccessSettings.NOT_ALLOWED_KEY;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import com.google.common.base.Strings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.ArrayList;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothUtils.class})
+public class NotificationAccessSettingsTest {
+
+    private Context mContext;
+    private NotificationAccessSettings mAccessSettings;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private PackageManager mPackageManager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+        ShadowApplication shadowApp = ShadowApplication.getInstance();
+        shadowApp.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mAccessSettings = new NotificationAccessSettings();
+        FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).setup().get();
+        activity.getSupportFragmentManager().beginTransaction().add(mAccessSettings, null).commit();
+
+        when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).then(
+                (Answer<ApplicationInfo>) invocation -> {
+                    ApplicationInfo appInfo = mock(ApplicationInfo.class);
+                    when(appInfo.loadLabel(any())).thenReturn(invocation.getArgument(0));
+                    return appInfo;
+                });
+
+        mAccessSettings.mNm = mNotificationManager;
+        mAccessSettings.mPm = mPackageManager;
+        ShadowBluetoothUtils.sLocalBluetoothManager = mock(LocalBluetoothManager.class);
+    }
+
+    @Test
+    public void updateList_enabledLongName_shown() {
+        ComponentName longCn = new ComponentName("test.pkg1",
+                Strings.repeat("Blah", 200) + "Service");
+        ComponentName shortCn = new ComponentName("test.pkg2", "ReasonableService");
+        ArrayList<ServiceInfo> services = new ArrayList<>();
+        services.add(newServiceInfo(longCn.getPackageName(), longCn.getClassName(), 1));
+        services.add(newServiceInfo(shortCn.getPackageName(), shortCn.getClassName(), 2));
+        when(mNotificationManager.isNotificationListenerAccessGranted(any())).thenReturn(true);
+
+        mAccessSettings.updateList(services);
+
+        PreferenceScreen screen = mAccessSettings.getPreferenceScreen();
+        PreferenceCategory allowed = checkNotNull(screen.findPreference(ALLOWED_KEY));
+        PreferenceCategory notAllowed = checkNotNull(screen.findPreference(NOT_ALLOWED_KEY));
+        assertThat(allowed.getPreferenceCount()).isEqualTo(2);
+        assertThat(allowed.getPreference(0).getKey()).isEqualTo(longCn.flattenToString());
+        assertThat(allowed.getPreference(1).getKey()).isEqualTo(shortCn.flattenToString());
+        assertThat(notAllowed.getPreferenceCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void updateList_disabledLongName_notShown() {
+        ComponentName longCn = new ComponentName("test.pkg1",
+                Strings.repeat("Blah", 200) + "Service");
+        ComponentName shortCn = new ComponentName("test.pkg2", "ReasonableService");
+        ArrayList<ServiceInfo> services = new ArrayList<>();
+        services.add(newServiceInfo(longCn.getPackageName(), longCn.getClassName(), 1));
+        services.add(newServiceInfo(shortCn.getPackageName(), shortCn.getClassName(), 2));
+        when(mNotificationManager.isNotificationListenerAccessGranted(any())).thenReturn(false);
+
+        mAccessSettings.updateList(services);
+
+        PreferenceScreen screen = mAccessSettings.getPreferenceScreen();
+        PreferenceCategory allowed = checkNotNull(screen.findPreference(ALLOWED_KEY));
+        PreferenceCategory notAllowed = checkNotNull(screen.findPreference(NOT_ALLOWED_KEY));
+        assertThat(allowed.getPreferenceCount()).isEqualTo(0);
+        assertThat(notAllowed.getPreferenceCount()).isEqualTo(1);
+        assertThat(notAllowed.getPreference(0).getKey()).isEqualTo(shortCn.flattenToString());
+    }
+
+    private static ServiceInfo newServiceInfo(String packageName, String serviceName, int uid) {
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.packageName = packageName;
+        serviceInfo.name = serviceName;
+        serviceInfo.applicationInfo = new ApplicationInfo();
+        serviceInfo.applicationInfo.uid = uid;
+        return serviceInfo;
+    }
+}