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

Commit 0745a7f6 authored by Brad Hinegardner's avatar Brad Hinegardner Committed by Automerger Merge Worker
Browse files

Merge "Adjust Mute Quick Affordance to not make binder calls on main thread"...

Merge "Adjust Mute Quick Affordance to not make binder calls on main thread" into tm-qpr-dev am: d56308bc am: e09eefdb

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21159008



Change-Id: Ib8f07b8b74a4faa23e1610a9b8e541563a555766
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents aec294d2 e09eefdb
Loading
Loading
Loading
Loading
+48 −31
Original line number Original line Diff line number Diff line
@@ -27,16 +27,24 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Inject


@SysUISingleton
@SysUISingleton
@@ -46,6 +54,9 @@ class MuteQuickAffordanceConfig @Inject constructor(
        private val userFileManager: UserFileManager,
        private val userFileManager: UserFileManager,
        private val ringerModeTracker: RingerModeTracker,
        private val ringerModeTracker: RingerModeTracker,
        private val audioManager: AudioManager,
        private val audioManager: AudioManager,
        @Application private val coroutineScope: CoroutineScope,
        @Main private val mainDispatcher: CoroutineDispatcher,
        @Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig {
) : KeyguardQuickAffordanceConfig {


    private var previousNonSilentMode: Int = DEFAULT_LAST_NON_SILENT_VALUE
    private var previousNonSilentMode: Int = DEFAULT_LAST_NON_SILENT_VALUE
@@ -58,7 +69,7 @@ class MuteQuickAffordanceConfig @Inject constructor(


    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
        ringerModeTracker.ringerModeInternal.asFlow()
        ringerModeTracker.ringerModeInternal.asFlow()
            .onStart { emit(getLastNonSilentRingerMode()) }
            .onStart { getLastNonSilentRingerMode() }
            .distinctUntilChanged()
            .distinctUntilChanged()
            .onEach { mode ->
            .onEach { mode ->
                // only remember last non-SILENT ringer mode
                // only remember last non-SILENT ringer mode
@@ -87,13 +98,14 @@ class MuteQuickAffordanceConfig @Inject constructor(
                    activationState,
                    activationState,
                )
                )
            }
            }
            .flowOn(backgroundDispatcher)


    override fun onTriggered(
    override fun onTriggered(
        expandable: Expandable?
        expandable: Expandable?
    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
        coroutineScope.launch(backgroundDispatcher) {
            val newRingerMode: Int
            val newRingerMode: Int
        val currentRingerMode =
            val currentRingerMode = audioManager.ringerModeInternal
                ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
            if (currentRingerMode == AudioManager.RINGER_MODE_SILENT) {
            if (currentRingerMode == AudioManager.RINGER_MODE_SILENT) {
                newRingerMode = previousNonSilentMode
                newRingerMode = previousNonSilentMode
            } else {
            } else {
@@ -104,21 +116,25 @@ class MuteQuickAffordanceConfig @Inject constructor(
            if (currentRingerMode != newRingerMode) {
            if (currentRingerMode != newRingerMode) {
                audioManager.ringerModeInternal = newRingerMode
                audioManager.ringerModeInternal = newRingerMode
            }
            }
        }
        return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
        return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
    }
    }


    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState =
    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState =
        withContext(backgroundDispatcher) {
            if (audioManager.isVolumeFixed) {
            if (audioManager.isVolumeFixed) {
                KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
                KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
            } else {
            } else {
                KeyguardQuickAffordanceConfig.PickerScreenState.Default()
                KeyguardQuickAffordanceConfig.PickerScreenState.Default()
            }
            }
        }


    /**
    /**
     * Gets the last non-silent ringer mode from shared-preferences if it exists. This is
     * Gets the last non-silent ringer mode from shared-preferences if it exists. This is
     *  cached by [MuteQuickAffordanceCoreStartable] while this affordance is selected
     *  cached by [MuteQuickAffordanceCoreStartable] while this affordance is selected
     */
     */
    private fun getLastNonSilentRingerMode(): Int =
    private suspend fun getLastNonSilentRingerMode(): Int =
        withContext(backgroundDispatcher) {
            userFileManager.getSharedPreferences(
            userFileManager.getSharedPreferences(
                    MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
                    MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
                    Context.MODE_PRIVATE,
                    Context.MODE_PRIVATE,
@@ -127,6 +143,7 @@ class MuteQuickAffordanceConfig @Inject constructor(
                    LAST_NON_SILENT_RINGER_MODE_KEY,
                    LAST_NON_SILENT_RINGER_MODE_KEY,
                    ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
                    ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
            )
            )
        }


    private fun <T> LiveData<T>.asFlow(): Flow<T?> =
    private fun <T> LiveData<T>.asFlow(): Flow<T?> =
        conflatedCallbackFlow {
        conflatedCallbackFlow {
@@ -134,7 +151,7 @@ class MuteQuickAffordanceConfig @Inject constructor(
            observeForever(observer)
            observeForever(observer)
            send(value)
            send(value)
            awaitClose { removeObserver(observer) }
            awaitClose { removeObserver(observer) }
            }
        }.flowOn(mainDispatcher)


    companion object {
    companion object {
        const val LAST_NON_SILENT_RINGER_MODE_KEY = "key_last_non_silent_ringer_mode"
        const val LAST_NON_SILENT_RINGER_MODE_KEY = "key_last_non_silent_ringer_mode"
+15 −9
Original line number Original line Diff line number Diff line
@@ -23,15 +23,18 @@ import androidx.lifecycle.Observer
import com.android.systemui.CoreStartable
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Inject


/**
/**
@@ -45,6 +48,7 @@ class MuteQuickAffordanceCoreStartable @Inject constructor(
    private val userFileManager: UserFileManager,
    private val userFileManager: UserFileManager,
    private val keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository,
    private val keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository,
    @Application private val coroutineScope: CoroutineScope,
    @Application private val coroutineScope: CoroutineScope,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : CoreStartable {
) : CoreStartable {


    private val observer = Observer(this::updateLastNonSilentRingerMode)
    private val observer = Observer(this::updateLastNonSilentRingerMode)
@@ -72,6 +76,7 @@ class MuteQuickAffordanceCoreStartable @Inject constructor(
    }
    }


    private fun updateLastNonSilentRingerMode(lastRingerMode: Int) {
    private fun updateLastNonSilentRingerMode(lastRingerMode: Int) {
        coroutineScope.launch(backgroundDispatcher) {
            if (AudioManager.RINGER_MODE_SILENT != lastRingerMode) {
            if (AudioManager.RINGER_MODE_SILENT != lastRingerMode) {
                userFileManager.getSharedPreferences(
                userFileManager.getSharedPreferences(
                        MuteQuickAffordanceConfig.MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
                        MuteQuickAffordanceConfig.MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
@@ -84,3 +89,4 @@ class MuteQuickAffordanceCoreStartable @Inject constructor(
            }
            }
        }
        }
    }
    }
}
 No newline at end of file
+17 −13
Original line number Original line Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.quickaffordance


import android.content.Context
import android.content.Context
import android.media.AudioManager
import android.media.AudioManager
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserFileManager
@@ -27,10 +26,12 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Before
@@ -57,13 +58,15 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
    @Mock
    @Mock
    private lateinit var userFileManager: UserFileManager
    private lateinit var userFileManager: UserFileManager


    private lateinit var testDispatcher: TestDispatcher
    private lateinit var testScope: TestScope
    private lateinit var testScope: TestScope


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


        testScope = TestScope()
        testDispatcher = StandardTestDispatcher()
        testScope = TestScope(testDispatcher)


        whenever(userTracker.userContext).thenReturn(context)
        whenever(userTracker.userContext).thenReturn(context)
        whenever(userFileManager.getSharedPreferences(any(), any(), any()))
        whenever(userFileManager.getSharedPreferences(any(), any(), any()))
@@ -74,7 +77,10 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
                userTracker,
                userTracker,
                userFileManager,
                userFileManager,
                ringerModeTracker,
                ringerModeTracker,
                audioManager
                audioManager,
                testScope.backgroundScope,
                testDispatcher,
                testDispatcher,
        )
        )
    }
    }


@@ -103,17 +109,16 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    fun `triggered - state was previously NORMAL - currently SILENT - move to previous state`() {
    fun `triggered - state was previously NORMAL - currently SILENT - move to previous state`() = testScope.runTest {
        //given
        //given
        val ringerModeCapture = argumentCaptor<Int>()
        val ringerModeCapture = argumentCaptor<Int>()
        val ringerModeInternal = mock<LiveData<Int>>()
        whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
        whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
        whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_NORMAL)
        underTest.onTriggered(null)
        underTest.onTriggered(null)
        whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_SILENT)
        whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_SILENT)


        //when
        //when
        val result = underTest.onTriggered(null)
        val result = underTest.onTriggered(null)
        runCurrent()
        verify(audioManager, times(2)).ringerModeInternal = ringerModeCapture.capture()
        verify(audioManager, times(2)).ringerModeInternal = ringerModeCapture.capture()


        //then
        //then
@@ -122,15 +127,14 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    fun `triggered - state is not SILENT - move to SILENT ringer`() {
    fun `triggered - state is not SILENT - move to SILENT ringer`() = testScope.runTest {
        //given
        //given
        val ringerModeCapture = argumentCaptor<Int>()
        val ringerModeCapture = argumentCaptor<Int>()
        val ringerModeInternal = mock<LiveData<Int>>()
        whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
        whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
        whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_NORMAL)


        //when
        //when
        val result = underTest.onTriggered(null)
        val result = underTest.onTriggered(null)
        runCurrent()
        verify(audioManager).ringerModeInternal = ringerModeCapture.capture()
        verify(audioManager).ringerModeInternal = ringerModeCapture.capture()


        //then
        //then
+8 −2
Original line number Original line Diff line number Diff line
@@ -37,6 +37,8 @@ import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
@@ -67,6 +69,7 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
    @Mock
    @Mock
    private lateinit var keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository
    private lateinit var keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository


    private lateinit var testDispatcher: TestDispatcher
    private lateinit var testScope: TestScope
    private lateinit var testScope: TestScope


    private lateinit var underTest: MuteQuickAffordanceCoreStartable
    private lateinit var underTest: MuteQuickAffordanceCoreStartable
@@ -83,7 +86,8 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
        val emission = MutableStateFlow(mapOf("testQuickAffordanceKey" to listOf(config)))
        val emission = MutableStateFlow(mapOf("testQuickAffordanceKey" to listOf(config)))
        whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission)
        whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission)


        testScope = TestScope()
        testDispatcher = StandardTestDispatcher()
        testScope = TestScope(testDispatcher)


        underTest = MuteQuickAffordanceCoreStartable(
        underTest = MuteQuickAffordanceCoreStartable(
            featureFlags,
            featureFlags,
@@ -91,7 +95,8 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
            ringerModeTracker,
            ringerModeTracker,
            userFileManager,
            userFileManager,
            keyguardQuickAffordanceRepository,
            keyguardQuickAffordanceRepository,
            testScope,
            testScope.backgroundScope,
            testDispatcher,
        )
        )
    }
    }


@@ -158,6 +163,7 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
        runCurrent()
        runCurrent()
        verify(ringerModeInternal).observeForever(observerCaptor.capture())
        verify(ringerModeInternal).observeForever(observerCaptor.capture())
        observerCaptor.value.onChanged(newRingerMode)
        observerCaptor.value.onChanged(newRingerMode)
        runCurrent()
        val result = sharedPrefs.getInt("key_last_non_silent_ringer_mode", -1)
        val result = sharedPrefs.getInt("key_last_non_silent_ringer_mode", -1)


        //then
        //then
+1 −1
Original line number Original line Diff line number Diff line
@@ -21,7 +21,7 @@ import android.hardware.display.DisplayManager
import android.view.Display
import android.view.Display
import java.util.concurrent.Executor
import java.util.concurrent.Executor


class FakeDisplayTracker internal constructor(val context: Context) : DisplayTracker {
class FakeDisplayTracker constructor(val context: Context) : DisplayTracker {
    val displayManager: DisplayManager = context.getSystemService(DisplayManager::class.java)!!
    val displayManager: DisplayManager = context.getSystemService(DisplayManager::class.java)!!
    override var defaultDisplayId: Int = Display.DEFAULT_DISPLAY
    override var defaultDisplayId: Int = Display.DEFAULT_DISPLAY
    override var allDisplays: Array<Display> = displayManager.displays
    override var allDisplays: Array<Display> = displayManager.displays