Use network type enum for APN

Instead of hardcoded names and values.

Bug: 303971237
Test: unit test
Change-Id: I099a408df7ee35abc886ed5c1d2d09fd31fda7d3
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 18f37bf..01a8126 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -416,61 +416,6 @@
         <item>20</item>
     </string-array>
 
-    <!-- Network type used in APN editor -->
-    <string-array name="network_type_entries">
-        <item>Unspecified</item>
-        <item>LTE</item>
-        <item>HSPAP</item>
-        <item>HSPA</item>
-        <item>HSUPA</item>
-        <item>HSDPA</item>
-        <item>UMTS</item>
-        <item>EDGE</item>
-        <item>GPRS</item>
-        <item>eHRPD</item>
-        <item>EVDO_B</item>
-        <item>EVDO_A</item>
-        <item>EVDO_0</item>
-        <item>1xRTT</item>
-        <item>CDMA</item>
-        <item>NR</item>
-    </string-array>
-
-    <string-array translatable="false" name="network_type_values">
-        <!-- Do not translate. -->
-        <item>0</item>
-        <!-- Do not translate. -->
-        <item>13</item>
-        <!-- Do not translate. -->
-        <item>15</item>
-        <!-- Do not translate. -->
-        <item>10</item>
-        <!-- Do not translate. -->
-        <item>9</item>
-        <!-- Do not translate. -->
-        <item>8</item>
-        <!-- Do not translate. -->
-        <item>3</item>
-        <!-- Do not translate. -->
-        <item>2</item>
-        <!-- Do not translate. -->
-        <item>1</item>
-        <!-- Do not translate. -->
-        <item>14</item>
-        <!-- Do not translate. -->
-        <item>12</item>
-        <!-- Do not translate. -->
-        <item>6</item>
-        <!-- Do not translate. -->
-        <item>5</item>
-        <!-- Do not translate. -->
-        <item>7</item>
-        <!-- Do not translate. -->
-        <item>4</item>
-        <!-- Do not translate. -->
-        <item>20</item>
-    </string-array>
-
     <!-- MVNO Info used in APN editor -->
     <string-array name="mvno_type_entries">
         <item>None</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7e6de11..b50f7fd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3123,6 +3123,8 @@
     <string name="bearer">Bearer</string>
     <!-- Edit Network Type Info of APN -->
     <string name="network_type">Network type</string>
+    <!-- Network type unspecified -->
+    <string name="network_type_unspecified">Unspecified</string>
     <!-- Edit Mvno Type Info of APN -->
     <string name="mvno_type">MVNO type</string>
     <!-- Edit Mvno Match Data Info of APN -->
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
index 97d001c..7ffa0c9 100644
--- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -31,6 +31,8 @@
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
 import com.android.settings.R
