Skip to content
Snippets Groups Projects
Commit ee68eee9 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: Ie03859c3fd20b8c228f440f8f8e6c700fcda95ed
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 001130e7 e09eefdb
No related branches found
No related tags found
No related merge requests found
......@@ -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.Icon
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.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@SysUISingleton
......@@ -46,6 +54,9 @@ class MuteQuickAffordanceConfig @Inject constructor(
private val userFileManager: UserFileManager,
private val ringerModeTracker: RingerModeTracker,
private val audioManager: AudioManager,
@Application private val coroutineScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig {
private var previousNonSilentMode: Int = DEFAULT_LAST_NON_SILENT_VALUE
......@@ -58,7 +69,7 @@ class MuteQuickAffordanceConfig @Inject constructor(
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
ringerModeTracker.ringerModeInternal.asFlow()
.onStart { emit(getLastNonSilentRingerMode()) }
.onStart { getLastNonSilentRingerMode() }
.distinctUntilChanged()
.onEach { mode ->
// only remember last non-SILENT ringer mode
......@@ -87,54 +98,60 @@ class MuteQuickAffordanceConfig @Inject constructor(
activationState,
)
}
.flowOn(backgroundDispatcher)
override fun onTriggered(
expandable: Expandable?
): KeyguardQuickAffordanceConfig.OnTriggeredResult {
val newRingerMode: Int
val currentRingerMode =
ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
if (currentRingerMode == AudioManager.RINGER_MODE_SILENT) {
newRingerMode = previousNonSilentMode
} else {
previousNonSilentMode = currentRingerMode
newRingerMode = AudioManager.RINGER_MODE_SILENT
}
coroutineScope.launch(backgroundDispatcher) {
val newRingerMode: Int
val currentRingerMode = audioManager.ringerModeInternal
if (currentRingerMode == AudioManager.RINGER_MODE_SILENT) {
newRingerMode = previousNonSilentMode
} else {
previousNonSilentMode = currentRingerMode
newRingerMode = AudioManager.RINGER_MODE_SILENT
}
if (currentRingerMode != newRingerMode) {
audioManager.ringerModeInternal = newRingerMode
if (currentRingerMode != newRingerMode) {
audioManager.ringerModeInternal = newRingerMode
}
}
return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState =
if (audioManager.isVolumeFixed) {
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
} else {
KeyguardQuickAffordanceConfig.PickerScreenState.Default()
withContext(backgroundDispatcher) {
if (audioManager.isVolumeFixed) {
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
} else {
KeyguardQuickAffordanceConfig.PickerScreenState.Default()
}
}
/**
* Gets the last non-silent ringer mode from shared-preferences if it exists. This is
* cached by [MuteQuickAffordanceCoreStartable] while this affordance is selected
*/
private fun getLastNonSilentRingerMode(): Int =
userFileManager.getSharedPreferences(
MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
Context.MODE_PRIVATE,
userTracker.userId
).getInt(
LAST_NON_SILENT_RINGER_MODE_KEY,
ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
)
private suspend fun getLastNonSilentRingerMode(): Int =
withContext(backgroundDispatcher) {
userFileManager.getSharedPreferences(
MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
Context.MODE_PRIVATE,
userTracker.userId
).getInt(
LAST_NON_SILENT_RINGER_MODE_KEY,
ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE
)
}
private fun <T> LiveData<T>.asFlow(): Flow<T?> =
conflatedCallbackFlow {
val observer = Observer { value: T -> trySend(value) }
observeForever(observer)
send(value)
awaitClose { removeObserver(observer) }
}
conflatedCallbackFlow {
val observer = Observer { value: T -> trySend(value) }
observeForever(observer)
send(value)
awaitClose { removeObserver(observer) }
}.flowOn(mainDispatcher)
companion object {
const val LAST_NON_SILENT_RINGER_MODE_KEY = "key_last_non_silent_ringer_mode"
......
......@@ -23,15 +23,18 @@ import androidx.lifecycle.Observer
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
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.Flags
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.RingerModeTracker
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
......@@ -45,6 +48,7 @@ class MuteQuickAffordanceCoreStartable @Inject constructor(
private val userFileManager: UserFileManager,
private val keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository,
@Application private val coroutineScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : CoreStartable {
private val observer = Observer(this::updateLastNonSilentRingerMode)
......@@ -72,15 +76,17 @@ class MuteQuickAffordanceCoreStartable @Inject constructor(
}
private fun updateLastNonSilentRingerMode(lastRingerMode: Int) {
if (AudioManager.RINGER_MODE_SILENT != lastRingerMode) {
userFileManager.getSharedPreferences(
MuteQuickAffordanceConfig.MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
Context.MODE_PRIVATE,
userTracker.userId
)
.edit()
.putInt(MuteQuickAffordanceConfig.LAST_NON_SILENT_RINGER_MODE_KEY, lastRingerMode)
.apply()
coroutineScope.launch(backgroundDispatcher) {
if (AudioManager.RINGER_MODE_SILENT != lastRingerMode) {
userFileManager.getSharedPreferences(
MuteQuickAffordanceConfig.MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME,
Context.MODE_PRIVATE,
userTracker.userId
)
.edit()
.putInt(MuteQuickAffordanceConfig.LAST_NON_SILENT_RINGER_MODE_KEY, lastRingerMode)
.apply()
}
}
}
}
\ No newline at end of file
......@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
import android.media.AudioManager
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
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.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
......@@ -57,13 +58,15 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
@Mock
private lateinit var userFileManager: UserFileManager
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
testScope = TestScope()
testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
whenever(userTracker.userContext).thenReturn(context)
whenever(userFileManager.getSharedPreferences(any(), any(), any()))
......@@ -74,7 +77,10 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
userTracker,
userFileManager,
ringerModeTracker,
audioManager
audioManager,
testScope.backgroundScope,
testDispatcher,
testDispatcher,
)
}
......@@ -103,17 +109,16 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
}
@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
val ringerModeCapture = argumentCaptor<Int>()
val ringerModeInternal = mock<LiveData<Int>>()
whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_NORMAL)
whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
underTest.onTriggered(null)
whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_SILENT)
whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_SILENT)
//when
val result = underTest.onTriggered(null)
runCurrent()
verify(audioManager, times(2)).ringerModeInternal = ringerModeCapture.capture()
//then
......@@ -122,15 +127,14 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
fun `triggered - state is not SILENT - move to SILENT ringer`() {
fun `triggered - state is not SILENT - move to SILENT ringer`() = testScope.runTest {
//given
val ringerModeCapture = argumentCaptor<Int>()
val ringerModeInternal = mock<LiveData<Int>>()
whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
whenever(ringerModeInternal.value).thenReturn(AudioManager.RINGER_MODE_NORMAL)
whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
//when
val result = underTest.onTriggered(null)
runCurrent()
verify(audioManager).ringerModeInternal = ringerModeCapture.capture()
//then
......
......@@ -37,6 +37,8 @@ import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
......@@ -67,6 +69,7 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
@Mock
private lateinit var keyguardQuickAffordanceRepository: KeyguardQuickAffordanceRepository
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
private lateinit var underTest: MuteQuickAffordanceCoreStartable
......@@ -83,7 +86,8 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
val emission = MutableStateFlow(mapOf("testQuickAffordanceKey" to listOf(config)))
whenever(keyguardQuickAffordanceRepository.selections).thenReturn(emission)
testScope = TestScope()
testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
underTest = MuteQuickAffordanceCoreStartable(
featureFlags,
......@@ -91,7 +95,8 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
ringerModeTracker,
userFileManager,
keyguardQuickAffordanceRepository,
testScope,
testScope.backgroundScope,
testDispatcher,
)
}
......@@ -158,6 +163,7 @@ class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
runCurrent()
verify(ringerModeInternal).observeForever(observerCaptor.capture())
observerCaptor.value.onChanged(newRingerMode)
runCurrent()
val result = sharedPrefs.getInt("key_last_non_silent_ringer_mode", -1)
//then
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment