[Settings] Code refactor - SIM slot UI preference key

Avoid from controlling Preference key separately in different places.

Bug: 261374879
Test: local & auto
Change-Id: I0a777c3f2511a25e8f619deba964bc343183c3cc
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 128ceca..e48d745 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -41,6 +41,7 @@
 import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
 import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController;
 import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceController;
+import com.android.settings.deviceinfo.simstatus.SlotSimStatus;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -104,14 +105,12 @@
             Context context, MyDeviceInfoFragment fragment, Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
 
-        String simStatusKey = SimStatusPreferenceController.KEY_SIM_STATUS;
-        SimStatusPreferenceController defaultRecord =
-            new SimStatusPreferenceController(context, simStatusKey);
-
-        for (int slotIndex = 0; slotIndex < defaultRecord.getSimSlotSize(); slotIndex ++) {
+        final SlotSimStatus slotSimStatus = new SlotSimStatus(context);
+        for (int slotIndex = 0; slotIndex < slotSimStatus.size(); slotIndex ++) {
             SimStatusPreferenceController slotRecord =
-                new SimStatusPreferenceController(context, simStatusKey + slotIndex + 1);
-            slotRecord.init(fragment, slotIndex);
+                    new SimStatusPreferenceController(context,
+                    slotSimStatus.getPreferenceKey(slotIndex));
+            slotRecord.init(fragment, slotSimStatus);
             controllers.add(slotRecord);
         }
 
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
index 529d314..3ea8cb4 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.os.UserManager;
 
 import androidx.annotation.VisibleForTesting;
@@ -38,39 +37,28 @@
 
 public class SimStatusPreferenceController extends BasePreferenceController {
 
-    public static final String KEY_SIM_STATUS = "sim_status";
     private static final String KEY_PREFERENCE_CATEGORY = "device_detail_category";
 
-    private final TelephonyManager mTelephonyManager;
     private final SubscriptionManager mSubscriptionManager;
     private final List<Preference> mPreferenceList = new ArrayList<>();
 
     private Fragment mFragment;
-    private int mSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+    private SlotSimStatus mSlotSimStatus;
 
     public SimStatusPreferenceController(Context context, String prefKey) {
         super(context, prefKey);
 
-        mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
     }
 
     /**
      * Initialize this preference controller.
      * @param fragment parent fragment
-     * @param slotIndex index of slot
+     * @param slotSimStatus SlotSimStatus object
      */
-    public void init(Fragment fragment, int slotIndex) {
+    public void init(Fragment fragment, SlotSimStatus slotSimStatus) {
         mFragment = fragment;
-        mSlotIndex = slotIndex;
-    }
-
-    /**
-     * Get number of subscription slots.
-     * @return number of slots
-     */
-    public int getSimSlotSize() {
-        return isAvailable() ? mTelephonyManager.getPhoneCount() : 0;
+        mSlotSimStatus = slotSimStatus;
     }
 
     /**
@@ -78,14 +66,12 @@
      * @return index of slot
      */
     public int getSimSlotIndex() {
-        return mSlotIndex;
+        return mSlotSimStatus == null ? SubscriptionManager.INVALID_SIM_SLOT_INDEX :
+                mSlotSimStatus.findSlotIndexByKey(getPreferenceKey());
     }
 
     @Override
     public int getAvailabilityStatus() {
-        if (getSimSlotIndex() == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            return UNSUPPORTED_ON_DEVICE;
-        }
         boolean isAvailable = SubscriptionUtil.isSimHardwareVisible(mContext) &&
                 mContext.getSystemService(UserManager.class).isAdminUser() &&
                 !Utils.isWifiOnly(mContext);
@@ -98,23 +84,24 @@
         if (!SubscriptionUtil.isSimHardwareVisible(mContext)) {
             return;
         }
-        final Preference preference = screen.findPreference(KEY_SIM_STATUS);
+        String basePreferenceKey = mSlotSimStatus.getPreferenceKey(
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        final Preference preference = screen.findPreference(basePreferenceKey);
         if (!isAvailable() || preference == null || !preference.isVisible()) {
             return;
         }
         final PreferenceCategory category = screen.findPreference(KEY_PREFERENCE_CATEGORY);
 
-        final int simStatusOrder = preference.getOrder();
+        mSlotSimStatus.setBasePreferenceOrdering(preference.getOrder());
         screen.removePreference(preference);
         preference.setVisible(false);
 
         // Add additional preferences for each sim in the device
-        for (int simSlotNumber = 0; simSlotNumber < mTelephonyManager.getPhoneCount();
-                simSlotNumber++) {
+        for (int simSlotNumber = 0; simSlotNumber < mSlotSimStatus.size(); simSlotNumber++) {
             final Preference multiSimPreference = createNewPreference(screen.getContext());
             multiSimPreference.setCopyingEnabled(true);
-            multiSimPreference.setOrder(simStatusOrder + simSlotNumber + 1);
-            multiSimPreference.setKey(KEY_SIM_STATUS + simSlotNumber + 1);
+            multiSimPreference.setOrder(mSlotSimStatus.getPreferenceOrdering(simSlotNumber));
+            multiSimPreference.setKey(mSlotSimStatus.getPreferenceKey(simSlotNumber));
             category.addPreference(multiSimPreference);
             mPreferenceList.add(multiSimPreference);
         }
@@ -141,7 +128,7 @@
     }
 
     private String getPreferenceTitle(int simSlot) {
-        return mTelephonyManager.getPhoneCount() > 1 ? mContext.getString(
+        return mSlotSimStatus.size() > 1 ? mContext.getString(
                 R.string.sim_status_title_sim_slot, simSlot + 1) : mContext.getString(
                 R.string.sim_status_title);
     }
diff --git a/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java b/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java
new file mode 100644
index 0000000..7056181
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 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.deviceinfo.simstatus;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+/**
+ * A class for showing a summary of status of sim slots.
+ */
+public class SlotSimStatus {
+
+    private static final String TAG = "SlotSimStatus";
+
+    private int mNumberOfSlots;
+    private int mBasePreferenceOrdering;
+
+    private static final String KEY_SIM_STATUS = "sim_status";
+
+    /**
+     * Construct of class.
+     * @param context Context
+     */
+    public SlotSimStatus(Context context) {
+        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
+        if (telMgr == null) {
+            return;
+        }
+        mNumberOfSlots = telMgr.getPhoneCount();
+    }
+
+    /**
+     * Set base ordering of Preference.
+     * @param baseOrdering the base ordering for SIM Status within "About Phone".
+     */
+    public void setBasePreferenceOrdering(int baseOrdering) {
+        mBasePreferenceOrdering = baseOrdering;
+    }
+
+    /**
+     * Number of slots available.
+     * @return number of slots
+     */
+    public int size() {
+        return mNumberOfSlots;
+    }
+
+    /**
+     * Get ordering of Preference based on index of slot.
+     * @param slotIndex index of slot
+     * @return Preference ordering.
+     */
+    public int getPreferenceOrdering(int slotIndex) {
+        return mBasePreferenceOrdering + 1 + slotIndex;
+    }
+
+    /**
+     * Get key of Preference and PreferenceController based on index of slot.
+     * @param slotIndex index of slot
+     * @return Preference key.
+     */
+    public String getPreferenceKey(int slotIndex) {
+        if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+            return KEY_SIM_STATUS;
+        }
+        return KEY_SIM_STATUS + (1 + slotIndex);
+    }
+
+    /**
+     * Get slot index based on Preference key
+     * @param prefKey is the preference key
+     * @return slot index.
+     */
+    public int findSlotIndexByKey(String prefKey) {
+        int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX + 1;
+        try {
+            simSlotIndex = Integer.parseInt(prefKey.substring(KEY_SIM_STATUS.length()));
+        } catch (Exception exception) {
+            Log.w(TAG, "Preference key invalid: " + prefKey +
+                       ". Error Msg: " + exception.getMessage());
+        }
+        return simSlotIndex - 1;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
index 0ca5fd2..9d4956d 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
@@ -72,6 +72,7 @@
 
     private Context mContext;
     private Resources mResources;
+    private SlotSimStatus mSlotSimStatus;
     private SimStatusPreferenceController mController;
 
     @Before
@@ -105,13 +106,13 @@
         final String prefKey = mController.getPreferenceKey();
         when(mPreference.getKey()).thenReturn(prefKey);
         when(mPreference.isVisible()).thenReturn(true);
-
-        mController.init(mFragment, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
     }
 
     @Test
     public void displayPreference_multiSim_shouldAddSecondPreference() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        mController.init(mFragment, slotSimStatus);
 
         mController.displayPreference(mScreen);
 
@@ -121,6 +122,8 @@
     @Test
     public void updateState_singleSim_shouldSetSingleSimTitleAndSummary() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(1);
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        mController.init(mFragment, slotSimStatus);
         mController.displayPreference(mScreen);
 
         mController.updateState(mPreference);
@@ -132,6 +135,8 @@
     @Test
     public void updateState_multiSim_shouldSetMultiSimTitleAndSummary() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        mController.init(mFragment, slotSimStatus);
         mController.displayPreference(mScreen);
 
         mController.updateState(mPreference);
@@ -149,6 +154,8 @@
         when(mFragment.getChildFragmentManager()).thenReturn(
                 mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS));
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        mController.init(mFragment, slotSimStatus);
         mController.displayPreference(mScreen);
 
         mController.handlePreferenceTreeClick(mFirstSimPreference);
diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java
new file mode 100644
index 0000000..1a4e740
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.deviceinfo.simstatus;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class SlotSimStatusTest {
+
+    @Mock
+    private TelephonyManager mTelephonyManager;
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
+    }
+
+    @Test
+    public void size_returnNumberOfPhone_whenQuery() {
+        doReturn(2).when(mTelephonyManager).getPhoneCount();
+
+        SlotSimStatus target = new SlotSimStatus(mContext);
+
+        assertEquals(new Integer(target.size()), new Integer(2));
+    }
+
+    @Test
+    public void getPreferenceOrdering_returnOrdering_whenQuery() {
+        doReturn(2).when(mTelephonyManager).getPhoneCount();
+
+        SlotSimStatus target = new SlotSimStatus(mContext);
+        target.setBasePreferenceOrdering(30);
+
+        assertEquals(new Integer(target.getPreferenceOrdering(1)), new Integer(32));
+    }
+
+    @Test
+    public void getPreferenceKey_returnKey_whenQuery() {
+        doReturn(2).when(mTelephonyManager).getPhoneCount();
+
+        SlotSimStatus target = new SlotSimStatus(mContext);
+        target.setBasePreferenceOrdering(50);
+
+        assertEquals(target.getPreferenceKey(1), "sim_status52");
+    }
+
+    private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
+        when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
+        when(mContext.getSystemService(serviceName)).thenReturn(service);
+    }
+}