Merge "Call detect anomaly in period job only when there is new battery usage data." into udc-qpr-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fa4b27a..3529b0b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -659,6 +659,7 @@
         <activity android:name="Settings$FaceSettingsActivity"
             android:label="@string/security_settings_face_preference_title"
             android:exported="true"
+            android:theme="@style/Theme.Settings.NoActionBar"
             android:icon="@drawable/ic_face_header">
             <intent-filter>
                 <action android:name="android.settings.FACE_SETTINGS" />
@@ -673,6 +674,7 @@
         <activity android:name="Settings$FaceSettingsInternalActivity"
                   android:label="@string/security_settings_face_preference_title"
                   android:exported="false"
+                  android:theme="@style/Theme.Settings.NoActionBar"
                   android:icon="@drawable/ic_face_header"
                   android:taskAffinity="com.android.settings.root">
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 1fd09a3..e76b92e 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -69,7 +69,9 @@
     private static final String ENABLE_DUAL_MODE_AUDIO =
             "persist.bluetooth.enable_dual_mode_audio";
     private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
-    private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
+    private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
+    private static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
+            "persist.bluetooth.leaudio.toggle_visible";
 
     private LocalBluetoothManager mManager;
     private LocalBluetoothProfileManager mProfileManager;
@@ -464,15 +466,13 @@
     private void updateLeAudioConfig() {
         mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
                 SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
-        boolean isLeDeviceDetailEnabled = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
-                LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+        boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
+                LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
         boolean isLeEnabledByDefault = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
                 CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
-        mIsLeAudioToggleEnabled = isLeDeviceDetailEnabled || isLeEnabledByDefault;
+        mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
         Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
-                + ", BT_LE_AUDIO_DEVICE_DETAIL_ENABLED:" + isLeDeviceDetailEnabled
+                + ", LE_AUDIO_TOGGLE_VISIBLE_PROPERTY:" + isLeAudioToggleVisible
                 + ", CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT:" + isLeEnabledByDefault);
     }
 
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 404b0b4..94074df 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -42,9 +42,4 @@
      * {@code true} whether or not event_log for generic actions is enabled. Default is true.
      */
     public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
-    /**
-     * {@code true} whether to show LE Audio toggle in device detail page. Default is false.
-     */
-    public static final String BT_LE_AUDIO_DEVICE_DETAIL_ENABLED =
-            "bt_le_audio_device_detail_enabled";
 }
diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
index 298ced0..980bdaa 100644
--- a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
+import android.os.SystemProperties;
 import android.provider.DeviceConfig;
 
 import androidx.annotation.VisibleForTesting;
