Merge "Do not set Notetaking shortcut to default if Stylus is not detected" into udc-dev am: 26ac560f85
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21649738 Change-Id: I8b550850da943375571fa062b60af9c3c32f0f3a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.notetask.quickaffordance
|
package com.android.systemui.notetask.quickaffordance
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.hardware.input.InputSettings
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.animation.Expandable
|
import com.android.systemui.animation.Expandable
|
||||||
import com.android.systemui.common.shared.model.ContentDescription
|
import com.android.systemui.common.shared.model.ContentDescription
|
||||||
@@ -26,36 +27,52 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc
|
|||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
|
||||||
|
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
|
||||||
import com.android.systemui.notetask.NoteTaskController
|
import com.android.systemui.notetask.NoteTaskController
|
||||||
import com.android.systemui.notetask.NoteTaskEnabledKey
|
import com.android.systemui.notetask.NoteTaskEnabledKey
|
||||||
import com.android.systemui.notetask.NoteTaskEntryPoint
|
import com.android.systemui.notetask.NoteTaskEntryPoint
|
||||||
|
import com.android.systemui.stylus.StylusManager
|
||||||
|
import dagger.Lazy
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.channels.trySendBlocking
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
class NoteTaskQuickAffordanceConfig
|
class NoteTaskQuickAffordanceConfig
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val noteTaskController: NoteTaskController,
|
private val controller: NoteTaskController,
|
||||||
|
private val stylusManager: StylusManager,
|
||||||
|
private val lazyRepository: Lazy<KeyguardQuickAffordanceRepository>,
|
||||||
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
||||||
) : KeyguardQuickAffordanceConfig {
|
) : KeyguardQuickAffordanceConfig {
|
||||||
|
|
||||||
override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
|
override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
|
||||||
|
|
||||||
override val pickerName: String = context.getString(R.string.note_task_button_label)
|
private val pickerNameResourceId = R.string.note_task_button_label
|
||||||
|
|
||||||
|
override val pickerName: String = context.getString(pickerNameResourceId)
|
||||||
|
|
||||||
override val pickerIconResourceId = R.drawable.ic_note_task_shortcut_keyguard
|
override val pickerIconResourceId = R.drawable.ic_note_task_shortcut_keyguard
|
||||||
|
|
||||||
override val lockScreenState = flowOf(getLockScreenState())
|
// Due to a dependency cycle with KeyguardQuickAffordanceRepository, we need to lazily access
|
||||||
|
// the repository when lockScreenState is accessed for the first time.
|
||||||
// TODO(b/265949213)
|
override val lockScreenState by lazy {
|
||||||
private fun getLockScreenState() =
|
val stylusEverUsedFlow = createStylusEverUsedFlow(context, stylusManager)
|
||||||
if (isEnabled) {
|
val configSelectedFlow = createConfigSelectedFlow(lazyRepository.get(), key)
|
||||||
val icon = Icon.Resource(pickerIconResourceId, ContentDescription.Loaded(pickerName))
|
combine(configSelectedFlow, stylusEverUsedFlow) { isSelected, isStylusEverUsed ->
|
||||||
|
if (isEnabled && (isSelected || isStylusEverUsed)) {
|
||||||
|
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
|
||||||
|
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
|
||||||
LockScreenState.Visible(icon)
|
LockScreenState.Visible(icon)
|
||||||
} else {
|
} else {
|
||||||
LockScreenState.Hidden
|
LockScreenState.Hidden
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getPickerScreenState() =
|
override suspend fun getPickerScreenState() =
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
@@ -65,9 +82,27 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
|
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
|
||||||
noteTaskController.showNoteTask(
|
controller.showNoteTask(
|
||||||
entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE,
|
entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE,
|
||||||
)
|
)
|
||||||
return OnTriggeredResult.Handled
|
return OnTriggeredResult.Handled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createStylusEverUsedFlow(context: Context, stylusManager: StylusManager) =
|
||||||
|
callbackFlow {
|
||||||
|
trySendBlocking(InputSettings.isStylusEverUsed(context))
|
||||||
|
val callback =
|
||||||
|
object : StylusManager.StylusCallback {
|
||||||
|
override fun onStylusFirstUsed() {
|
||||||
|
trySendBlocking(InputSettings.isStylusEverUsed(context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stylusManager.registerCallback(callback)
|
||||||
|
awaitClose { stylusManager.unregisterCallback(callback) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createConfigSelectedFlow(repository: KeyguardQuickAffordanceRepository, key: String) =
|
||||||
|
repository.selections.map { selected ->
|
||||||
|
selected.values.flatten().any { selectedConfig -> selectedConfig.key == key }
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,75 +18,139 @@
|
|||||||
|
|
||||||
package com.android.systemui.notetask.quickaffordance
|
package com.android.systemui.notetask.quickaffordance
|
||||||
|
|
||||||
|
import android.hardware.input.InputSettings
|
||||||
import android.test.suitebuilder.annotation.SmallTest
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import android.testing.AndroidTestingRunner
|
||||||
|
import com.android.dx.mockito.inline.extended.ExtendedMockito
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
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.coroutines.collectLastValue
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
||||||
|
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
|
||||||
import com.android.systemui.notetask.NoteTaskController
|
import com.android.systemui.notetask.NoteTaskController
|
||||||
import com.android.systemui.notetask.NoteTaskEntryPoint
|
import com.android.systemui.notetask.NoteTaskEntryPoint
|
||||||
|
import com.android.systemui.stylus.StylusManager
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoSession
|
||||||
|
import org.mockito.quality.Strictness
|
||||||
|
|
||||||
/**
|
/** atest SystemUITests:NoteTaskQuickAffordanceConfigTest */
|
||||||
* Tests for [NoteTaskQuickAffordanceConfig].
|
|
||||||
*
|
|
||||||
* Build/Install/Run:
|
|
||||||
* - atest SystemUITests:NoteTaskQuickAffordanceConfigTest
|
|
||||||
*/
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||||
|
|
||||||
@Mock lateinit var noteTaskController: NoteTaskController
|
@Mock lateinit var controller: NoteTaskController
|
||||||
|
@Mock lateinit var stylusManager: StylusManager
|
||||||
|
@Mock lateinit var repository: KeyguardQuickAffordanceRepository
|
||||||
|
|
||||||
|
private lateinit var mockitoSession: MockitoSession
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
mockitoSession =
|
||||||
|
ExtendedMockito.mockitoSession()
|
||||||
|
.initMocks(this)
|
||||||
|
.mockStatic(InputSettings::class.java)
|
||||||
|
.strictness(Strictness.LENIENT)
|
||||||
|
.startMocking()
|
||||||
|
|
||||||
|
whenever(InputSettings.isStylusEverUsed(mContext)).then { true }
|
||||||
|
whenever(repository.selections).then {
|
||||||
|
val map = mapOf("" to listOf(createUnderTest()))
|
||||||
|
MutableStateFlow(map)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createUnderTest(isEnabled: Boolean) =
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
mockitoSession.finishMocking()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createUnderTest(isEnabled: Boolean = true): KeyguardQuickAffordanceConfig =
|
||||||
NoteTaskQuickAffordanceConfig(
|
NoteTaskQuickAffordanceConfig(
|
||||||
context = context,
|
context = context,
|
||||||
noteTaskController = noteTaskController,
|
controller = controller,
|
||||||
|
stylusManager = stylusManager,
|
||||||
|
lazyRepository = { repository },
|
||||||
isEnabled = isEnabled,
|
isEnabled = isEnabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun createLockScreenStateVisible(): LockScreenState =
|
||||||
|
LockScreenState.Visible(
|
||||||
|
icon =
|
||||||
|
Icon.Resource(
|
||||||
|
res = R.drawable.ic_note_task_shortcut_keyguard,
|
||||||
|
contentDescription =
|
||||||
|
ContentDescription.Resource(R.string.note_task_button_label),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockScreenState_stylusUsed_noCustomShortcutSelected_shouldEmitVisible() = runTest {
|
||||||
|
val underTest = createUnderTest()
|
||||||
|
|
||||||
|
val actual by collectLastValue(underTest.lockScreenState)
|
||||||
|
|
||||||
|
assertThat(actual).isEqualTo(createLockScreenStateVisible())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockScreenState_noStylusEverUsed_noCustomShortcutSelected_shouldEmitVisible() = runTest {
|
||||||
|
whenever(InputSettings.isStylusEverUsed(mContext)).then { false }
|
||||||
|
val underTest = createUnderTest()
|
||||||
|
|
||||||
|
val actual by collectLastValue(underTest.lockScreenState)
|
||||||
|
|
||||||
|
assertThat(actual).isEqualTo(createLockScreenStateVisible())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockScreenState_stylusUsed_customShortcutSelected_shouldEmitVisible() = runTest {
|
||||||
|
whenever(repository.selections).then {
|
||||||
|
val map = mapOf<String, List<KeyguardQuickAffordanceConfig>>()
|
||||||
|
MutableStateFlow(map)
|
||||||
|
}
|
||||||
|
val underTest = createUnderTest()
|
||||||
|
|
||||||
|
val actual by collectLastValue(underTest.lockScreenState)
|
||||||
|
|
||||||
|
assertThat(actual).isEqualTo(createLockScreenStateVisible())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockScreenState_noIsStylusEverUsed_noCustomShortcutSelected_shouldEmitHidden() = runTest {
|
||||||
|
whenever(InputSettings.isStylusEverUsed(mContext)).then { false }
|
||||||
|
whenever(repository.selections).then {
|
||||||
|
val map = mapOf<String, List<KeyguardQuickAffordanceConfig>>()
|
||||||
|
MutableStateFlow(map)
|
||||||
|
}
|
||||||
|
val underTest = createUnderTest()
|
||||||
|
|
||||||
|
val actual by collectLastValue(underTest.lockScreenState)
|
||||||
|
|
||||||
|
assertThat(actual).isEqualTo(LockScreenState.Hidden)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
|
fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
|
||||||
val underTest = createUnderTest(isEnabled = false)
|
val underTest = createUnderTest(isEnabled = false)
|
||||||
|
|
||||||
val actual = collectLastValue(underTest.lockScreenState)
|
val actual by collectLastValue(underTest.lockScreenState)
|
||||||
|
|
||||||
assertThat(actual()).isEqualTo(LockScreenState.Hidden)
|
assertThat(actual).isEqualTo(LockScreenState.Hidden)
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun lockScreenState_isEnabled_shouldEmitVisible() = runTest {
|
|
||||||
val stringResult = "Notetaking"
|
|
||||||
val underTest = createUnderTest(isEnabled = true)
|
|
||||||
|
|
||||||
val actual = collectLastValue(underTest.lockScreenState)
|
|
||||||
|
|
||||||
val expected =
|
|
||||||
LockScreenState.Visible(
|
|
||||||
icon =
|
|
||||||
Icon.Resource(
|
|
||||||
res = R.drawable.ic_note_task_shortcut_keyguard,
|
|
||||||
contentDescription = ContentDescription.Loaded(stringResult),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
assertThat(actual()).isEqualTo(expected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -95,6 +159,6 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
|||||||
|
|
||||||
underTest.onTriggered(expandable = null)
|
underTest.onTriggered(expandable = null)
|
||||||
|
|
||||||
verify(noteTaskController).showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user