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

Commit cd00a5db authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

Adds telephony repository and interactor.

This is needed for downstream dependencies to observe the call state.

Bug: 246631653
Test: Unit test included
Change-Id: If7f213dea82581e04620189ca3b13dea3295d9ae
parent 963f710d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.statusbar.window.StatusBarWindowModule;
import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule;
import com.android.systemui.tuner.dagger.TunerModule;
import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
@@ -145,6 +146,7 @@ import dagger.Provides;
            StatusBarWindowModule.class,
            SysUIConcurrencyModule.class,
            SysUIUnfoldModule.class,
            TelephonyRepositoryModule.class,
            TunerModule.class,
            UserModule.class,
            UtilModule.class,
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.systemui.telephony.data.repository

import android.telephony.Annotation
import android.telephony.TelephonyCallback
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.telephony.TelephonyListenerManager
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow

/** Defines interface for classes that encapsulate _some_ telephony-related state. */
interface TelephonyRepository {
    /** The state of the current call. */
    @Annotation.CallState val callState: Flow<Int>
}

/**
 * NOTE: This repository tracks only telephony-related state regarding the default mobile
 * subscription. `TelephonyListenerManager` does not create new instances of `TelephonyManager` on a
 * per-subscription basis and thus will always be tracking telephony information regarding
 * `SubscriptionManager.getDefaultSubscriptionId`. See `TelephonyManager` and `SubscriptionManager`
 * for more documentation.
 */
@SysUISingleton
class TelephonyRepositoryImpl
@Inject
constructor(
    private val manager: TelephonyListenerManager,
) : TelephonyRepository {
    @Annotation.CallState
    override val callState: Flow<Int> = conflatedCallbackFlow {
        val listener = TelephonyCallback.CallStateListener { state -> trySend(state) }

        manager.addCallStateListener(listener)

        awaitClose { manager.removeCallStateListener(listener) }
    }
}
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.systemui.telephony.data.repository

import dagger.Binds
import dagger.Module

@Module
interface TelephonyRepositoryModule {
    @Binds fun repository(impl: TelephonyRepositoryImpl): TelephonyRepository
}
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.systemui.telephony.domain.interactor

import android.telephony.Annotation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.telephony.data.repository.TelephonyRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow

/** Hosts business logic related to telephony. */
@SysUISingleton
class TelephonyInteractor
@Inject
constructor(
    repository: TelephonyRepository,
) {
    @Annotation.CallState val callState: Flow<Int> = repository.callState
}
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.systemui.telephony.data.repository

import android.telephony.TelephonyCallback
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(JUnit4::class)
class TelephonyRepositoryImplTest : SysuiTestCase() {

    @Mock private lateinit var manager: TelephonyListenerManager

    private lateinit var underTest: TelephonyRepositoryImpl

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        underTest =
            TelephonyRepositoryImpl(
                manager = manager,
            )
    }

    @Test
    fun callState() =
        runBlocking(IMMEDIATE) {
            var callState: Int? = null
            val job = underTest.callState.onEach { callState = it }.launchIn(this)
            val listenerCaptor = kotlinArgumentCaptor<TelephonyCallback.CallStateListener>()
            verify(manager).addCallStateListener(listenerCaptor.capture())
            val listener = listenerCaptor.value

            listener.onCallStateChanged(0)
            assertThat(callState).isEqualTo(0)

            listener.onCallStateChanged(1)
            assertThat(callState).isEqualTo(1)

            listener.onCallStateChanged(2)
            assertThat(callState).isEqualTo(2)

            job.cancel()

            verify(manager).removeCallStateListener(listener)
        }

    companion object {
        private val IMMEDIATE = Dispatchers.Main.immediate
    }
}
Loading