@@ -27,7 +28,6 @@
 import androidx.preference.SwitchPreference;
 
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
 
 /**
@@ -40,9 +40,12 @@
 
     private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
     private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
-    private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
+    private static final boolean LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE = true;
     static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
 
+    static final String LE_AUDIO_TOGGLE_VISIBLE_PROPERTY =
+            "persist.bluetooth.leaudio.toggle_visible";
+
     @VisibleForTesting
     BluetoothAdapter mBluetoothAdapter;
 
@@ -73,10 +76,7 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean isEnabled = (Boolean) newValue;
-        DeviceConfig.setProperty(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
-                isEnabled ? "true" : "false", LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+        SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, Boolean.toString(isEnabled));
         return true;
     }
 
@@ -86,25 +86,13 @@
             return;
         }
 
-        final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
-                LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
+        final boolean isLeAudioToggleVisible = SystemProperties.getBoolean(
+                LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, LE_AUDIO_TOGGLE_VISIBLE_DEFAULT_VALUE);
         final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
 
         mPreference.setEnabled(!leAudioEnabledByDefault);
-        ((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled
+        ((SwitchPreference) mPreference).setChecked(isLeAudioToggleVisible
                 || leAudioEnabledByDefault);
     }
-
-    @Override
-    protected void onDeveloperOptionsSwitchDisabled() {
-        super.onDeveloperOptionsSwitchDisabled();
-        // Reset the toggle to null when the developer option is disabled
-        DeviceConfig.setProperty(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null",
-                LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
-    }
 }
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 0cd12fe..9974ba2 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -18,7 +18,6 @@
 
 import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
-
 import static com.android.internal.util.CollectionUtils.emptyIfNull;
 
 import android.annotation.Nullable;
@@ -56,6 +55,8 @@
 import java.util.Set;
 import java.util.function.Function;
 import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -66,6 +67,9 @@
     static final String SUB_ID = "sub_id";
     @VisibleForTesting
     static final String KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME = "unique_subscription_displayName";
+    private static final String REGEX_DISPLAY_NAME_PREFIXES = "^";
+    private static final String REGEX_DISPLAY_NAME_SUFFIXES = "\\s[0-9]+";
+
     private static List<SubscriptionInfo> sAvailableResultsForTesting;
     private static List<SubscriptionInfo> sActiveResultsForTesting;
 
@@ -281,8 +285,8 @@
                             String displayName = i.getDisplayName().toString();
                             info.originalName =
                                     TextUtils.equals(displayName, PROFILE_GENERIC_DISPLAY_NAME)
-                                    ? context.getResources().getString(R.string.sim_card)
-                                    : displayName.trim();
+                                            ? context.getResources().getString(R.string.sim_card)
+                                            : displayName.trim();
                             return info;
                         });
 
@@ -298,12 +302,17 @@
         // If a display name is duplicate, append the final 4 digits of the phone number.
         // Creates a mapping of Subscription id to original display name + phone number display name
         final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
+            int infoSubId = info.subscriptionInfo.getSubscriptionId();
             String cachedDisplayName = getDisplayNameFromSharedPreference(
-                    context, info.subscriptionInfo.getSubscriptionId());
-            if (!TextUtils.isEmpty(cachedDisplayName)) {
-                Log.d(TAG, "use cached display name : " + cachedDisplayName);
+                    context, infoSubId);
+            if (isValidCachedDisplayName(cachedDisplayName, info.originalName.toString())) {
+                Log.d(TAG, "use cached display name : for subId : " + infoSubId
+                        + "cached display name : " + cachedDisplayName);
                 info.uniqueName = cachedDisplayName;
                 return info;
+            } else {
+                Log.d(TAG, "remove cached display name : " + infoSubId);
+                removeItemFromDisplayNameSharedPreference(context, infoSubId);
             }
 
             if (duplicateOriginalNames.contains(info.originalName)) {
@@ -320,9 +329,8 @@
                 } else {
                     info.uniqueName = info.originalName + " " + lastFourDigits;
                     Log.d(TAG, "Cache display name [" + info.uniqueName + "] for sub id "
-                            + info.subscriptionInfo.getSubscriptionId());
-                    saveDisplayNameToSharedPreference(
-                            context, info.subscriptionInfo.getSubscriptionId(), info.uniqueName);
+                            + infoSubId);
+                    saveDisplayNameToSharedPreference(context, infoSubId, info.uniqueName);
                 }
             } else {
                 info.uniqueName = info.originalName;
@@ -404,10 +412,27 @@
                 .apply();
     }
 
+    private static void removeItemFromDisplayNameSharedPreference(Context context, int subId) {
+        getDisplayNameSharedPreferenceEditor(context)
+                .remove(SUB_ID + subId)
+                .commit();
+    }
+
     private static String getDisplayNameFromSharedPreference(Context context, int subid) {
         return getDisplayNameSharedPreferences(context).getString(SUB_ID + subid, "");
     }
 
+    @VisibleForTesting
+    static boolean isValidCachedDisplayName(String cachedDisplayName, String originalName) {
+        if (TextUtils.isEmpty(cachedDisplayName) || TextUtils.isEmpty(originalName)) {
+            return false;
+        }
+        String regex = REGEX_DISPLAY_NAME_PREFIXES + originalName + REGEX_DISPLAY_NAME_SUFFIXES;
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(cachedDisplayName);
+        return matcher.matches();
+    }
+
     public static String getDisplayName(SubscriptionInfo info) {
         final CharSequence name = info.getDisplayName();
         if (name != null) {
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
index b405f9e..13bc6a4 100644
--- a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.development;
 
+import static com.android.settings.development.BluetoothLeAudioDeviceDetailsPreferenceController
+        .LE_AUDIO_TOGGLE_VISIBLE_PROPERTY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
@@ -25,12 +28,11 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
-import android.provider.DeviceConfig;
+import android.os.SystemProperties;
 
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
-import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settings.testutils.shadow.ShadowDeviceConfig;
 
 import org.junit.After;
@@ -77,9 +79,8 @@
     public void onPreferenceChanged_settingEnabled_shouldTurnOnLeAudioDeviceDetailSetting() {
         mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
         mController.onPreferenceChange(mPreference, true /* new value */);
-        final boolean isEnabled = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+        final boolean isEnabled = SystemProperties.getBoolean(
+                LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, false);
 
         assertThat(isEnabled).isTrue();
     }
@@ -88,9 +89,8 @@
     public void onPreferenceChanged_settingDisabled_shouldTurnOffLeAudioDeviceDetailSetting() {
         mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
         mController.onPreferenceChange(mPreference, false /* new value */);
-        final boolean isEnabled = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+        final boolean isEnabled = SystemProperties.getBoolean(
+                LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, true);
 
         assertThat(isEnabled).isFalse();
     }
@@ -98,18 +98,15 @@
     @Test
     public void updateState_settingEnabled_preferenceShouldBeChecked() {
         mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "true", false);