+import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeDisplayNames
+import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeSelectedOptionsState
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
@@ -51,8 +53,8 @@
 
 object ApnEditPageProvider : SettingsPageProvider {
 
-    override val name = "Apn"
-    const val TAG = "ApnPageProvider"
+    override val name = "ApnEdit"
+    const val TAG = "ApnEditPageProvider"
 
     override val parameter = listOf(
         navArgument(URI_TYPE) { type = NavType.StringType },
@@ -88,12 +90,9 @@
     val context = LocalContext.current
     val authTypeOptions = stringArrayResource(R.array.apn_auth_entries).toList()
     val apnProtocolOptions = stringArrayResource(R.array.apn_protocol_entries).toList()
-    val networkTypeOptionsAll = stringArrayResource(R.array.network_type_entries)
-    val networkTypeOptions = networkTypeOptionsAll.drop(1).toList()
-    val networkTypeEmptyVal = networkTypeOptionsAll[0]
     val mvnoTypeOptions = stringArrayResource(R.array.mvno_type_entries).toList()
     val networkTypeSelectedOptionsState = remember {
-        getNetworkTypeSelectedOptionsState(apnData.networkType, context)
+        getNetworkTypeSelectedOptionsState(apnData.networkType)
     }
     RegularScaffold(
         title = stringResource(id = R.string.apn_edit),
@@ -197,9 +196,9 @@
             )
             SettingsExposedDropdownMenuCheckBox(
                 label = stringResource(R.string.network_type),
-                options = networkTypeOptions,
+                options = getNetworkTypeDisplayNames(),
                 selectedOptionsState = networkTypeSelectedOptionsState,
-                emptyVal = networkTypeEmptyVal,
+                emptyVal = stringResource(R.string.network_type_unspecified),
                 enabled = apnData.networkTypeEnabled
             ) {}
             SettingsExposedDropdownMenuBox(
diff --git a/src/com/android/settings/network/apn/ApnNetworkTypes.kt b/src/com/android/settings/network/apn/ApnNetworkTypes.kt
new file mode 100644
index 0000000..560449a
--- /dev/null
+++ b/src/com/android/settings/network/apn/ApnNetworkTypes.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.network.apn
+
+import android.telephony.TelephonyManager
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.snapshots.SnapshotStateList
+
+object ApnNetworkTypes {
+    private val Types = listOf(
+        TelephonyManager.NETWORK_TYPE_LTE,
+        TelephonyManager.NETWORK_TYPE_HSPAP,
+        TelephonyManager.NETWORK_TYPE_HSPA,
+        TelephonyManager.NETWORK_TYPE_HSUPA,
+        TelephonyManager.NETWORK_TYPE_HSDPA,
+        TelephonyManager.NETWORK_TYPE_UMTS,
+        TelephonyManager.NETWORK_TYPE_EDGE,
+        TelephonyManager.NETWORK_TYPE_GPRS,
+        TelephonyManager.NETWORK_TYPE_EHRPD,
+        TelephonyManager.NETWORK_TYPE_EVDO_B,
+        TelephonyManager.NETWORK_TYPE_EVDO_A,
+        TelephonyManager.NETWORK_TYPE_EVDO_0,
+        TelephonyManager.NETWORK_TYPE_1xRTT,
+        TelephonyManager.NETWORK_TYPE_CDMA,
+        TelephonyManager.NETWORK_TYPE_NR,
+    )
+
+    fun getNetworkTypeDisplayNames(): List<String> =
+        Types.map { TelephonyManager.getNetworkTypeName(it) }
+
+    /**
+     * Gets the selected Network type Selected Options according to network type.
+     * @param networkType Initialized network type bitmask, often multiple network type options may
+     *                    be included.
+     */
+    fun getNetworkTypeSelectedOptionsState(networkType: Long): SnapshotStateList<Int> {
+        val networkTypeSelectedOptionsState = mutableStateListOf<Int>()
+        Types.forEachIndexed { index, type ->
+            if (networkType and TelephonyManager.getBitMaskForNetworkType(type) == 1L) {
+                networkTypeSelectedOptionsState.add(index)
+            }
+        }
+        return networkTypeSelectedOptionsState
+    }
+}
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
index 5a13ede..c8d1b83 100644
--- a/src/com/android/settings/network/apn/ApnStatus.kt
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -16,12 +16,8 @@
 
 package com.android.settings.network.apn
 
-import android.content.Context
 import android.provider.Telephony
 import android.telephony.TelephonyManager
-import androidx.compose.runtime.mutableStateListOf
-import androidx.compose.runtime.snapshots.SnapshotStateList
-import com.android.settings.R
 
 data class ApnData(
     val name: String = "",
@@ -41,7 +37,7 @@
     val apnProtocol: Int = -1,
     val apnRoaming: Int = -1,
     val apnEnable: Boolean = true,
-    val networkType: Int = 0,
+    val networkType: Long = 0,
     val mvnoType: Int = -1,
     var mvnoValue: String = "",
     val edited: Int = Telephony.Carriers.USER_EDITED,
@@ -69,32 +65,3 @@
     var mvnoTypeEnabled = true
     var mvnoValueEnabled = false
 }
-
-/**
- * Initialize the selected Network type Selected Options according to network type.
- * @param networkType Initialized network type bitmask, often multiple network type options may be included.
- * @param context The context to get network type values.
- *
- * @return An error message if the apn data is invalid, otherwise return null.
- */
-fun getNetworkTypeSelectedOptionsState(
-    networkType: Int,
-    context: Context
-): SnapshotStateList<Int> {
-    val networkTypeValues = context.resources.getStringArray(R.array.network_type_values)
-    val networkTypeSelectedOptionsState = mutableStateListOf<Int>()
-    if (networkType != 0) {
-        var i = 1
-        var networkTypeBitMask = networkType
-        while (networkTypeBitMask != 0) {
-            if (networkTypeBitMask and 1 == 1 && !networkTypeSelectedOptionsState.contains(i)) {
-                networkTypeSelectedOptionsState.add(networkTypeValues.indexOf("$i") - 1)
-            }
-            networkTypeBitMask = networkTypeBitMask shr 1
-            i++
-        }
-    }
-    return networkTypeSelectedOptionsState
-}
-
-
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
index f6b2342..8902c73 100644
--- a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
@@ -58,7 +58,6 @@
     private val apnProtocolOptions =
         context.resources.getStringArray(R.array.apn_protocol_entries).toList()
     private val networkType = context.resources.getString(R.string.network_type)
-    private val networkTypeOptions = context.resources.getStringArray(R.array.network_type_entries).toList()
     private val passwordTitle = context.resources.getString(R.string.apn_password)
     private val apnData = mutableStateOf(
         ApnData(
@@ -74,7 +73,7 @@
 
     @Test
     fun apnEditPageProvider_name() {
-        Truth.assertThat(ApnEditPageProvider.name).isEqualTo("Apn")
+        Truth.assertThat(ApnEditPageProvider.name).isEqualTo("ApnEdit")
     }
 
     @Test
@@ -218,9 +217,10 @@
         composeTestRule.onRoot().onChild().onChildAt(0)
             .performScrollToNode(hasText(networkType, true))
         composeTestRule.onNodeWithText(networkType, true).performClick()
-        composeTestRule.onNodeWithText(networkTypeOptions[1], true).performClick()
-        composeTestRule.onNode(hasText(networkTypeOptions[0]) and isFocused(), true).assertDoesNotExist()
-        composeTestRule.onNode(hasText(networkTypeOptions[1]) and isFocused(), true).assertIsDisplayed()
+        composeTestRule.onNodeWithText(NETWORK_TYPE_LTE, true).performClick()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_UNSPECIFIED) and isFocused(), true)
+            .assertDoesNotExist()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_LTE) and isFocused(), true).assertIsDisplayed()
     }
 
     @Test
