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

Commit d48b296b authored by Tom Hsu's avatar Tom Hsu Committed by Android (Google) Code Review
Browse files

Merge "[SystemUI]Check the Satellite modem state instead of enabled state only." into main

parents 4bf690ce 8c40659a
Loading
Loading
Loading
Loading
+110 −14
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.Context
import android.content.Intent
import android.os.OutcomeReceiver
import android.telephony.satellite.SatelliteManager
import android.telephony.satellite.SatelliteModemStateCallback
import android.util.Log
import android.view.WindowManager
import androidx.lifecycle.LifecycleOwner
@@ -31,12 +32,19 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.Job
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeoutException
import kotlin.coroutines.resume
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn

/** A util for Satellite dialog */
object SatelliteDialogUtils {
@@ -70,7 +78,7 @@ object SatelliteDialogUtils {
            coroutineScope.launch {
                var isSatelliteModeOn = false
                try {
                    isSatelliteModeOn = requestIsEnabled(context)
                    isSatelliteModeOn = requestIsSessionStarted(context)
                } catch (e: InterruptedException) {
                    Log.w(TAG, "Error to get satellite status : $e")
                } catch (e: ExecutionException) {
@@ -118,6 +126,7 @@ object SatelliteDialogUtils {
        }

        suspendCancellableCoroutine {continuation ->
            try {
                satelliteManager?.requestIsEnabled(Default.asExecutor(),
                        object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
                            override fun onResult(result: Boolean) {
@@ -131,6 +140,93 @@ object SatelliteDialogUtils {
                                continuation.resume(false)
                            }
                        })
            } catch (e: IllegalStateException) {
                Log.w(TAG, "IllegalStateException: $e")
                continuation.resume(false)
            }
        }
    }

    private suspend fun requestIsSessionStarted(
            context: Context
    ): Boolean = withContext(Default) {
        val satelliteManager: SatelliteManager? =
                context.getSystemService(SatelliteManager::class.java)
        if (satelliteManager == null) {
            Log.w(TAG, "SatelliteManager is null")
            return@withContext false
        }

        getIsSessionStartedFlow(context).conflate().first()
    }

    /**
     * Provides a Flow that emits the session state of the satellite modem. Updates are triggered
     * when the modem state changes.
     *
     * @param defaultDispatcher The CoroutineDispatcher to use (Defaults to `Dispatchers.Default`).
     * @return A Flow emitting `true` when the session is started and `false` otherwise.
     */
    private fun getIsSessionStartedFlow(
            context: Context
    ): Flow<Boolean> {
        val satelliteManager: SatelliteManager? =
                context.getSystemService(SatelliteManager::class.java)
        if (satelliteManager == null) {
            Log.w(TAG, "SatelliteManager is null")
            return flowOf(false)
        }

        return callbackFlow {
            val callback = SatelliteModemStateCallback { state ->
                val isSessionStarted = isSatelliteSessionStarted(state)
                Log.i(TAG, "Satellite modem state changed: state=$state"
                        + ", isSessionStarted=$isSessionStarted")
                trySend(isSessionStarted)
            }

            var registerResult = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN
            try {
                registerResult = satelliteManager.registerForModemStateChanged(
                        Default.asExecutor(),
                        callback
                )
            } catch (e: IllegalStateException) {
                Log.w(TAG, "IllegalStateException: $e")
            }


            if (registerResult != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
                // If the registration failed (e.g., device doesn't support satellite),
                // SatelliteManager will not emit the current state by callback.
                // We send `false` value by ourself to make sure the flow has initial value.
                Log.w(TAG, "Failed to register for satellite modem state change: $registerResult")
                trySend(false)
            }

            awaitClose {
                try {
                    satelliteManager.unregisterForModemStateChanged(callback)
                } catch (e: IllegalStateException) {
                    Log.w(TAG, "IllegalStateException: $e")
                }
            }
        }.flowOn(Default)
    }


    /**
     * Check if the modem is in a satellite session.
     *
     * @param state The SatelliteModemState provided by the SatelliteManager.
     * @return `true` if the modem is in a satellite session, `false` otherwise.
     */
    fun isSatelliteSessionStarted(@SatelliteManager.SatelliteModemState state: Int): Boolean {
        return when (state) {
            SatelliteManager.SATELLITE_MODEM_STATE_OFF,
            SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE,
            SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN -> false
            else -> true
        }
    }

+42 −55
Original line number Diff line number Diff line
@@ -17,11 +17,12 @@
package com.android.settingslib.satellite

import android.content.Context
import android.content.Intent
import android.os.OutcomeReceiver
import android.platform.test.annotations.RequiresFlagsEnabled
import android.telephony.satellite.SatelliteManager
import android.telephony.satellite.SatelliteManager.SatelliteException
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF
import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR
import android.telephony.satellite.SatelliteModemStateCallback
import android.util.AndroidRuntimeException
import androidx.test.core.app.ApplicationProvider
import com.android.internal.telephony.flags.Flags
@@ -67,18 +68,11 @@ class SatelliteDialogUtilsTest {
    @Test
    @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
    fun mayStartSatelliteWarningDialog_satelliteIsOn_showWarningDialog() = runBlocking {
        `when`(
                satelliteManager.requestIsEnabled(
                        any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
                )
        )
        `when`(satelliteManager.registerForModemStateChanged(any(), any()))
                .thenAnswer { invocation ->
                    val receiver = invocation
                            .getArgument<
                                    OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
                                    1
                            )
                    receiver.onResult(true)
                    val callback = invocation
                            .getArgument<SatelliteModemStateCallback>(1)
                    callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_ENABLING_SATELLITE)
                    null
                }

@@ -95,18 +89,11 @@ class SatelliteDialogUtilsTest {
    @Test
    @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
    fun mayStartSatelliteWarningDialog_satelliteIsOff_notShowWarningDialog() = runBlocking {
        `when`(
                satelliteManager.requestIsEnabled(
                        any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
                )
        )
        `when`(satelliteManager.registerForModemStateChanged(any(), any()))
                .thenAnswer { invocation ->
                    val receiver = invocation
                            .getArgument<
                                    OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
                                    1
                            )
                    receiver.onResult(false)
                    val callback = invocation
                            .getArgument<SatelliteModemStateCallback>(1)
                    callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF)
                    null
                }

@@ -116,47 +103,47 @@ class SatelliteDialogUtilsTest {
            assertFalse(it)
        })

        verify(context, Times(0)).startActivity(any<Intent>())
        verify(context, Times(0)).startActivity(any())
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
    fun mayStartSatelliteWarningDialog_noSatelliteManager_notShowWarningDialog() = runBlocking {
        `when`(context.getSystemService(SatelliteManager::class.java))
                .thenReturn(null)
        `when`(context.getSystemService(SatelliteManager::class.java)).thenReturn(null)

        SatelliteDialogUtils.mayStartSatelliteWarningDialog(
                context, coroutineScope, TYPE_IS_WIFI, allowClick = {
            assertFalse(it)
        })

        verify(context, Times(0)).startActivity(any<Intent>())
        verify(context, Times(0)).startActivity(any())
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
    fun mayStartSatelliteWarningDialog_satelliteErrorResult_notShowWarningDialog() = runBlocking {
        `when`(
                satelliteManager.requestIsEnabled(
                        any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>()
                )
        )
                .thenAnswer { invocation ->
                    val receiver = invocation
                            .getArgument<
                                    OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>(
                                    1
                            )
                    receiver.onError(SatelliteException(SatelliteManager.SATELLITE_RESULT_ERROR))
                    null
        `when`(satelliteManager.registerForModemStateChanged(any(), any()))
                .thenReturn(SATELLITE_RESULT_MODEM_ERROR)

        SatelliteDialogUtils.mayStartSatelliteWarningDialog(
                context, coroutineScope, TYPE_IS_WIFI, allowClick = {
            assertFalse(it)
        })

        verify(context, Times(0)).startActivity(any())
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
    fun mayStartSatelliteWarningDialog_phoneCrash_notShowWarningDialog() = runBlocking {
        `when`(satelliteManager.registerForModemStateChanged(any(), any()))
                .thenThrow(IllegalStateException("Telephony is null!!!"))

        SatelliteDialogUtils.mayStartSatelliteWarningDialog(
                context, coroutineScope, TYPE_IS_WIFI, allowClick = {
            assertFalse(it)
        })

        verify(context, Times(0)).startActivity(any<Intent>())
        verify(context, Times(0)).startActivity(any())
    }
}