[flexiglass] Fetch InputMethod subtypes using the explicit user ID.
IME subtypes were being fetched without passing in a user ID, which
fetches them for the currently-selected user by default.
Fix: 354968281
Flag: com.android.systemui.scene_container
Test: Updated unit tests, and existing ones still pass.
Change-Id: I6d2ee05d6c816ecf23e8ec313a2a53e64d8db06f
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index c28cf34..a09189e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -372,6 +372,7 @@
nonAuxiliarySubtypes: Int,
): InputMethodModel {
return InputMethodModel(
+ userId = UUID.randomUUID().mostSignificantBits.toInt(),
imeId = UUID.randomUUID().toString(),
subtypes =
List(auxiliarySubtypes + nonAuxiliarySubtypes) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/data/repository/InputMethodRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/data/repository/InputMethodRepositoryTest.kt
index 857cdce..274880b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/data/repository/InputMethodRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/data/repository/InputMethodRepositoryTest.kt
@@ -56,9 +56,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(inputMethodManager.getEnabledInputMethodSubtypeList(eq(null), anyBoolean()))
- .thenReturn(listOf())
-
underTest =
InputMethodRepositoryImpl(
backgroundDispatcher = kosmos.testDispatcher,
@@ -71,10 +68,16 @@
testScope.runTest {
whenever(inputMethodManager.getEnabledInputMethodListAsUser(eq(USER_HANDLE)))
.thenReturn(listOf())
- whenever(inputMethodManager.getEnabledInputMethodSubtypeList(any(), anyBoolean()))
+ whenever(
+ inputMethodManager.getEnabledInputMethodSubtypeListAsUser(
+ any(),
+ anyBoolean(),
+ eq(USER_HANDLE)
+ )
+ )
.thenReturn(listOf())
- assertThat(underTest.enabledInputMethods(USER_ID, fetchSubtypes = true).count())
+ assertThat(underTest.enabledInputMethods(USER_HANDLE, fetchSubtypes = true).count())
.isEqualTo(0)
}
@@ -83,11 +86,20 @@
testScope.runTest {
val subtypeId = 123
val isAuxiliary = true
+ val selectedImiId = "imiId"
+ val selectedImi = mock<InputMethodInfo>()
+ whenever(selectedImi.id).thenReturn(selectedImiId)
+ whenever(inputMethodManager.getCurrentInputMethodInfoAsUser(eq(USER_HANDLE)))
+ .thenReturn(selectedImi)
whenever(inputMethodManager.getEnabledInputMethodListAsUser(eq(USER_HANDLE)))
- .thenReturn(listOf(mock<InputMethodInfo>()))
- whenever(inputMethodManager.getEnabledInputMethodSubtypeList(any(), anyBoolean()))
- .thenReturn(listOf())
- whenever(inputMethodManager.getEnabledInputMethodSubtypeList(eq(null), anyBoolean()))
+ .thenReturn(listOf(selectedImi))
+ whenever(
+ inputMethodManager.getEnabledInputMethodSubtypeListAsUser(
+ eq(selectedImiId),
+ anyBoolean(),
+ eq(USER_HANDLE)
+ )
+ )
.thenReturn(
listOf(
InputMethodSubtype.InputMethodSubtypeBuilder()
@@ -97,7 +109,7 @@
)
)
- val result = underTest.selectedInputMethodSubtypes()
+ val result = underTest.selectedInputMethodSubtypes(USER_HANDLE)
assertThat(result).hasSize(1)
assertThat(result.first().subtypeId).isEqualTo(subtypeId)
assertThat(result.first().isAuxiliary).isEqualTo(isAuxiliary)
@@ -108,7 +120,7 @@
testScope.runTest {
val displayId = 7
- underTest.showInputMethodPicker(displayId, /* showAuxiliarySubtypes = */ true)
+ underTest.showInputMethodPicker(displayId, /* showAuxiliarySubtypes= */ true)
verify(inputMethodManager)
.showInputMethodPickerFromSystem(
@@ -118,7 +130,6 @@
}
companion object {
- private const val USER_ID = 100
- private val USER_HANDLE = UserHandle.of(USER_ID)
+ private val USER_HANDLE = UserHandle.of(100)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractorTest.kt
index d23ff2a..8e6de2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractorTest.kt
@@ -143,6 +143,7 @@
nonAuxiliarySubtypes: Int,
): InputMethodModel {
return InputMethodModel(
+ userId = UUID.randomUUID().mostSignificantBits.toInt(),
imeId = UUID.randomUUID().toString(),
subtypes =
List(auxiliarySubtypes + nonAuxiliarySubtypes) {
diff --git a/packages/SystemUI/src/com/android/systemui/inputmethod/data/model/InputMethodModel.kt b/packages/SystemUI/src/com/android/systemui/inputmethod/data/model/InputMethodModel.kt
index bdc18b3..0e19d87 100644
--- a/packages/SystemUI/src/com/android/systemui/inputmethod/data/model/InputMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputmethod/data/model/InputMethodModel.kt
@@ -22,6 +22,8 @@
* @see android.view.inputmethod.InputMethodInfo
*/
data class InputMethodModel(
+ /** A unique ID for the user associated with this input method. */
+ val userId: Int,
/** A unique ID for this input method. */
val imeId: String,
/** The subtypes of this IME (may be empty). */
diff --git a/packages/SystemUI/src/com/android/systemui/inputmethod/data/repository/InputMethodRepository.kt b/packages/SystemUI/src/com/android/systemui/inputmethod/data/repository/InputMethodRepository.kt
index 5f316c4..c6fdc32 100644
--- a/packages/SystemUI/src/com/android/systemui/inputmethod/data/repository/InputMethodRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputmethod/data/repository/InputMethodRepository.kt
@@ -18,7 +18,6 @@
import android.annotation.SuppressLint
import android.os.UserHandle
-import android.view.inputmethod.InputMethodInfo
import android.view.inputmethod.InputMethodManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -34,18 +33,27 @@
/** Provides access to input-method related application state in the bouncer. */
interface InputMethodRepository {
+
/**
* Creates and returns a new `Flow` of installed input methods that are enabled for the
* specified user.
*
+ * @param user The user to query.
* @param fetchSubtypes Whether to fetch the IME Subtypes as well (requires an additional IPC
* call for each IME, avoid if not needed).
* @see InputMethodManager.getEnabledInputMethodListAsUser
*/
- suspend fun enabledInputMethods(userId: Int, fetchSubtypes: Boolean): Flow<InputMethodModel>
+ suspend fun enabledInputMethods(
+ user: UserHandle,
+ fetchSubtypes: Boolean,
+ ): Flow<InputMethodModel>
- /** Returns enabled subtypes for the currently selected input method. */
- suspend fun selectedInputMethodSubtypes(): List<InputMethodModel.Subtype>
+ /**
+ * Returns enabled subtypes for the currently selected input method.
+ *
+ * @param user The user to query.
+ */
+ suspend fun selectedInputMethodSubtypes(user: UserHandle): List<InputMethodModel.Subtype>
/**
* Shows the system's input method picker dialog.
@@ -67,20 +75,22 @@
) : InputMethodRepository {
override suspend fun enabledInputMethods(
- userId: Int,
+ user: UserHandle,
fetchSubtypes: Boolean
): Flow<InputMethodModel> {
return withContext(backgroundDispatcher) {
- inputMethodManager.getEnabledInputMethodListAsUser(UserHandle.of(userId))
+ inputMethodManager.getEnabledInputMethodListAsUser(user)
}
.asFlow()
.map { inputMethodInfo ->
InputMethodModel(
+ userId = user.identifier,
imeId = inputMethodInfo.id,
subtypes =
if (fetchSubtypes) {
enabledInputMethodSubtypes(
- inputMethodInfo,
+ user = user,
+ imeId = inputMethodInfo.id,
allowsImplicitlyEnabledSubtypes = true
)
} else {
@@ -90,11 +100,19 @@
}
}
- override suspend fun selectedInputMethodSubtypes(): List<InputMethodModel.Subtype> {
- return enabledInputMethodSubtypes(
- inputMethodInfo = null, // Fetch subtypes for the currently-selected IME.
- allowsImplicitlyEnabledSubtypes = false
- )
+ override suspend fun selectedInputMethodSubtypes(
+ user: UserHandle,
+ ): List<InputMethodModel.Subtype> {
+ val selectedIme = inputMethodManager.getCurrentInputMethodInfoAsUser(user)
+ return if (selectedIme == null) {
+ emptyList()
+ } else {
+ enabledInputMethodSubtypes(
+ user = user,
+ imeId = selectedIme.id,
+ allowsImplicitlyEnabledSubtypes = false
+ )
+ }
}
@SuppressLint("MissingPermission")
@@ -107,21 +125,23 @@
/**
* Returns a list of enabled input method subtypes for the specified input method info.
*
- * @param inputMethodInfo The [InputMethodInfo] whose subtypes list will be returned. If `null`,
- * returns enabled subtypes for the currently selected [InputMethodInfo].
+ * @param user The user to query.
+ * @param imeId The ID of the input method whose subtypes list will be returned.
* @param allowsImplicitlyEnabledSubtypes Whether to allow to return the implicitly enabled
* subtypes. If an input method info doesn't have enabled subtypes, the framework will
* implicitly enable subtypes according to the current system language.
- * @see InputMethodManager.getEnabledInputMethodSubtypeList
+ * @see InputMethodManager.getEnabledInputMethodSubtypeListAsUser
*/
private suspend fun enabledInputMethodSubtypes(
- inputMethodInfo: InputMethodInfo?,
+ user: UserHandle,
+ imeId: String,
allowsImplicitlyEnabledSubtypes: Boolean
): List<InputMethodModel.Subtype> {
return withContext(backgroundDispatcher) {
- inputMethodManager.getEnabledInputMethodSubtypeList(
- inputMethodInfo,
- allowsImplicitlyEnabledSubtypes
+ inputMethodManager.getEnabledInputMethodSubtypeListAsUser(
+ imeId,
+ allowsImplicitlyEnabledSubtypes,
+ user
)
}
.map {
diff --git a/packages/SystemUI/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractor.kt
index c54aa7f..d3ef178 100644
--- a/packages/SystemUI/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputmethod/domain/interactor/InputMethodInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.inputmethod.domain.interactor
+import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.inputmethod.data.repository.InputMethodRepository
import javax.inject.Inject
@@ -36,14 +37,16 @@
* Method adapted from `com.android.inputmethod.latin.Utils`.
*/
suspend fun hasMultipleEnabledImesOrSubtypes(userId: Int): Boolean {
+ val user = UserHandle.of(userId)
// Count IMEs that either have no subtypes, or have at least one non-auxiliary subtype.
val matchingInputMethods =
repository
- .enabledInputMethods(userId, fetchSubtypes = true)
+ .enabledInputMethods(user, fetchSubtypes = true)
.filter { ime -> ime.subtypes.isEmpty() || ime.subtypes.any { !it.isAuxiliary } }
.take(2) // Short-circuit if we find at least 2 matching IMEs.
- return matchingInputMethods.count() > 1 || repository.selectedInputMethodSubtypes().size > 1
+ return matchingInputMethods.count() > 1 ||
+ repository.selectedInputMethodSubtypes(user).size > 1
}
/** Shows the system's input method picker dialog. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/inputmethod/data/repository/FakeInputMethodRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/inputmethod/data/repository/FakeInputMethodRepository.kt
index 8e4461d..444baa0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/inputmethod/data/repository/FakeInputMethodRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/inputmethod/data/repository/FakeInputMethodRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.inputmethod.data.repository
+import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.inputmethod.data.model.InputMethodModel
import kotlinx.coroutines.flow.Flow
@@ -40,14 +41,15 @@
}
override suspend fun enabledInputMethods(
- userId: Int,
- fetchSubtypes: Boolean,
+ user: UserHandle,
+ fetchSubtypes: Boolean
): Flow<InputMethodModel> {
- return usersToEnabledInputMethods[userId] ?: flowOf()
+ return usersToEnabledInputMethods[user.identifier] ?: flowOf()
}
- override suspend fun selectedInputMethodSubtypes(): List<InputMethodModel.Subtype> =
- selectedInputMethodSubtypes
+ override suspend fun selectedInputMethodSubtypes(
+ user: UserHandle,
+ ): List<InputMethodModel.Subtype> = selectedInputMethodSubtypes
override suspend fun showInputMethodPicker(displayId: Int, showAuxiliarySubtypes: Boolean) {
inputMethodPickerShownDisplayId = displayId