@@ -235,12 +235,14 @@
         composeTestRule.onRoot().onChild().onChildAt(0)
             .performScrollToNode(hasText(networkType, true))
         composeTestRule.onNodeWithText(networkType, true).performClick()
-        composeTestRule.onNodeWithText(networkTypeOptions[1], true).performClick()
-        composeTestRule.onNode(hasText(networkTypeOptions[0]) and isFocused(), true).assertDoesNotExist()
-        composeTestRule.onNode(hasText(networkTypeOptions[1]) and isFocused(), true).assertIsDisplayed()
-        composeTestRule.onAllNodesWithText(networkTypeOptions[1], true).onLast().performClick()
-        composeTestRule.onNode(hasText(networkTypeOptions[0]) and isFocused(), true).assertIsDisplayed()
-        composeTestRule.onNode(hasText(networkTypeOptions[1]) and isFocused(), true).assertDoesNotExist()
+        composeTestRule.onNodeWithText(NETWORK_TYPE_LTE, true).performClick()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_UNSPECIFIED) and isFocused(), true)
+            .assertDoesNotExist()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_LTE) and isFocused(), true).assertIsDisplayed()
+        composeTestRule.onAllNodesWithText(NETWORK_TYPE_LTE, true).onLast().performClick()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_UNSPECIFIED) and isFocused(), true)
+            .assertIsDisplayed()
+        composeTestRule.onNode(hasText(NETWORK_TYPE_LTE) and isFocused(), true).assertDoesNotExist()
     }
 
     @Test
@@ -254,4 +256,9 @@
             .performScrollToNode(hasText(passwordTitle, true))
         composeTestRule.onNodeWithText(passwordTitle, true).assertIsDisplayed()
     }
-}
\ No newline at end of file
+    
+    private companion object {
+        const val NETWORK_TYPE_UNSPECIFIED = "Unspecified"
+        const val NETWORK_TYPE_LTE = "LTE"
+    }
+}