Loading src/com/android/settings/network/TetherPreferenceController.kt +30 −5 Original line number Diff line number Diff line Loading @@ -35,19 +35,35 @@ import com.android.settingslib.TetherUtil import com.android.settingslib.Utils import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class TetherPreferenceController(context: Context, key: String) : BasePreferenceController(context, key) { class TetherPreferenceController( context: Context, key: String, private val tetheredRepository: TetheredRepository = TetheredRepository(context), ) : BasePreferenceController(context, key) { private val tetheredRepository = TetheredRepository(context) private val tetheringManager = mContext.getSystemService(TetheringManager::class.java)!! private var preference: Preference? = null override fun getAvailabilityStatus() = if (TetherUtil.isTetherAvailable(mContext)) AVAILABLE else CONDITIONALLY_UNAVAILABLE private val isTetherAvailableFlow = flow { emit(TetherUtil.isTetherAvailable(mContext)) } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) /** * Always returns available here to avoid ANR. * - Actual UI visibility is handled in [onViewCreated]. * - Search visibility is handled in [updateNonIndexableKeys]. */ override fun getAvailabilityStatus() = AVAILABLE override fun displayPreference(screen: PreferenceScreen) { super.displayPreference(screen) Loading @@ -55,6 +71,9 @@ class TetherPreferenceController(context: Context, key: String) : } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { isTetherAvailableFlow.collectLatestWithLifecycle(viewLifecycleOwner) { preference?.isVisible = it } viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { getTitleResId()?.let { preference?.setTitle(it) } Loading Loading @@ -84,6 +103,12 @@ class TetherPreferenceController(context: Context, key: String) : } } override fun updateNonIndexableKeys(keys: MutableList<String>) { if (!TetherUtil.isTetherAvailable(mContext)) { keys += preferenceKey } } companion object { @JvmStatic fun isTetherConfigDisallowed(context: Context?): Boolean = Loading tests/spa_unit/src/com/android/settings/network/TetherPreferenceControllerTest.kt +33 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.settings.network import android.content.Context import android.net.TetheringManager import androidx.lifecycle.testing.TestLifecycleOwner import androidx.preference.PreferenceCategory import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.dx.mockito.inline.extended.ExtendedMockito Loading @@ -25,11 +28,15 @@ import com.android.settings.R import com.android.settings.core.BasePreferenceController import com.android.settingslib.TetherUtil import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoSession import org.mockito.kotlin.mock import org.mockito.quality.Strictness @RunWith(AndroidJUnit4::class) Loading @@ -38,7 +45,14 @@ class TetherPreferenceControllerTest { private val context: Context = ApplicationProvider.getApplicationContext() private val controller = TetherPreferenceController(context, TEST_KEY) private val mockTetheredRepository = mock<TetheredRepository> { on { tetheredTypesFlow() }.thenReturn(flowOf(emptySet())) } private val controller = TetherPreferenceController(context, TEST_KEY, mockTetheredRepository) private val preference = PreferenceCategory(context).apply { key = TEST_KEY } private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context) @Before fun setUp() { Loading @@ -49,6 +63,9 @@ class TetherPreferenceControllerTest { .startMocking() ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } preferenceScreen.addPreference(preference) controller.displayPreference(preferenceScreen) } @After Loading @@ -57,21 +74,30 @@ class TetherPreferenceControllerTest { } @Test fun getAvailabilityStatus_whenTetherAvailable() { ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } fun getAvailabilityStatus_alwaysReturnAvailable() { val availabilityStatus = controller.availabilityStatus assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE) } @Test fun getAvailabilityStatus_whenTetherNotAvailable() { fun onViewCreated_whenTetherAvailable() = runBlocking { ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } controller.onViewCreated(TestLifecycleOwner()) delay(100) assertThat(preference.isVisible).isTrue() } @Test fun onViewCreated_whenTetherNotAvailable() = runBlocking { ExtendedMockito.doReturn(false).`when` { TetherUtil.isTetherAvailable(context) } val availabilityStatus = controller.availabilityStatus controller.onViewCreated(TestLifecycleOwner()) delay(100) assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE) assertThat(preference.isVisible).isFalse() } @Test Loading Loading
src/com/android/settings/network/TetherPreferenceController.kt +30 −5 Original line number Diff line number Diff line Loading @@ -35,19 +35,35 @@ import com.android.settingslib.TetherUtil import com.android.settingslib.Utils import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class TetherPreferenceController(context: Context, key: String) : BasePreferenceController(context, key) { class TetherPreferenceController( context: Context, key: String, private val tetheredRepository: TetheredRepository = TetheredRepository(context), ) : BasePreferenceController(context, key) { private val tetheredRepository = TetheredRepository(context) private val tetheringManager = mContext.getSystemService(TetheringManager::class.java)!! private var preference: Preference? = null override fun getAvailabilityStatus() = if (TetherUtil.isTetherAvailable(mContext)) AVAILABLE else CONDITIONALLY_UNAVAILABLE private val isTetherAvailableFlow = flow { emit(TetherUtil.isTetherAvailable(mContext)) } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) /** * Always returns available here to avoid ANR. * - Actual UI visibility is handled in [onViewCreated]. * - Search visibility is handled in [updateNonIndexableKeys]. */ override fun getAvailabilityStatus() = AVAILABLE override fun displayPreference(screen: PreferenceScreen) { super.displayPreference(screen) Loading @@ -55,6 +71,9 @@ class TetherPreferenceController(context: Context, key: String) : } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { isTetherAvailableFlow.collectLatestWithLifecycle(viewLifecycleOwner) { preference?.isVisible = it } viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { getTitleResId()?.let { preference?.setTitle(it) } Loading Loading @@ -84,6 +103,12 @@ class TetherPreferenceController(context: Context, key: String) : } } override fun updateNonIndexableKeys(keys: MutableList<String>) { if (!TetherUtil.isTetherAvailable(mContext)) { keys += preferenceKey } } companion object { @JvmStatic fun isTetherConfigDisallowed(context: Context?): Boolean = Loading
tests/spa_unit/src/com/android/settings/network/TetherPreferenceControllerTest.kt +33 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.settings.network import android.content.Context import android.net.TetheringManager import androidx.lifecycle.testing.TestLifecycleOwner import androidx.preference.PreferenceCategory import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.dx.mockito.inline.extended.ExtendedMockito Loading @@ -25,11 +28,15 @@ import com.android.settings.R import com.android.settings.core.BasePreferenceController import com.android.settingslib.TetherUtil import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.MockitoSession import org.mockito.kotlin.mock import org.mockito.quality.Strictness @RunWith(AndroidJUnit4::class) Loading @@ -38,7 +45,14 @@ class TetherPreferenceControllerTest { private val context: Context = ApplicationProvider.getApplicationContext() private val controller = TetherPreferenceController(context, TEST_KEY) private val mockTetheredRepository = mock<TetheredRepository> { on { tetheredTypesFlow() }.thenReturn(flowOf(emptySet())) } private val controller = TetherPreferenceController(context, TEST_KEY, mockTetheredRepository) private val preference = PreferenceCategory(context).apply { key = TEST_KEY } private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context) @Before fun setUp() { Loading @@ -49,6 +63,9 @@ class TetherPreferenceControllerTest { .startMocking() ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } preferenceScreen.addPreference(preference) controller.displayPreference(preferenceScreen) } @After Loading @@ -57,21 +74,30 @@ class TetherPreferenceControllerTest { } @Test fun getAvailabilityStatus_whenTetherAvailable() { ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } fun getAvailabilityStatus_alwaysReturnAvailable() { val availabilityStatus = controller.availabilityStatus assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE) } @Test fun getAvailabilityStatus_whenTetherNotAvailable() { fun onViewCreated_whenTetherAvailable() = runBlocking { ExtendedMockito.doReturn(true).`when` { TetherUtil.isTetherAvailable(context) } controller.onViewCreated(TestLifecycleOwner()) delay(100) assertThat(preference.isVisible).isTrue() } @Test fun onViewCreated_whenTetherNotAvailable() = runBlocking { ExtendedMockito.doReturn(false).`when` { TetherUtil.isTetherAvailable(context) } val availabilityStatus = controller.availabilityStatus controller.onViewCreated(TestLifecycleOwner()) delay(100) assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE) assertThat(preference.isVisible).isFalse() } @Test Loading