Add condition whether esim is visible or not

Bug: 314736037
Test: SubscriptionInfoListViewModelTest pass and build pass
Change-Id: I7dc86ca93691f044d951122c0c669c790b7aef98
This commit is contained in:
SongFerngWang
2023-12-11 05:43:12 +08:00
parent 0a32ca2bbc
commit ec27c60461
4 changed files with 194 additions and 6 deletions

View File

@@ -19,8 +19,10 @@ package com.android.settings.network
import android.app.Application import android.app.Application
import android.telephony.SubscriptionInfo import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
@@ -32,13 +34,12 @@ import kotlinx.coroutines.plus
class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel(application) { class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel(application) {
private val scope = viewModelScope + Dispatchers.Default private val scope = viewModelScope + Dispatchers.Default
val subscriptionInfoListFlow = callbackFlow<List<SubscriptionInfo>> { val subscriptionInfoListFlow = callbackFlow<List<SubscriptionInfo>> {
val subscriptionManager = application.getSystemService(SubscriptionManager::class.java)!! val subscriptionManager = application.getSystemService(SubscriptionManager::class.java)!!
val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() { val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
override fun onSubscriptionsChanged() { override fun onSubscriptionsChanged() {
trySend(subscriptionManager.activeSubscriptionInfoList ?: emptyList()) trySend(SubscriptionUtil.getActiveSubscriptions(subscriptionManager))
} }
} }

View File

@@ -18,6 +18,8 @@ package com.android.settings.network;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
import static com.android.internal.util.CollectionUtils.emptyIfNull; import static com.android.internal.util.CollectionUtils.emptyIfNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -36,9 +38,11 @@ import android.text.TextDirectionHeuristics;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.flags.Flags;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.network.helper.SelectableSubscriptions; import com.android.settings.network.helper.SelectableSubscriptions;
import com.android.settings.network.helper.SubscriptionAnnotation; import com.android.settings.network.helper.SubscriptionAnnotation;
@@ -84,6 +88,8 @@ public class SubscriptionUtil {
} }
public static List<SubscriptionInfo> getActiveSubscriptions(SubscriptionManager manager) { public static List<SubscriptionInfo> getActiveSubscriptions(SubscriptionManager manager) {
//TODO (b/315499317) : Refactor the subscription utils.
if (sActiveResultsForTesting != null) { if (sActiveResultsForTesting != null) {
return sActiveResultsForTesting; return sActiveResultsForTesting;
} }
@@ -94,7 +100,12 @@ public class SubscriptionUtil {
if (subscriptions == null) { if (subscriptions == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
return subscriptions; // Since the SubscriptionManager.getActiveSubscriptionInfoList() has checked whether the
// sim visible by the SubscriptionManager.isSubscriptionVisible(), here only checks whether
// the esim visible here.
return subscriptions.stream()
.filter(subInfo -> subInfo != null && isEmbeddedSubscriptionVisible(subInfo))
.collect(Collectors.toList());
} }
/** /**
@@ -128,7 +139,7 @@ public class SubscriptionUtil {
} }
/** /**
* Get subscription which is available to be displayed to the user * Get subscriptionInfo which is available to be displayed to the user
* per subscription id. * per subscription id.
* *
* @param context {@code Context} * @param context {@code Context}
@@ -138,13 +149,20 @@ public class SubscriptionUtil {
* @return {@code SubscriptionInfo} based on the given subscription id. Null of subscription * @return {@code SubscriptionInfo} based on the given subscription id. Null of subscription
* is invalid or not allowed to be displayed to the user. * is invalid or not allowed to be displayed to the user.
*/ */
public static SubscriptionInfo getAvailableSubscription(Context context, public static SubscriptionInfo getAvailableSubscriptionBySubIdAndShowingForUser(Context context,
ProxySubscriptionManager subscriptionManager, int subId) { ProxySubscriptionManager subscriptionManager, int subId) {
//TODO (b/315499317) : Refactor the subscription utils.
final SubscriptionInfo subInfo = subscriptionManager.getAccessibleSubscriptionInfo(subId); final SubscriptionInfo subInfo = subscriptionManager.getAccessibleSubscriptionInfo(subId);
if (subInfo == null) { if (subInfo == null) {
return null; return null;
} }
// hide provisioning/bootstrap and satellite profiles for user
if (isEmbeddedSubscriptionVisible(subInfo)) {
Log.d(TAG, "Do not insert the provision eSIM or NTN eSim");
return null;
}
final ParcelUuid groupUuid = subInfo.getGroupUuid(); final ParcelUuid groupUuid = subInfo.getGroupUuid();
if (groupUuid != null) { if (groupUuid != null) {
@@ -567,6 +585,12 @@ public class SubscriptionUtil {
public static boolean isSubscriptionVisible( public static boolean isSubscriptionVisible(
SubscriptionManager subscriptionManager, Context context, SubscriptionInfo info) { SubscriptionManager subscriptionManager, Context context, SubscriptionInfo info) {
if (info == null) return false; if (info == null) return false;
// hide provisioning/bootstrap and satellite profiles for user
if (isEmbeddedSubscriptionVisible(info)) {
return false;
}
// If subscription is NOT grouped opportunistic subscription, it's visible. // If subscription is NOT grouped opportunistic subscription, it's visible.
if (info.getGroupUuid() == null || !info.isOpportunistic()) return true; if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;
@@ -786,4 +810,14 @@ public class SubscriptionUtil {
} }
return (currentSubInfo == null) ? null : currentSubInfo.getSubInfo(); return (currentSubInfo == null) ? null : currentSubInfo.getSubInfo();
} }
private static boolean isEmbeddedSubscriptionVisible(@NonNull SubscriptionInfo subInfo) {
if (subInfo.isEmbedded()
&& (subInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING
|| (Flags.oemEnabledSatelliteFlag()
&& subInfo.isOnlyNonTerrestrialNetwork()))) {
return false;
}
return true;
}
} }

View File

@@ -521,7 +521,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
* Uses to inject function and value for class and test class. * Uses to inject function and value for class and test class.
*/ */
public boolean canSubscriptionBeDisplayed(Context context, int subId) { public boolean canSubscriptionBeDisplayed(Context context, int subId) {
return (SubscriptionUtil.getAvailableSubscription(context, return (SubscriptionUtil.getAvailableSubscriptionBySubIdAndShowingForUser(context,
ProxySubscriptionManager.getInstance(context), subId) != null); ProxySubscriptionManager.getInstance(context), subId) != null);
} }

View File

@@ -0,0 +1,153 @@
/*
* 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
import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
import android.app.Application
import android.content.Context
import android.platform.test.flag.junit.SetFlagsRule
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.telephony.flags.Flags
import com.android.settings.network.telephony.CallStateFlowTest
import com.android.settingslib.spa.testutils.toListWithTimeout
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class SubscriptionInfoListViewModelTest {
@get:Rule
val mSetFlagsRule = SetFlagsRule()
private var subInfoListener: SubscriptionManager.OnSubscriptionsChangedListener? = null
private val mockSubscriptionManager = mock<SubscriptionManager> {
on { activeSubscriptionInfoList } doAnswer { activeSubscriptionInfoList }
on { addOnSubscriptionsChangedListener(any(), any()) } doAnswer {
subInfoListener =
it.arguments[1] as SubscriptionManager.OnSubscriptionsChangedListener
subInfoListener?.onSubscriptionsChanged()
}
}
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
}
private val subscriptionInfoListViewModel: SubscriptionInfoListViewModel =
SubscriptionInfoListViewModel(context as Application);
private var activeSubscriptionInfoList: List<SubscriptionInfo>? = null
@Test
fun onSubscriptionsChanged_noProvisioning_resultSameAsInput() = runBlocking {
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2)
val listDeferred = async {
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
}
delay(100)
subInfoListener?.onSubscriptionsChanged()
assertThat(listDeferred.await()).contains(activeSubscriptionInfoList)
}
@Test
fun onSubscriptionsChanged_hasProvisioning_filterProvisioning() = runBlocking {
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)
val expectation = listOf(SUB_INFO_1, SUB_INFO_2)
val listDeferred = async {
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
}
delay(100)
subInfoListener?.onSubscriptionsChanged()
assertThat(listDeferred.await()).contains(expectation)
}
@Test
fun onSubscriptionsChanged_flagOffHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
runBlocking {
mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
val expectation = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
val listDeferred = async {
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
}
delay(100)
subInfoListener?.onSubscriptionsChanged()
assertThat(listDeferred.await()).contains(expectation)
}
@Test
fun onSubscriptionsChanged_flagOnHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
runBlocking {
mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
val expectation = listOf(SUB_INFO_1, SUB_INFO_2)
val listDeferred = async {
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
}
delay(100)
subInfoListener?.onSubscriptionsChanged()
assertThat(listDeferred.await()).contains(expectation)
}
private companion object {
val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply {
setId(1)
}.build()
val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply {
setId(2)
}.build()
val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply {
setId(3)
setEmbedded(true)
setProfileClass(PROFILE_CLASS_PROVISIONING)
setOnlyNonTerrestrialNetwork(false)
}.build()
val SUB_INFO_4: SubscriptionInfo = SubscriptionInfo.Builder().apply {
setId(4)
setEmbedded(true)
setOnlyNonTerrestrialNetwork(true)
}.build()
}
}