Merge "Create selectableSubscriptionInfoListFlow" into main

This commit is contained in:
Chaohui Wang
2024-09-12 08:56:39 +00:00
committed by Android (Google) Code Review
4 changed files with 48 additions and 44 deletions

View File

@@ -20,7 +20,7 @@ import android.app.Application
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 com.android.settings.network.telephony.getSelectableSubscriptionInfoList import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settings.network.telephony.subscriptionsChangedFlow import com.android.settings.network.telephony.subscriptionsChangedFlow
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -45,7 +45,8 @@ class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel
* Getting the Selectable SubscriptionInfo List from the SubscriptionRepository's * Getting the Selectable SubscriptionInfo List from the SubscriptionRepository's
* getAvailableSubscriptionInfoList * getAvailableSubscriptionInfoList
*/ */
val selectableSubscriptionInfoListFlow = application.subscriptionsChangedFlow().map { val selectableSubscriptionInfoListFlow =
application.getSelectableSubscriptionInfoList() SubscriptionRepository(application)
}.stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList()) .selectableSubscriptionInfoListFlow()
.stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList())
} }

View File

@@ -52,7 +52,7 @@ import com.android.settings.network.helper.SelectableSubscriptions;
import com.android.settings.network.helper.SubscriptionAnnotation; import com.android.settings.network.helper.SubscriptionAnnotation;
import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity; import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity; import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity;
import com.android.settings.network.telephony.SubscriptionRepositoryKt; import com.android.settings.network.telephony.SubscriptionRepository;
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity; import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
import java.util.ArrayList; import java.util.ArrayList;
@@ -508,7 +508,7 @@ public class SubscriptionUtil {
* @return list of user selectable subscriptions. * @return list of user selectable subscriptions.
*/ */
public static List<SubscriptionInfo> getSelectableSubscriptionInfoList(Context context) { public static List<SubscriptionInfo> getSelectableSubscriptionInfoList(Context context) {
return SubscriptionRepositoryKt.getSelectableSubscriptionInfoList(context); return new SubscriptionRepository(context).getSelectableSubscriptionInfoList();
} }
/** /**

View File

@@ -42,13 +42,48 @@ private const val TAG = "SubscriptionRepository"
class SubscriptionRepository(private val context: Context) { class SubscriptionRepository(private val context: Context) {
private val subscriptionManager = context.requireSubscriptionManager() private val subscriptionManager = context.requireSubscriptionManager()
/** A cold flow of a list of subscriptions that are available and visible to the user. */
fun selectableSubscriptionInfoListFlow(): Flow<List<SubscriptionInfo>> =
context
.subscriptionsChangedFlow()
.map { getSelectableSubscriptionInfoList() }
.conflate()
.flowOn(Dispatchers.Default)
/** /**
* Return a list of subscriptions that are available and visible to the user. * Return a list of subscriptions that are available and visible to the user.
* *
* @return list of user selectable subscriptions. * @return list of user selectable subscriptions.
*/ */
fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> = fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
context.getSelectableSubscriptionInfoList() val availableList =
subscriptionManager.getAvailableSubscriptionInfoList() ?: return emptyList()
val visibleList =
availableList.filter { subInfo ->
// Opportunistic subscriptions are considered invisible to users so they should
// never be returned.
SubscriptionUtil.isSubscriptionVisible(subscriptionManager, context, subInfo)
}
return visibleList
.groupBy { it.groupUuid }
.flatMap { (groupUuid, subInfos) ->
if (groupUuid == null) {
subInfos
} else {
// Multiple subscriptions in a group should only have one representative.
// It should be the current active primary subscription if any, or the primary
// subscription with minimum subscription id.
subInfos
.filter { it.simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX }
.ifEmpty { subInfos.sortedBy { it.subscriptionId } }
.take(1)
}
}
// Matching the sorting order in
// SubscriptionManagerService.getAvailableSubscriptionInfoList
.sortedWith(compareBy({ it.sortableSimSlotIndex }, { it.subscriptionId }))
.also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") }
}
/** Flow of whether the subscription visible for the given [subId]. */ /** Flow of whether the subscription visible for the given [subId]. */
fun isSubscriptionVisibleFlow(subId: Int): Flow<Boolean> { fun isSubscriptionVisibleFlow(subId: Int): Flow<Boolean> {
@@ -154,38 +189,6 @@ fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo): Flow<String?> =
fun Context.subscriptionsChangedFlow(): Flow<Unit> = fun Context.subscriptionsChangedFlow(): Flow<Unit> =
SubscriptionRepository(this).subscriptionsChangedFlow() SubscriptionRepository(this).subscriptionsChangedFlow()
/**
* Return a list of subscriptions that are available and visible to the user.
*
* @return list of user selectable subscriptions.
*/
fun Context.getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
val subscriptionManager = requireSubscriptionManager()
val availableList = subscriptionManager.getAvailableSubscriptionInfoList() ?: return emptyList()
val visibleList = availableList.filter { subInfo ->
// Opportunistic subscriptions are considered invisible
// to users so they should never be returned.
SubscriptionUtil.isSubscriptionVisible(subscriptionManager, this, subInfo)
}
return visibleList
.groupBy { it.groupUuid }
.flatMap { (groupUuid, subInfos) ->
if (groupUuid == null) {
subInfos
} else {
// Multiple subscriptions in a group should only have one representative.
// It should be the current active primary subscription if any, or the primary
// subscription with minimum subscription id.
subInfos.filter { it.simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX }
.ifEmpty { subInfos.sortedBy { it.subscriptionId } }
.take(1)
}
}
// Matching the sorting order in SubscriptionManagerService.getAvailableSubscriptionInfoList
.sortedWith(compareBy({ it.sortableSimSlotIndex }, { it.subscriptionId }))
.also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") }
}
/** Subscription with invalid sim slot index has lowest sort order. */ /** Subscription with invalid sim slot index has lowest sort order. */
private val SubscriptionInfo.sortableSimSlotIndex: Int private val SubscriptionInfo.sortableSimSlotIndex: Int
get() = if (simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { get() = if (simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {

View File

@@ -120,7 +120,7 @@ class SubscriptionRepositoryTest {
) )
} }
val subInfos = context.getSelectableSubscriptionInfoList() val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.simSlotIndex }) assertThat(subInfos.map { it.simSlotIndex })
.containsExactly(SIM_SLOT_INDEX_0, SIM_SLOT_INDEX_1).inOrder() .containsExactly(SIM_SLOT_INDEX_0, SIM_SLOT_INDEX_1).inOrder()
@@ -141,7 +141,7 @@ class SubscriptionRepositoryTest {
) )
} }
val subInfos = context.getSelectableSubscriptionInfoList() val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.simSlotIndex }) assertThat(subInfos.map { it.simSlotIndex })
.containsExactly(SIM_SLOT_INDEX_1, SubscriptionManager.INVALID_SIM_SLOT_INDEX).inOrder() .containsExactly(SIM_SLOT_INDEX_1, SubscriptionManager.INVALID_SIM_SLOT_INDEX).inOrder()
@@ -164,7 +164,7 @@ class SubscriptionRepositoryTest {
) )
} }
val subInfos = context.getSelectableSubscriptionInfoList() val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_IN_SLOT_0) assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_IN_SLOT_0)
} }
@@ -184,7 +184,7 @@ class SubscriptionRepositoryTest {
) )
} }
val subInfos = context.getSelectableSubscriptionInfoList() val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_3_NOT_IN_SLOT) assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_3_NOT_IN_SLOT)
} }