Merge changes from topic "hide-phone-number" into main

* changes:
  Phone number only available if telephony capable
  Phone number only available for admin users
  Added unit test for MobileNetworkPhoneNumberPreferenceController visibility
  Added unit tests for PhoneNumberPreferenceController visibility
This commit is contained in:
Aleksander Morgado
2025-02-13 00:06:32 -08:00
committed by Android (Google) Code Review
4 changed files with 126 additions and 16 deletions

View File

@@ -17,6 +17,7 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import android.content.Context; import android.content.Context;
import android.os.UserManager;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@@ -30,6 +31,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.SubscriptionUtil;
import com.android.settingslib.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -51,8 +53,13 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return SubscriptionUtil.isSimHardwareVisible(mContext) ? if (!SubscriptionUtil.isSimHardwareVisible(mContext) || Utils.isWifiOnly(mContext)) {
AVAILABLE : UNSUPPORTED_ON_DEVICE; return UNSUPPORTED_ON_DEVICE;
}
if (!mContext.getSystemService(UserManager.class).isAdminUser()) {
return DISABLED_FOR_USER;
}
return AVAILABLE;
} }
@Override @Override

View File

@@ -25,6 +25,8 @@ import com.android.settings.R
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.android.settingslib.Utils
/** Preference controller for "Phone number" */ /** Preference controller for "Phone number" */
class MobileNetworkPhoneNumberPreferenceController class MobileNetworkPhoneNumberPreferenceController
@@ -41,13 +43,14 @@ constructor(
mSubId = subId mSubId = subId
} }
override fun getAvailabilityStatus(subId: Int): Int = override fun getAvailabilityStatus(subId: Int): Int = when {
when { !Flags.isDualSimOnboardingEnabled()
!Flags.isDualSimOnboardingEnabled() -> CONDITIONALLY_UNAVAILABLE || !SubscriptionManager.isValidSubscriptionId(subId)
SubscriptionManager.isValidSubscriptionId(subId) && || !SubscriptionUtil.isSimHardwareVisible(mContext)
SubscriptionUtil.isSimHardwareVisible(mContext) -> AVAILABLE || Utils.isWifiOnly(mContext) -> CONDITIONALLY_UNAVAILABLE
else -> CONDITIONALLY_UNAVAILABLE !mContext.userManager.isAdminUser -> DISABLED_FOR_USER
} else -> AVAILABLE
}
override fun displayPreference(screen: PreferenceScreen) { override fun displayPreference(screen: PreferenceScreen) {
super.displayPreference(screen) super.displayPreference(screen)

View File

@@ -17,6 +17,7 @@
package com.android.settings.deviceinfo package com.android.settings.deviceinfo
import android.content.Context import android.content.Context
import android.os.UserManager
import android.telephony.SubscriptionInfo import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
@@ -25,30 +26,39 @@ import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R import com.android.settings.R
import com.android.settings.core.BasePreferenceController
import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.Utils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.MockitoSession
import org.mockito.kotlin.any import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
import org.mockito.kotlin.verify import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class PhoneNumberPreferenceControllerTest { class PhoneNumberPreferenceControllerTest {
private lateinit var mockSession: MockitoSession
private val mockUserManager = mock<UserManager>()
private val mockTelephonyManager = mock<TelephonyManager>() private val mockTelephonyManager = mock<TelephonyManager>()
private val mockSubscriptionManager = mock<SubscriptionManager>() private val mockSubscriptionManager = mock<SubscriptionManager>()
private val context: Context = private val context: Context =
spy(ApplicationProvider.getApplicationContext()) { spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(SubscriptionManager::class.java) } doReturn on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
mockSubscriptionManager
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
on { getSystemService(UserManager::class.java) } doReturn mockUserManager
} }
private val subscriptionInfo = mock<SubscriptionInfo>() private val subscriptionInfo = mock<SubscriptionInfo>()
@@ -61,6 +71,20 @@ class PhoneNumberPreferenceControllerTest {
@Before @Before
fun setup() { fun setup() {
mockSession =
ExtendedMockito.mockitoSession()
.mockStatic(SubscriptionUtil::class.java)
.mockStatic(Utils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
// By default, available
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
whenever(Utils.isWifiOnly(context)).thenReturn(false)
mockUserManager.stub {
on { isAdminUser } doReturn true
}
preference.setKey(controller.preferenceKey) preference.setKey(controller.preferenceKey)
preference.isVisible = true preference.isVisible = true
preferenceScreen.addPreference(preference) preferenceScreen.addPreference(preference)
@@ -70,6 +94,11 @@ class PhoneNumberPreferenceControllerTest {
doReturn(secondPreference).whenever(controller).createNewPreference(context) doReturn(secondPreference).whenever(controller).createNewPreference(context)
} }
@After
fun teardown() {
mockSession.finishMocking()
}
@Test @Test
fun displayPreference_multiSim_shouldAddSecondPreference() { fun displayPreference_multiSim_shouldAddSecondPreference() {
whenever(mockTelephonyManager.phoneCount).thenReturn(2) whenever(mockTelephonyManager.phoneCount).thenReturn(2)
@@ -132,4 +161,37 @@ class PhoneNumberPreferenceControllerTest {
verify(preference).summary = context.getString(R.string.device_info_not_available) verify(preference).summary = context.getString(R.string.device_info_not_available)
} }
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
// Use defaults from setup()
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
}
@Test
fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
mockUserManager.stub {
on { isAdminUser } doReturn false
}
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
whenever(Utils.isWifiOnly(context)).thenReturn(true)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
}
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.network.telephony package com.android.settings.network.telephony
import android.content.Context import android.content.Context
import android.os.UserManager
import androidx.lifecycle.testing.TestLifecycleOwner import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@@ -26,6 +27,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R import com.android.settings.R
import com.android.settings.core.BasePreferenceController import com.android.settings.core.BasePreferenceController
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.Utils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@@ -37,6 +39,7 @@ import org.junit.runner.RunWith
import org.mockito.MockitoSession import org.mockito.MockitoSession
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub import org.mockito.kotlin.stub
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness import org.mockito.quality.Strictness
@@ -45,9 +48,14 @@ import org.mockito.quality.Strictness
class MobileNetworkPhoneNumberPreferenceControllerTest { class MobileNetworkPhoneNumberPreferenceControllerTest {
private lateinit var mockSession: MockitoSession private lateinit var mockSession: MockitoSession
private val context: Context = ApplicationProvider.getApplicationContext() private val mockUserManager = mock<UserManager>()
private val mockSubscriptionRepository = mock<SubscriptionRepository>() private val mockSubscriptionRepository = mock<SubscriptionRepository>()
private val context: Context =
spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(UserManager::class.java) } doReturn mockUserManager
}
private val controller = private val controller =
MobileNetworkPhoneNumberPreferenceController(context, TEST_KEY, mockSubscriptionRepository) MobileNetworkPhoneNumberPreferenceController(context, TEST_KEY, mockSubscriptionRepository)
private val preference = Preference(context).apply { key = TEST_KEY } private val preference = Preference(context).apply { key = TEST_KEY }
@@ -58,9 +66,17 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
mockSession = mockSession =
ExtendedMockito.mockitoSession() ExtendedMockito.mockitoSession()
.mockStatic(SubscriptionUtil::class.java) .mockStatic(SubscriptionUtil::class.java)
.mockStatic(Utils::class.java)
.strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT)
.startMocking() .startMocking()
// By default, available
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
whenever(Utils.isWifiOnly(context)).thenReturn(false)
mockUserManager.stub {
on { isAdminUser } doReturn true
}
preferenceScreen.addPreference(preference) preferenceScreen.addPreference(preference)
controller.init(SUB_ID) controller.init(SUB_ID)
controller.displayPreference(preferenceScreen) controller.displayPreference(preferenceScreen)
@@ -73,7 +89,6 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
@Test @Test
fun onViewCreated_cannotGetPhoneNumber_displayUnknown() = runBlocking { fun onViewCreated_cannotGetPhoneNumber_displayUnknown() = runBlocking {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
mockSubscriptionRepository.stub { mockSubscriptionRepository.stub {
on { phoneNumberFlow(SUB_ID) } doReturn flowOf(null) on { phoneNumberFlow(SUB_ID) } doReturn flowOf(null)
} }
@@ -86,7 +101,6 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
@Test @Test
fun onViewCreated_canGetPhoneNumber_displayPhoneNumber() = runBlocking { fun onViewCreated_canGetPhoneNumber_displayPhoneNumber() = runBlocking {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
mockSubscriptionRepository.stub { mockSubscriptionRepository.stub {
on { phoneNumberFlow(SUB_ID) } doReturn flowOf(PHONE_NUMBER) on { phoneNumberFlow(SUB_ID) } doReturn flowOf(PHONE_NUMBER)
} }
@@ -98,11 +112,35 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
} }
@Test @Test
fun getAvailabilityStatus_notSimHardwareVisible() { fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
// Use defaults from setup()
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
}
@Test
fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false) whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
val availabilityStatus = controller.availabilityStatus val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
mockUserManager.stub {
on { isAdminUser } doReturn false
}
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
whenever(Utils.isWifiOnly(context)).thenReturn(true)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE) assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE)
} }