Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd2cc366 authored by SongFerng Wang's avatar SongFerng Wang Committed by Android (Google) Code Review
Browse files

Merge "Add condition whether esim is visible or not" into main

parents 64bfa1cb ec27c604
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@ package com.android.settings.network
import android.app.Application
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager

import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
@@ -32,13 +34,12 @@ import kotlinx.coroutines.plus

class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel(application) {
    private val scope = viewModelScope + Dispatchers.Default

    val subscriptionInfoListFlow = callbackFlow<List<SubscriptionInfo>> {
        val subscriptionManager = application.getSystemService(SubscriptionManager::class.java)!!

        val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
            override fun onSubscriptionsChanged() {
                trySend(subscriptionManager.activeSubscriptionInfoList ?: emptyList())
                trySend(SubscriptionUtil.getActiveSubscriptions(subscriptionManager))
            }
        }

+37 −3
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.settings.network;

import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
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 android.annotation.Nullable;
@@ -36,9 +38,11 @@ import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.flags.Flags;
import com.android.settings.R;
import com.android.settings.network.helper.SelectableSubscriptions;
import com.android.settings.network.helper.SubscriptionAnnotation;
@@ -84,6 +88,8 @@ public class SubscriptionUtil {
    }

    public static List<SubscriptionInfo> getActiveSubscriptions(SubscriptionManager manager) {
        //TODO (b/315499317) : Refactor the subscription utils.

        if (sActiveResultsForTesting != null) {
            return sActiveResultsForTesting;
        }
@@ -94,7 +100,12 @@ public class SubscriptionUtil {
        if (subscriptions == null) {
            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.
     *
     * @param context {@code Context}
@@ -138,13 +149,20 @@ public class SubscriptionUtil {
     * @return {@code SubscriptionInfo} based on the given subscription id. Null of subscription
     *         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) {
        //TODO (b/315499317) : Refactor the subscription utils.
        final SubscriptionInfo subInfo = subscriptionManager.getAccessibleSubscriptionInfo(subId);
        if (subInfo == 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();

        if (groupUuid != null) {
@@ -567,6 +585,12 @@ public class SubscriptionUtil {
    public static boolean isSubscriptionVisible(
            SubscriptionManager subscriptionManager, Context context, SubscriptionInfo info) {
        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 (info.getGroupUuid() == null || !info.isOpportunistic()) return true;

@@ -786,4 +810,14 @@ public class SubscriptionUtil {
        }
        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;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -521,7 +521,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
         * Uses to inject function and value for class and test class.
         */
        public boolean canSubscriptionBeDisplayed(Context context, int subId) {
            return (SubscriptionUtil.getAvailableSubscription(context,
            return (SubscriptionUtil.getAvailableSubscriptionBySubIdAndShowingForUser(context,
                    ProxySubscriptionManager.getInstance(context), subId) != null);
        }

+153 −0
Original line number Diff line number Diff line
/*
 * 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()
    }
}
 No newline at end of file