Create MobileNetworkSummaryRepository

For MobileNetworkSummaryController to use, so it no longer use
MobileNetworkRepository.

Fix: 366097262
Flag: EXEMPT refactor
Test: manual - on Network & internet
Test: atest MobileNetworkSummaryRepositoryTest
Change-Id: I8a9d52af8e230fc407a4339c27f73ef79d512b24
This commit is contained in:
Chaohui Wang
2024-09-13 16:52:25 +08:00
parent 540ce288ad
commit 777a179bd6
9 changed files with 445 additions and 562 deletions

View File

@@ -1,333 +0,0 @@
/*
* Copyright (C) 2019 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;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;
import com.android.settings.Settings.MobileNetworkActivity;
import com.android.settings.widget.AddPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
public class MobileNetworkSummaryControllerTest {
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private EuiccManager mEuiccManager;
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private MobileNetworkRepository mMobileNetworkRepository;
@Mock
private MobileNetworkRepository.MobileNetworkCallback mMobileNetworkCallback;
private AddPreference mPreference;
private Context mContext;
private MobileNetworkSummaryController mController;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class);
doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class);
doReturn(mEuiccManager).when(mContext).getSystemService(EuiccManager.class);
mMobileNetworkRepository = MobileNetworkRepository.getInstance(mContext);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mMobileNetworkRepository.addRegister(mLifecycleOwner, mMobileNetworkCallback,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("");
when(mSubscriptionManager.isActiveSubscriptionId(anyInt())).thenReturn(true);
when(mEuiccManager.isEnabled()).thenReturn(true);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.EUICC_PROVISIONED, 1);
mController = new MobileNetworkSummaryController(mContext, mLifecycle, mLifecycleOwner);
mPreference = spy(new AddPreference(mContext, null));
mPreference.setKey(mController.getPreferenceKey());
when(mPreferenceScreen.findPreference(eq(mController.getPreferenceKey()))).thenReturn(
mPreference);
}
@After
public void tearDown() {
mMobileNetworkRepository.removeRegister(mMobileNetworkCallback);
SubscriptionUtil.setActiveSubscriptionsForTesting(null);
SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
}
@Test
public void getSummary_noSubscriptions_returnSummaryCorrectly() {
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mController.getSummary()).isEqualTo("Add a network");
}
@Test
public void getSummary_noSubscriptionsNoEuiccMgr_correctSummaryAndClickHandler() {
when(mEuiccManager.isEnabled()).thenReturn(false);
assertThat(TextUtils.isEmpty(mController.getSummary())).isTrue();
assertThat(mPreference.getOnPreferenceClickListener()).isNull();
assertThat(mPreference.getFragment()).isNull();
}
@Test
@Ignore
public void getSummary_oneSubscription_correctSummaryAndClickHandler() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
when(sub1.getSubscriptionId()).thenReturn(1);
when(sub1.getDisplayName()).thenReturn("sub1");
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mController.getSummary()).isEqualTo("sub1");
assertThat(mPreference.getFragment()).isNull();
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mContext).startActivity(intentCaptor.capture());
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
Intent intent = intentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
MobileNetworkActivity.class.getName());
assertThat(intent.getIntExtra(Settings.EXTRA_SUB_ID,
SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(sub1.getSubscriptionId());
}
@Test
@Ignore
public void getSummary_oneInactivePSim_cannotDisablePsim_correctSummaryAndClickHandler() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
when(sub1.getSubscriptionId()).thenReturn(1);
when(sub1.getDisplayName()).thenReturn("sub1");
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
when(mSubscriptionManager.isActiveSubscriptionId(eq(1))).thenReturn(false);
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mController.getSummary()).isEqualTo("Tap to activate sub1");
assertThat(mPreference.getFragment()).isNull();
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
verify(mSubscriptionManager).setSubscriptionEnabled(eq(sub1.getSubscriptionId()), eq(true));
}
@Test
@Ignore
public void getSummary_oneInactivePSim_canDisablePsim_correctSummaryAndClickHandler() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
when(sub1.getSubscriptionId()).thenReturn(1);
when(sub1.getDisplayName()).thenReturn("sub1");
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1));
when(mSubscriptionManager.isActiveSubscriptionId(eq(1))).thenReturn(false);
when(mSubscriptionManager.canDisablePhysicalSubscription()).thenReturn(true);
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mController.getSummary()).isEqualTo("sub1");
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mContext).startActivity(intentCaptor.capture());
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
Intent intent = intentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
MobileNetworkActivity.class.getName());
assertThat(intent.getIntExtra(Settings.EXTRA_SUB_ID,
SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(sub1.getSubscriptionId());
}
@Test
public void addButton_noSubscriptionsNoEuiccMgr_noAddClickListener() {
when(mEuiccManager.isEnabled()).thenReturn(false);
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference, never()).setOnAddClickListener(notNull());
}
@Test
public void addButton_oneSubscriptionNoEuiccMgr_noAddClickListener() {
when(mEuiccManager.isEnabled()).thenReturn(false);
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference, never()).setOnAddClickListener(notNull());
}
@Test
public void addButton_noSubscriptions_noAddClickListener() {
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference, never()).setOnAddClickListener(notNull());
}
@Test
@Ignore
public void addButton_oneSubscription_hasAddClickListener() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference).setOnAddClickListener(notNull());
}
@Test
@Ignore
public void addButton_twoSubscriptions_hasAddClickListener() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference).setOnAddClickListener(notNull());
}
@Test
@Ignore
public void addButton_oneSubscriptionAirplaneModeTurnedOn_addButtonGetsDisabled() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
mController.onAirplaneModeChanged(true);
final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
assertThat(captor.getValue()).isFalse();
}
@Test
@Ignore
public void onResume_oneSubscriptionAirplaneMode_isDisabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mPreference.isEnabled()).isFalse();
final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
assertThat(captor.getValue()).isFalse();
}
@Test
public void onAvailableSubInfoChanged_noSubscriptionEsimDisabled_isDisabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
when(mEuiccManager.isEnabled()).thenReturn(false);
mController.displayPreference(mPreferenceScreen);
mController.onAvailableSubInfoChanged(null);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOn_isDisabled() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mPreference.isEnabled()).isTrue();
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
mController.onAirplaneModeChanged(true);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
@Ignore
public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOff_isEnabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
assertThat(mPreference.isEnabled()).isFalse();
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
mController.onAirplaneModeChanged(false);
assertThat(mPreference.isEnabled()).isTrue();
final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
verify(mPreference, atLeastOnce()).setAddWidgetEnabled(eq(false));
verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
assertThat(captor.getValue()).isTrue();
}
@Test
public void onResume_disabledByAdmin_prefStaysDisabled() {
mPreference.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin());
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mPreference, never()).setEnabled(eq(true));
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2024 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
import android.content.Context
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.preference.PreferenceManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settingslib.RestrictedPreference
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class MobileNetworkSummaryControllerTest {
private val context: Context = ApplicationProvider.getApplicationContext()
private val preference = RestrictedPreference(context).apply { key = KEY }
private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context)
private val mockMobileNetworkSummaryRepository = mock<MobileNetworkSummaryRepository>()
private val airplaneModeOnFlow = MutableStateFlow(false)
private val controller =
MobileNetworkSummaryController(
context = context,
preferenceKey = KEY,
repository = mockMobileNetworkSummaryRepository,
airplaneModeOnFlow = airplaneModeOnFlow,
)
@Before
fun setUp() {
preferenceScreen.addPreference(preference)
controller.displayPreference(preferenceScreen)
}
@Test
fun onViewCreated_noSubscriptions(): Unit = runBlocking {
mockMobileNetworkSummaryRepository.stub {
on { subscriptionsStateFlow() } doReturn
flowOf(MobileNetworkSummaryRepository.NoSubscriptions)
}
controller.onViewCreated(TestLifecycleOwner())
delay(100)
assertThat(preference.summary).isNull()
assertThat(preference.isEnabled).isFalse()
assertThat(preference.onPreferenceClickListener).isNull()
}
@Test
fun onViewCreated_addNetwork(): Unit = runBlocking {
mockMobileNetworkSummaryRepository.stub {
on { subscriptionsStateFlow() } doReturn
flowOf(MobileNetworkSummaryRepository.AddNetwork)
}
controller.onViewCreated(TestLifecycleOwner())
delay(100)
assertThat(preference.summary)
.isEqualTo(context.getString(R.string.mobile_network_summary_add_a_network))
assertThat(preference.isEnabled).isTrue()
assertThat(preference.onPreferenceClickListener).isNotNull()
}
@Test
fun onViewCreated_hasSubscriptions(): Unit = runBlocking {
mockMobileNetworkSummaryRepository.stub {
on { subscriptionsStateFlow() } doReturn
flowOf(
MobileNetworkSummaryRepository.HasSubscriptions(
displayNames = listOf(DISPLAY_NAME_1, DISPLAY_NAME_2)
)
)
}
controller.onViewCreated(TestLifecycleOwner())
delay(100)
assertThat(preference.summary).isEqualTo("$DISPLAY_NAME_1, $DISPLAY_NAME_2")
assertThat(preference.isEnabled).isTrue()
assertThat(preference.fragment).isNotNull()
}
@Test
fun onViewCreated_addNetworkAndAirplaneModeOn(): Unit = runBlocking {
mockMobileNetworkSummaryRepository.stub {
on { subscriptionsStateFlow() } doReturn
flowOf(MobileNetworkSummaryRepository.AddNetwork)
}
airplaneModeOnFlow.value = true
controller.onViewCreated(TestLifecycleOwner())
delay(100)
assertThat(preference.isEnabled).isFalse()
}
@Test
fun onViewCreated_hasSubscriptionsAndAirplaneModeOn(): Unit = runBlocking {
mockMobileNetworkSummaryRepository.stub {
on { subscriptionsStateFlow() } doReturn
flowOf(
MobileNetworkSummaryRepository.HasSubscriptions(
displayNames = listOf(DISPLAY_NAME_1, DISPLAY_NAME_2)
)
)
}
airplaneModeOnFlow.value = true
controller.onViewCreated(TestLifecycleOwner())
delay(100)
assertThat(preference.isEnabled).isFalse()
}
private companion object {
const val KEY = "test_key"
const val DISPLAY_NAME_1 = "Display Name 1"
const val DISPLAY_NAME_2 = "Display Name 2"
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 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
import android.content.Context
import android.telephony.SubscriptionInfo
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settings.network.telephony.euicc.EuiccRepository
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class MobileNetworkSummaryRepositoryTest {
private val context: Context = ApplicationProvider.getApplicationContext()
private val mockSubscriptionRepository = mock<SubscriptionRepository>()
private val mockEuiccRepository = mock<EuiccRepository>()
private val repository =
MobileNetworkSummaryRepository(
context = context,
subscriptionRepository = mockSubscriptionRepository,
euiccRepository = mockEuiccRepository,
getDisplayName = { it.displayName.toString() },
)
@Test
fun subscriptionsStateFlow_noSubscriptionsAndShowEuicc_returnsAddNetwork() = runBlocking {
mockSubscriptionRepository.stub {
on { selectableSubscriptionInfoListFlow() } doReturn flowOf(emptyList())
}
mockEuiccRepository.stub { on { showEuiccSettings() } doReturn true }
val state = repository.subscriptionsStateFlow().firstWithTimeoutOrNull()
assertThat(state).isEqualTo(MobileNetworkSummaryRepository.AddNetwork)
}
@Test
fun subscriptionsStateFlow_noSubscriptionsAndHideEuicc_returnsNoSubscriptions() = runBlocking {
mockSubscriptionRepository.stub {
on { selectableSubscriptionInfoListFlow() } doReturn flowOf(emptyList())
}
mockEuiccRepository.stub { on { showEuiccSettings() } doReturn false }
val state = repository.subscriptionsStateFlow().firstWithTimeoutOrNull()
assertThat(state).isEqualTo(MobileNetworkSummaryRepository.NoSubscriptions)
}
@Test
fun subscriptionsStateFlow_hasSubscriptions_returnsHasSubscriptions() = runBlocking {
mockSubscriptionRepository.stub {
on { selectableSubscriptionInfoListFlow() } doReturn
flowOf(
listOf(
SubscriptionInfo.Builder().setDisplayName(DISPLAY_NAME_1).build(),
SubscriptionInfo.Builder().setDisplayName(DISPLAY_NAME_2).build(),
)
)
}
val state = repository.subscriptionsStateFlow().firstWithTimeoutOrNull()
assertThat(state)
.isEqualTo(
MobileNetworkSummaryRepository.HasSubscriptions(
listOf(DISPLAY_NAME_1, DISPLAY_NAME_2)
)
)
}
private companion object {
const val DISPLAY_NAME_1 = "Sub 1"
const val DISPLAY_NAME_2 = "Sub 2"
}
}