+        SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "true");
         mController.updateState(mPreference);
-
         verify(mPreference).setChecked(true);
     }
 
     @Test
     public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
         mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "false", false);
+        SystemProperties.set(LE_AUDIO_TOGGLE_VISIBLE_PROPERTY, "false");
         mController.updateState(mPreference);
 
         verify(mPreference).setChecked(false);
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
index f063042..587e734 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -18,9 +18,7 @@
 
 import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
 import static com.android.settings.network.SubscriptionUtil.SUB_ID;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -185,7 +183,7 @@
     @Ignore
     @Test
     public void getUniqueDisplayNames_identicalCarriers_fourDigitsUsed() {
-        // Both subscriptoins have the same display name.
+        // Both subscriptions have the same display name.
         final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
         when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -215,7 +213,7 @@
     @Ignore
     @Test
     public void getUniqueDisplayNames_identicalCarriersAfterTrim_fourDigitsUsed() {
-        // Both subscriptoins have the same display name.
+        // Both subscriptions have the same display name.
         final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
         when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -244,8 +242,8 @@
 
     @Ignore
     @Test
-    public void getUniqueDisplayNames_phoneNumberBlocked_subscriptoinIdFallback() {
-        // Both subscriptoins have the same display name.
+    public void getUniqueDisplayNames_phoneNumberBlocked_subscriptionIdFallback() {
+        // Both subscriptions have the same display name.
         final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
         when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -273,9 +271,9 @@
 
     @Ignore
     @Test
-    public void getUniqueDisplayNames_phoneNumberIdentical_subscriptoinIdFallback() {
+    public void getUniqueDisplayNames_phoneNumberIdentical_subscriptionIdFallback() {
         // TODO have three here from the same carrier
-        // Both subscriptoins have the same display name.
+        // Both subscriptions have the same display name.
         final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
         final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
@@ -464,8 +462,8 @@
         SharedPreferences sp = mock(SharedPreferences.class);
         when(mContext.getSharedPreferences(
                 KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
-        when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + "6789");
-        when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + "4321");
+        when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
+        when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
 
 
         final CharSequence nameOfSub1 =
@@ -475,8 +473,41 @@
 
         assertThat(nameOfSub1).isNotNull();
         assertThat(nameOfSub2).isNotNull();
-        assertEquals(CARRIER_1 + "6789", nameOfSub1.toString());
-        assertEquals(CARRIER_1 + "4321", nameOfSub2.toString());
+        assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
+        assertEquals(CARRIER_1 + " 4321", nameOfSub2.toString());
+    }
+
+    @Test
+    public void getUniqueDisplayName_hasRecordAndNameIsChanged_doesNotUseRecordBeTheResult() {
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+        when(info2.getSubscriptionId()).thenReturn(SUBID_2);
+        when(info1.getDisplayName()).thenReturn(CARRIER_1);
+        when(info2.getDisplayName()).thenReturn(CARRIER_2);
+        when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(
+                Arrays.asList(info1, info2));
+
+        SharedPreferences sp = mock(SharedPreferences.class);
+        SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+        when(mContext.getSharedPreferences(
+                KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
+        when(sp.edit()).thenReturn(editor);
+        when(editor.remove(anyString())).thenReturn(editor);
+
+        when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
+        when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
+
+
+        final CharSequence nameOfSub1 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(info1, mContext);
+        final CharSequence nameOfSub2 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(info2, mContext);
+
+        assertThat(nameOfSub1).isNotNull();
+        assertThat(nameOfSub2).isNotNull();
+        assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
+        assertEquals(CARRIER_2.toString(), nameOfSub2.toString());
     }
 
     @Test
@@ -501,4 +532,60 @@
 
         assertTrue(SubscriptionUtil.isSimHardwareVisible(mContext));
     }
+
+    @Test
+    public void isValidCachedDisplayName_matchesRule1_returnTrue() {
+        String originalName = "originalName";
+        String cacheString = "originalName 1234";
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_matchesRule2_returnTrue() {
+        String originalName = "original Name";
+        String cacheString = originalName + " " + 1234;
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_nameIsEmpty1_returnFalse() {
+        String originalName = "original Name";
+        String cacheString = "";
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_nameIsEmpty2_returnFalse() {
+        String originalName = "";
+        String cacheString = "originalName 1234";
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_nameIsDifferent_returnFalse() {
+        String originalName = "original Name";
+        String cacheString = "originalName 1234";
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_noNumber_returnFalse() {
+        String originalName = "original Name";
+        String cacheString = originalName;
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+    }
+
+    @Test
+    public void isValidCachedDisplayName_noSpace_returnFalse() {
+        String originalName = "original Name";
+        String cacheString = originalName;
+
+        assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
+    }
 }