Merge "Reset IME visible types only when losing control" into main
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 80578e4..ac67909 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1765,15 +1765,12 @@
public final class InputManager {
method public void addUniqueIdAssociation(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void clearAllModifierKeyRemappings();
- method @Nullable public String getCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier);
- method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptorsForInputDevice(@NonNull android.view.InputDevice);
+ method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptors();
method @NonNull public String getKeyboardLayoutTypeForLayoutDescriptor(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public java.util.Map<java.lang.Integer,java.lang.Integer> getModifierKeyRemapping();
method public int getMousePointerSpeed();
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
- method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
method public void removeUniqueIdAssociation(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 2816f77..1c37aa2 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -94,33 +94,8 @@
// Keyboard layouts configuration.
KeyboardLayout[] getKeyboardLayouts();
- KeyboardLayout[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
-
KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
- String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier);
-
- @EnforcePermission("SET_KEYBOARD_LAYOUT")
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
- + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
- void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor);
-
- String[] getEnabledKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
-
- @EnforcePermission("SET_KEYBOARD_LAYOUT")
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
- + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
- void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor);
-
- @EnforcePermission("SET_KEYBOARD_LAYOUT")
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
- + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
- void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor);
-
- // New Keyboard layout config APIs
KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
in InputDeviceIdentifier identifier, int userId, in InputMethodInfo imeInfo,
in InputMethodSubtype imeSubtype);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index a1242fb..f949158 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -473,22 +473,21 @@
}
/**
- * Returns the descriptors of all supported keyboard layouts appropriate for the specified
- * input device.
+ * Returns the descriptors of all supported keyboard layouts.
* <p>
* The input manager consults the built-in keyboard layouts as well as all keyboard layouts
* advertised by applications using a {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver.
* </p>
*
- * @param device The input device to query.
* @return The ids of all keyboard layouts which are supported by the specified input device.
*
* @hide
*/
@TestApi
@NonNull
- public List<String> getKeyboardLayoutDescriptorsForInputDevice(@NonNull InputDevice device) {
- KeyboardLayout[] layouts = getKeyboardLayoutsForInputDevice(device.getIdentifier());
+ @SuppressLint("UnflaggedApi")
+ public List<String> getKeyboardLayoutDescriptors() {
+ KeyboardLayout[] layouts = getKeyboardLayouts();
List<String> res = new ArrayList<>();
for (KeyboardLayout kl : layouts) {
res.add(kl.getDescriptor());
@@ -511,33 +510,18 @@
@TestApi
@NonNull
public String getKeyboardLayoutTypeForLayoutDescriptor(@NonNull String layoutDescriptor) {
- KeyboardLayout[] layouts = getKeyboardLayouts();
- for (KeyboardLayout kl : layouts) {
- if (layoutDescriptor.equals(kl.getDescriptor())) {
- return kl.getLayoutType();
- }
- }
- return "";
+ KeyboardLayout layout = getKeyboardLayout(layoutDescriptor);
+ return layout == null ? "" : layout.getLayoutType();
}
/**
- * Gets information about all supported keyboard layouts appropriate
- * for a specific input device.
- * <p>
- * The input manager consults the built-in keyboard layouts as well
- * as all keyboard layouts advertised by applications using a
- * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver.
- * </p>
- *
- * @return A list of all supported keyboard layouts for a specific
- * input device.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
@NonNull
public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
@NonNull InputDeviceIdentifier identifier) {
- return mGlobal.getKeyboardLayoutsForInputDevice(identifier);
+ return new KeyboardLayout[0];
}
/**
@@ -549,6 +533,7 @@
*
* @hide
*/
+ @Nullable
public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
if (keyboardLayoutDescriptor == null) {
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
@@ -562,121 +547,45 @@
}
/**
- * Gets the current keyboard layout descriptor for the specified input device.
- *
- * @param identifier Identifier for the input device
- * @return The keyboard layout descriptor, or null if no keyboard layout has been set.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
- @TestApi
@Nullable
public String getCurrentKeyboardLayoutForInputDevice(
@NonNull InputDeviceIdentifier identifier) {
- try {
- return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return null;
}
/**
- * Sets the current keyboard layout descriptor for the specified input device.
- * <p>
- * This method may have the side-effect of causing the input device in question to be
- * reconfigured.
- * </p>
- *
- * @param identifier The identifier for the input device.
- * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, must not be null.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
- @TestApi
- @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
public void setCurrentKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
- @NonNull String keyboardLayoutDescriptor) {
- mGlobal.setCurrentKeyboardLayoutForInputDevice(identifier,
- keyboardLayoutDescriptor);
- }
+ @NonNull String keyboardLayoutDescriptor) {}
/**
- * Gets all keyboard layout descriptors that are enabled for the specified input device.
- *
- * @param identifier The identifier for the input device.
- * @return The keyboard layout descriptors.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
- if (identifier == null) {
- throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
- }
-
- try {
- return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return new String[0];
}
/**
- * Adds the keyboard layout descriptor for the specified input device.
- * <p>
- * This method may have the side-effect of causing the input device in question to be
- * reconfigured.
- * </p>
- *
- * @param identifier The identifier for the input device.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to add.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
- @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
- if (identifier == null) {
- throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
- }
- if (keyboardLayoutDescriptor == null) {
- throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
- }
-
- try {
- mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
}
/**
- * Removes the keyboard layout descriptor for the specified input device.
- * <p>
- * This method may have the side-effect of causing the input device in question to be
- * reconfigured.
- * </p>
- *
- * @param identifier The identifier for the input device.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to remove.
- *
+ * TODO(b/330517633): Cleanup the unsupported API
* @hide
*/
- @TestApi
@RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
public void removeKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
@NonNull String keyboardLayoutDescriptor) {
- if (identifier == null) {
- throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
- }
- if (keyboardLayoutDescriptor == null) {
- throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
- }
-
- try {
- mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
}
/**
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 7c104a0..7b29666 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -1068,36 +1068,21 @@
}
/**
- * @see InputManager#getKeyboardLayoutsForInputDevice(InputDeviceIdentifier)
+ * TODO(b/330517633): Cleanup the unsupported API
*/
@NonNull
public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
@NonNull InputDeviceIdentifier identifier) {
- try {
- return mIm.getKeyboardLayoutsForInputDevice(identifier);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return new KeyboardLayout[0];
}
/**
- * @see InputManager#setCurrentKeyboardLayoutForInputDevice
- * (InputDeviceIdentifier, String)
+ * TODO(b/330517633): Cleanup the unsupported API
*/
- @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
public void setCurrentKeyboardLayoutForInputDevice(
@NonNull InputDeviceIdentifier identifier,
- @NonNull String keyboardLayoutDescriptor) {
- Objects.requireNonNull(identifier, "identifier must not be null");
- Objects.requireNonNull(keyboardLayoutDescriptor,
- "keyboardLayoutDescriptor must not be null");
- try {
- mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
- keyboardLayoutDescriptor);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
+ @NonNull String keyboardLayoutDescriptor) {}
+
/**
* @see InputDevice#getSensorManager()
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index efe31ff..616004b 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -36,3 +36,10 @@
description: "Enables a limit on the number of Tasks shown in Desktop Mode"
bug: "332502912"
}
+
+flag {
+ name: "enable_windowing_edge_drag_resize"
+ namespace: "lse_desktop_experience"
+ description: "Enables edge drag resizing for all input sources"
+ bug: "323383067"
+}
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index f9347ee..e8b4104 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -424,12 +424,14 @@
key 582 VOICE_ASSIST
# Linux KEY_ASSISTANT
key 583 ASSIST
+key 585 EMOJI_PICKER
key 656 MACRO_1
key 657 MACRO_2
key 658 MACRO_3
key 659 MACRO_4
# Keys defined by HID usages
+key usage 0x0c0065 SCREENSHOT FALLBACK_USAGE_MAPPING
key usage 0x0c0067 WINDOW FALLBACK_USAGE_MAPPING
key usage 0x0c006F BRIGHTNESS_UP FALLBACK_USAGE_MAPPING
key usage 0x0c0070 BRIGHTNESS_DOWN FALLBACK_USAGE_MAPPING
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 207ccbe..871e9ab 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -80,4 +80,7 @@
boolean hasCustomMediaSessionPolicyProvider(String componentName);
int getSessionPolicies(in MediaSession.Token token);
void setSessionPolicies(in MediaSession.Token token, int policies);
+
+ // For testing of temporarily engaged sessions.
+ void expireTempEngagedSessions();
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
index 8b546b4..791893b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
@@ -23,7 +23,6 @@
@Composable
fun TwoTargetSwitchPreference(
model: SwitchPreferenceModel,
- icon: @Composable (() -> Unit)? = null,
primaryEnabled: () -> Boolean = { true },
primaryOnClick: (() -> Unit)?,
) {
@@ -33,7 +32,7 @@
summary = model.summary,
primaryEnabled = primaryEnabled,
primaryOnClick = primaryOnClick,
- icon = icon,
+ icon = model.icon,
) {
SettingsSwitch(
checked = model.checked(),
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItem.kt
index 5c2d770..1f7122e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItem.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItem.kt
@@ -33,11 +33,13 @@
model = object : SwitchPreferenceModel {
override val title = label
override val summary = this@AppListTwoTargetSwitchItem.summary
+ override val icon = @Composable {
+ AppIcon(record.app, SettingsDimension.appIconItemSize)
+ }
override val checked = checked
override val changeable = changeable
override val onCheckedChange = onCheckedChange
},
- icon = { AppIcon(record.app, SettingsDimension.appIconItemSize) },
primaryOnClick = onClick,
)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
index 87cd2b8..c9934ad 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
@@ -52,6 +52,8 @@
checked = model.checked,
)
+ override val icon = model.icon
+
override val checked = when (restrictedMode) {
null -> ({ null })
is NoRestricted -> model.checked
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreference.kt
index e100773..1bed733 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreference.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreference.kt
@@ -29,14 +29,12 @@
@Composable
fun RestrictedTwoTargetSwitchPreference(
model: SwitchPreferenceModel,
- icon: @Composable (() -> Unit)? = null,
restrictions: Restrictions,
primaryEnabled: () -> Boolean = { true },
primaryOnClick: (() -> Unit)?,
) {
RestrictedTwoTargetSwitchPreference(
model = model,
- icon = icon,
primaryEnabled = primaryEnabled,
primaryOnClick = primaryOnClick,
restrictions = restrictions,
@@ -48,21 +46,19 @@
@Composable
internal fun RestrictedTwoTargetSwitchPreference(
model: SwitchPreferenceModel,
- icon: @Composable (() -> Unit)? = null,
primaryEnabled: () -> Boolean = { true },
primaryOnClick: (() -> Unit)?,
restrictions: Restrictions,
restrictionsProviderFactory: RestrictionsProviderFactory,
) {
if (restrictions.isEmpty()) {
- TwoTargetSwitchPreference(model, icon, primaryEnabled, primaryOnClick)
+ TwoTargetSwitchPreference(model, primaryEnabled, primaryOnClick)
return
}
val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions).value
RestrictedSwitchWrapper(model, restrictedMode) { restrictedModel ->
TwoTargetSwitchPreference(
model = restrictedModel,
- icon = icon,
primaryEnabled = restrictedMode.restrictEnabled(primaryEnabled),
primaryOnClick = restrictedMode.restrictOnClick(primaryOnClick),
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/BottomComponentButtonSurface.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/BottomComponentButtonSurface.kt
new file mode 100644
index 0000000..167eb65
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/BottomComponentButtonSurface.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.button.ui.composable
+
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+/**
+ * Container to create a rim around the button. Both `Expandable` and `OutlinedIconToggleButton`
+ * have antialiasing problem when used with [androidx.compose.foundation.BorderStroke] and some
+ * contrast container color.
+ */
+// TODO(b/331584069): Remove this once antialiasing bug is fixed
+@Composable
+fun BottomComponentButtonSurface(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
+ Surface(
+ modifier = modifier.height(64.dp),
+ shape = RoundedCornerShape(28.dp),
+ color = MaterialTheme.colorScheme.surface,
+ content = content,
+ )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
index 8f187cc..fc511e1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
@@ -16,14 +16,12 @@
package com.android.systemui.volume.panel.component.button.ui.composable
-import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
@@ -64,20 +62,21 @@
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
- Expandable(
- modifier =
- Modifier.height(64.dp).fillMaxWidth().semantics {
- role = Role.Button
- contentDescription = label
- },
- color = MaterialTheme.colorScheme.primaryContainer,
- shape = RoundedCornerShape(28.dp),
- contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
- borderStroke = BorderStroke(8.dp, MaterialTheme.colorScheme.surface),
- onClick = onClick,
- ) {
- Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
- Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
+ BottomComponentButtonSurface {
+ Expandable(
+ modifier =
+ Modifier.fillMaxSize().padding(8.dp).semantics {
+ role = Role.Button
+ contentDescription = label
+ },
+ color = MaterialTheme.colorScheme.primaryContainer,
+ shape = RoundedCornerShape(28.dp),
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ onClick = onClick,
+ ) {
+ Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
+ }
}
}
Text(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 51ec63b..780e3f2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -16,23 +16,23 @@
package com.android.systemui.volume.panel.component.button.ui.composable
-import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.IconButtonDefaults
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedIconToggleButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
@@ -62,26 +62,33 @@
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
- OutlinedIconToggleButton(
- modifier =
- Modifier.height(64.dp).fillMaxWidth().semantics {
- role = Role.Switch
- contentDescription = label
- },
- checked = viewModel.isChecked,
- onCheckedChange = onCheckedChange,
- shape = RoundedCornerShape(28.dp),
- colors =
- IconButtonDefaults.outlinedIconToggleButtonColors(
- containerColor = MaterialTheme.colorScheme.surface,
- contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
- checkedContainerColor = MaterialTheme.colorScheme.primaryContainer,
- checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
- ),
- border = BorderStroke(8.dp, MaterialTheme.colorScheme.surface),
- ) {
- Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
+ BottomComponentButtonSurface {
+ val colors =
+ if (viewModel.isChecked) {
+ ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.primaryContainer,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ )
+ } else {
+ ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+ Button(
+ modifier =
+ Modifier.fillMaxSize().padding(8.dp).semantics {
+ role = Role.Switch
+ contentDescription = label
+ },
+ onClick = { onCheckedChange(!viewModel.isChecked) },
+ shape = RoundedCornerShape(28.dp),
+ colors = colors
+ ) {
+ Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
+ }
}
+
Text(
modifier = Modifier.clearAndSetSemantics {}.basicMarquee(),
text = label,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
index e2d7d11..c743314 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
@@ -46,6 +46,12 @@
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.selected
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
@@ -112,10 +118,16 @@
horizontalArrangement = Arrangement.spacedBy(spacing)
) {
for (itemIndex in items.indices) {
+ val item = items[itemIndex]
Row(
modifier =
Modifier.height(48.dp)
.weight(1f)
+ .semantics {
+ item.contentDescription?.let { contentDescription = it }
+ role = Role.Switch
+ selected = itemIndex == scope.selectedIndex
+ }
.clickable(
interactionSource = null,
indication = null,
@@ -124,7 +136,6 @@
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
- val item = items[itemIndex]
if (item.icon !== Empty) {
with(items[itemIndex]) { icon() }
}
@@ -138,7 +149,8 @@
start = indicatorBackgroundPadding,
top = labelIndicatorBackgroundSpacing,
end = indicatorBackgroundPadding
- ),
+ )
+ .clearAndSetSemantics {},
horizontalArrangement = Arrangement.spacedBy(spacing),
) {
for (itemIndex in items.indices) {
@@ -296,6 +308,7 @@
onItemSelected: () -> Unit,
icon: @Composable RowScope.() -> Unit = Empty,
label: @Composable RowScope.() -> Unit = Empty,
+ contentDescription: String? = null,
)
}
@@ -317,6 +330,7 @@
onItemSelected: () -> Unit,
icon: @Composable RowScope.() -> Unit,
label: @Composable RowScope.() -> Unit,
+ contentDescription: String?,
) {
require(!isSelected || !hasSelectedItem) { "Only one item should be selected at a time" }
if (isSelected) {
@@ -327,6 +341,7 @@
onItemSelected = onItemSelected,
icon = icon,
label = label,
+ contentDescription = contentDescription,
)
)
}
@@ -340,6 +355,7 @@
val onItemSelected: () -> Unit,
val icon: @Composable RowScope.() -> Unit,
val label: @Composable RowScope.() -> Unit,
+ val contentDescription: String?,
)
private const val UNSET_OFFSET = -1
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
index 6673afd..eed54da 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
@@ -74,9 +74,11 @@
}
VolumePanelRadioButtonBar {
for (buttonViewModel in enabledModelStates) {
+ val label = buttonViewModel.button.label.toString()
item(
isSelected = buttonViewModel.button.isChecked,
onItemSelected = { viewModel.setEnabled(buttonViewModel.model) },
+ contentDescription = label,
icon = {
Icon(
icon = buttonViewModel.button.icon,
@@ -86,7 +88,7 @@
label = {
Text(
modifier = Modifier.basicMarquee(),
- text = buttonViewModel.button.label.toString(),
+ text = label,
style = MaterialTheme.typography.labelMedium,
color = buttonViewModel.labelColor.toColor(),
textAlign = TextAlign.Center,
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 77119d5..f32c11d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1197,54 +1197,11 @@
}
@Override // Binder call
- public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
- final InputDeviceIdentifier identifier) {
- return mKeyboardLayoutManager.getKeyboardLayoutsForInputDevice(identifier);
- }
-
- @Override // Binder call
public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
return mKeyboardLayoutManager.getKeyboardLayout(keyboardLayoutDescriptor);
}
@Override // Binder call
- public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
- return mKeyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(identifier);
- }
-
- @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
- @Override // Binder call
- public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- super.setCurrentKeyboardLayoutForInputDevice_enforcePermission();
- mKeyboardLayoutManager.setCurrentKeyboardLayoutForInputDevice(identifier,
- keyboardLayoutDescriptor);
- }
-
- @Override // Binder call
- public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
- return mKeyboardLayoutManager.getEnabledKeyboardLayoutsForInputDevice(identifier);
- }
-
- @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
- @Override // Binder call
- public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- super.addKeyboardLayoutForInputDevice_enforcePermission();
- mKeyboardLayoutManager.addKeyboardLayoutForInputDevice(identifier,
- keyboardLayoutDescriptor);
- }
-
- @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
- @Override // Binder call
- public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- super.removeKeyboardLayoutForInputDevice_enforcePermission();
- mKeyboardLayoutManager.removeKeyboardLayoutForInputDevice(identifier,
- keyboardLayoutDescriptor);
- }
-
- @Override // Binder call
public KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
InputDeviceIdentifier identifier, @UserIdInt int userId,
@NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype) {
@@ -1270,11 +1227,6 @@
imeInfo, imeSubtype);
}
-
- public void switchKeyboardLayout(int deviceId, int direction) {
- mKeyboardLayoutManager.switchKeyboardLayout(deviceId, direction);
- }
-
public void setFocusedApplication(int displayId, InputApplicationHandle application) {
mNative.setFocusedApplication(displayId, application);
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 6610081..9ba647f 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -60,7 +60,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -69,7 +68,6 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -96,7 +94,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.stream.Stream;
/**
* A component of {@link InputManagerService} responsible for managing Physical Keyboard layouts.
@@ -112,9 +109,8 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
- private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
- private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
- private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
+ private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 2;
+ private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 3;
private final Context mContext;
private final NativeInputManagerService mNative;
@@ -126,13 +122,14 @@
// Connected keyboards with associated keyboard layouts (either auto-detected or manually
// selected layout).
private final SparseArray<KeyboardConfiguration> mConfiguredKeyboards = new SparseArray<>();
- private Toast mSwitchedKeyboardLayoutToast;
// This cache stores "best-matched" layouts so that we don't need to run the matching
// algorithm repeatedly.
@GuardedBy("mKeyboardLayoutCache")
private final Map<String, KeyboardLayoutSelectionResult> mKeyboardLayoutCache =
new ArrayMap<>();
+
+ private HashSet<String> mAvailableLayouts = new HashSet<>();
private final Object mImeInfoLock = new Object();
@Nullable
@GuardedBy("mImeInfoLock")
@@ -206,68 +203,51 @@
}
boolean needToShowNotification = false;
- if (!useNewSettingsUi()) {
- synchronized (mDataStore) {
- String layout = getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
- if (layout == null) {
- layout = getDefaultKeyboardLayout(inputDevice);
- if (layout != null) {
- setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
- }
- }
- if (layout == null) {
- // In old settings show notification always until user manually selects a
- // layout in the settings.
+ Set<String> selectedLayouts = new HashSet<>();
+ List<ImeInfo> imeInfoList = getImeInfoListForLayoutMapping();
+ List<KeyboardLayoutSelectionResult> resultList = new ArrayList<>();
+ boolean hasMissingLayout = false;
+ for (ImeInfo imeInfo : imeInfoList) {
+ // Check if the layout has been previously configured
+ KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
+ keyboardIdentifier, imeInfo);
+ if (result.getLayoutDescriptor() != null) {
+ selectedLayouts.add(result.getLayoutDescriptor());
+ } else {
+ hasMissingLayout = true;
+ }
+ resultList.add(result);
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Layouts selected for input device: " + keyboardIdentifier
+ + " -> selectedLayouts: " + selectedLayouts);
+ }
+
+ // If even one layout not configured properly, we need to ask user to configure
+ // the keyboard properly from the Settings.
+ if (hasMissingLayout) {
+ selectedLayouts.clear();
+ }
+
+ config.setConfiguredLayouts(selectedLayouts);
+
+ synchronized (mDataStore) {
+ try {
+ final String key = keyboardIdentifier.toString();
+ if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
+ // Need to show the notification only if layout selection changed
+ // from the previous configuration
needToShowNotification = true;
}
- }
- } else {
- Set<String> selectedLayouts = new HashSet<>();
- List<ImeInfo> imeInfoList = getImeInfoListForLayoutMapping();
- List<KeyboardLayoutSelectionResult> resultList = new ArrayList<>();
- boolean hasMissingLayout = false;
- for (ImeInfo imeInfo : imeInfoList) {
- // Check if the layout has been previously configured
- KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
- keyboardIdentifier, imeInfo);
- boolean noLayoutFound = result.getLayoutDescriptor() == null;
- if (!noLayoutFound) {
- selectedLayouts.add(result.getLayoutDescriptor());
+
+ if (shouldLogConfiguration) {
+ logKeyboardConfigurationEvent(inputDevice, imeInfoList, resultList,
+ !mDataStore.hasInputDeviceEntry(key));
}
- resultList.add(result);
- hasMissingLayout |= noLayoutFound;
- }
-
- if (DEBUG) {
- Slog.d(TAG,
- "Layouts selected for input device: " + keyboardIdentifier
- + " -> selectedLayouts: " + selectedLayouts);
- }
-
- // If even one layout not configured properly, we need to ask user to configure
- // the keyboard properly from the Settings.
- if (hasMissingLayout) {
- selectedLayouts.clear();
- }
-
- config.setConfiguredLayouts(selectedLayouts);
-
- synchronized (mDataStore) {
- try {
- final String key = keyboardIdentifier.toString();
- if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
- // Need to show the notification only if layout selection changed
- // from the previous configuration
- needToShowNotification = true;
- }
-
- if (shouldLogConfiguration) {
- logKeyboardConfigurationEvent(inputDevice, imeInfoList, resultList,
- !mDataStore.hasInputDeviceEntry(key));
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
+ } finally {
+ mDataStore.saveIfNeeded();
}
}
if (needToShowNotification) {
@@ -275,63 +255,6 @@
}
}
- private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
- final Locale systemLocale = mContext.getResources().getConfiguration().locale;
- // If our locale doesn't have a language for some reason, then we don't really have a
- // reasonable default.
- if (TextUtils.isEmpty(systemLocale.getLanguage())) {
- return null;
- }
- final List<KeyboardLayout> layouts = new ArrayList<>();
- visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> {
- // Only select a default when we know the layout is appropriate. For now, this
- // means it's a custom layout for a specific keyboard.
- if (layout.getVendorId() != inputDevice.getVendorId()
- || layout.getProductId() != inputDevice.getProductId()) {
- return;
- }
- final LocaleList locales = layout.getLocales();
- for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
- final Locale locale = locales.get(localeIndex);
- if (locale != null && isCompatibleLocale(systemLocale, locale)) {
- layouts.add(layout);
- break;
- }
- }
- });
-
- if (layouts.isEmpty()) {
- return null;
- }
-
- // First sort so that ones with higher priority are listed at the top
- Collections.sort(layouts);
- // Next we want to try to find an exact match of language, country and variant.
- for (KeyboardLayout layout : layouts) {
- final LocaleList locales = layout.getLocales();
- for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
- final Locale locale = locales.get(localeIndex);
- if (locale != null && locale.getCountry().equals(systemLocale.getCountry())
- && locale.getVariant().equals(systemLocale.getVariant())) {
- return layout.getDescriptor();
- }
- }
- }
- // Then try an exact match of language and country
- for (KeyboardLayout layout : layouts) {
- final LocaleList locales = layout.getLocales();
- for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
- final Locale locale = locales.get(localeIndex);
- if (locale != null && locale.getCountry().equals(systemLocale.getCountry())) {
- return layout.getDescriptor();
- }
- }
- }
-
- // Give up and just use the highest priority layout with matching language
- return layouts.get(0).getDescriptor();
- }
-
private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
// Different languages are never compatible
if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
@@ -343,11 +266,19 @@
|| systemLocale.getCountry().equals(keyboardLocale.getCountry());
}
+ @MainThread
private void updateKeyboardLayouts() {
// Scan all input devices state for keyboard layouts that have been uninstalled.
- final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
+ final HashSet<String> availableKeyboardLayouts = new HashSet<>();
visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) ->
availableKeyboardLayouts.add(layout.getDescriptor()));
+
+ // If available layouts don't change, there is no need to reload layouts.
+ if (mAvailableLayouts.equals(availableKeyboardLayouts)) {
+ return;
+ }
+ mAvailableLayouts = availableKeyboardLayouts;
+
synchronized (mDataStore) {
try {
mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
@@ -374,53 +305,6 @@
}
@AnyThread
- public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
- final InputDeviceIdentifier identifier) {
- if (useNewSettingsUi()) {
- // Provide all supported keyboard layouts since Ime info is not provided
- return getKeyboardLayouts();
- }
- final String[] enabledLayoutDescriptors =
- getEnabledKeyboardLayoutsForInputDevice(identifier);
- final ArrayList<KeyboardLayout> enabledLayouts =
- new ArrayList<>(enabledLayoutDescriptors.length);
- final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
- visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
- boolean mHasSeenDeviceSpecificLayout;
-
- @Override
- public void visitKeyboardLayout(Resources resources,
- int keyboardLayoutResId, KeyboardLayout layout) {
- // First check if it's enabled. If the keyboard layout is enabled then we always
- // want to return it as a possible layout for the device.
- for (String s : enabledLayoutDescriptors) {
- if (s != null && s.equals(layout.getDescriptor())) {
- enabledLayouts.add(layout);
- return;
- }
- }
- // Next find any potential layouts that aren't yet enabled for the device. For
- // devices that have special layouts we assume there's a reason that the generic
- // layouts don't work for them so we don't want to return them since it's likely
- // to result in a poor user experience.
- if (layout.getVendorId() == identifier.getVendorId()
- && layout.getProductId() == identifier.getProductId()) {
- if (!mHasSeenDeviceSpecificLayout) {
- mHasSeenDeviceSpecificLayout = true;
- potentialLayouts.clear();
- }
- potentialLayouts.add(layout);
- } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
- && !mHasSeenDeviceSpecificLayout) {
- potentialLayouts.add(layout);
- }
- }
- });
- return Stream.concat(enabledLayouts.stream(), potentialLayouts.stream()).toArray(
- KeyboardLayout[]::new);
- }
-
- @AnyThread
@Nullable
public KeyboardLayout getKeyboardLayout(@NonNull String keyboardLayoutDescriptor) {
Objects.requireNonNull(keyboardLayoutDescriptor,
@@ -580,195 +464,16 @@
return LocaleList.forLanguageTags(languageTags.replace('|', ','));
}
- @AnyThread
- @Nullable
- public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "getCurrentKeyboardLayoutForInputDevice API not supported");
- return null;
- }
- String key = new KeyboardIdentifier(identifier).toString();
- synchronized (mDataStore) {
- String layout;
- // try loading it using the layout descriptor if we have it
- layout = mDataStore.getCurrentKeyboardLayout(key);
- if (layout == null && !key.equals(identifier.getDescriptor())) {
- // if it doesn't exist fall back to the device descriptor
- layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
- }
- if (DEBUG) {
- Slog.d(TAG, "getCurrentKeyboardLayoutForInputDevice() "
- + identifier.toString() + ": " + layout);
- }
- return layout;
- }
- }
-
- @AnyThread
- public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "setCurrentKeyboardLayoutForInputDevice API not supported");
- return;
- }
-
- Objects.requireNonNull(keyboardLayoutDescriptor,
- "keyboardLayoutDescriptor must not be null");
- String key = new KeyboardIdentifier(identifier).toString();
- synchronized (mDataStore) {
- try {
- if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
- if (DEBUG) {
- Slog.d(TAG, "setCurrentKeyboardLayoutForInputDevice() " + identifier
- + " key: " + key
- + " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
- }
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
- }
-
- @AnyThread
- public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "getEnabledKeyboardLayoutsForInputDevice API not supported");
- return new String[0];
- }
- String key = new KeyboardIdentifier(identifier).toString();
- synchronized (mDataStore) {
- String[] layouts = mDataStore.getKeyboardLayouts(key);
- if ((layouts == null || layouts.length == 0)
- && !key.equals(identifier.getDescriptor())) {
- layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
- }
- return layouts;
- }
- }
-
- @AnyThread
- public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "addKeyboardLayoutForInputDevice API not supported");
- return;
- }
- Objects.requireNonNull(keyboardLayoutDescriptor,
- "keyboardLayoutDescriptor must not be null");
-
- String key = new KeyboardIdentifier(identifier).toString();
- synchronized (mDataStore) {
- try {
- String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
- if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
- oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
- }
- if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
- && !Objects.equals(oldLayout,
- mDataStore.getCurrentKeyboardLayout(key))) {
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
- }
-
- @AnyThread
- public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- String keyboardLayoutDescriptor) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "removeKeyboardLayoutForInputDevice API not supported");
- return;
- }
- Objects.requireNonNull(keyboardLayoutDescriptor,
- "keyboardLayoutDescriptor must not be null");
-
- String key = new KeyboardIdentifier(identifier).toString();
- synchronized (mDataStore) {
- try {
- String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
- if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
- oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
- }
- boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
- if (!key.equals(identifier.getDescriptor())) {
- // We need to remove from both places to ensure it is gone
- removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
- keyboardLayoutDescriptor);
- }
- if (removed && !Objects.equals(oldLayout,
- mDataStore.getCurrentKeyboardLayout(key))) {
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
- }
-
- @AnyThread
- public void switchKeyboardLayout(int deviceId, int direction) {
- if (useNewSettingsUi()) {
- Slog.e(TAG, "switchKeyboardLayout API not supported");
- return;
- }
- mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
- }
-
- @MainThread
- private void handleSwitchKeyboardLayout(int deviceId, int direction) {
- final InputDevice device = getInputDevice(deviceId);
- if (device != null) {
- final boolean changed;
- final String keyboardLayoutDescriptor;
-
- String key = new KeyboardIdentifier(device.getIdentifier()).toString();
- synchronized (mDataStore) {
- try {
- changed = mDataStore.switchKeyboardLayout(key, direction);
- keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
- key);
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
-
- if (changed) {
- if (mSwitchedKeyboardLayoutToast != null) {
- mSwitchedKeyboardLayoutToast.cancel();
- mSwitchedKeyboardLayoutToast = null;
- }
- if (keyboardLayoutDescriptor != null) {
- KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
- if (keyboardLayout != null) {
- mSwitchedKeyboardLayoutToast = Toast.makeText(
- mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
- mSwitchedKeyboardLayoutToast.show();
- }
- }
-
- reloadKeyboardLayouts();
- }
- }
- }
-
@Nullable
@AnyThread
public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag,
String layoutType) {
String keyboardLayoutDescriptor;
- if (useNewSettingsUi()) {
- synchronized (mImeInfoLock) {
- KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
- new KeyboardIdentifier(identifier, languageTag, layoutType),
- mCurrentImeInfo);
- keyboardLayoutDescriptor = result.getLayoutDescriptor();
- }
- } else {
- keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
+ synchronized (mImeInfoLock) {
+ KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
+ new KeyboardIdentifier(identifier, languageTag, layoutType),
+ mCurrentImeInfo);
+ keyboardLayoutDescriptor = result.getLayoutDescriptor();
}
if (keyboardLayoutDescriptor == null) {
return null;
@@ -797,10 +502,6 @@
public KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
InputDeviceIdentifier identifier, @UserIdInt int userId,
@NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype) {
- if (!useNewSettingsUi()) {
- Slog.e(TAG, "getKeyboardLayoutForInputDevice() API not supported");
- return FAILED;
- }
InputDevice inputDevice = getInputDevice(identifier);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return FAILED;
@@ -820,10 +521,6 @@
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype,
String keyboardLayoutDescriptor) {
- if (!useNewSettingsUi()) {
- Slog.e(TAG, "setKeyboardLayoutForInputDevice() API not supported");
- return;
- }
Objects.requireNonNull(keyboardLayoutDescriptor,
"keyboardLayoutDescriptor must not be null");
InputDevice inputDevice = getInputDevice(identifier);
@@ -854,10 +551,6 @@
public KeyboardLayout[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
@UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
@Nullable InputMethodSubtype imeSubtype) {
- if (!useNewSettingsUi()) {
- Slog.e(TAG, "getKeyboardLayoutListForInputDevice() API not supported");
- return new KeyboardLayout[0];
- }
InputDevice inputDevice = getInputDevice(identifier);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return new KeyboardLayout[0];
@@ -923,10 +616,6 @@
public void onInputMethodSubtypeChanged(@UserIdInt int userId,
@Nullable InputMethodSubtypeHandle subtypeHandle,
@Nullable InputMethodSubtype subtype) {
- if (!useNewSettingsUi()) {
- Slog.e(TAG, "onInputMethodSubtypeChanged() API not supported");
- return;
- }
if (subtypeHandle == null) {
if (DEBUG) {
Slog.d(TAG, "No InputMethod is running, ignoring change");
@@ -1289,9 +978,6 @@
onInputDeviceAdded(deviceId);
}
return true;
- case MSG_SWITCH_KEYBOARD_LAYOUT:
- handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
- return true;
case MSG_RELOAD_KEYBOARD_LAYOUTS:
reloadKeyboardLayouts();
return true;
@@ -1303,10 +989,6 @@
}
}
- private boolean useNewSettingsUi() {
- return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
- }
-
@Nullable
private InputDevice getInputDevice(int deviceId) {
InputManager inputManager = mContext.getSystemService(InputManager.class);
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index 31083fd..7859253 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -27,7 +27,6 @@
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -42,7 +41,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -74,7 +72,7 @@
new HashMap<String, InputDeviceState>();
// The interface for methods which should be replaced by the test harness.
- private Injector mInjector;
+ private final Injector mInjector;
// True if the data has been loaded.
private boolean mLoaded;
@@ -83,7 +81,7 @@
private boolean mDirty;
// Storing key remapping
- private Map<Integer, Integer> mKeyRemapping = new HashMap<>();
+ private final Map<Integer, Integer> mKeyRemapping = new HashMap<>();
public PersistentDataStore() {
this(new Injector());
@@ -130,22 +128,6 @@
}
@Nullable
- public String getCurrentKeyboardLayout(String inputDeviceDescriptor) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
- return state != null ? state.getCurrentKeyboardLayout() : null;
- }
-
- public boolean setCurrentKeyboardLayout(String inputDeviceDescriptor,
- String keyboardLayoutDescriptor) {
- InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
- if (state.setCurrentKeyboardLayout(keyboardLayoutDescriptor)) {
- setDirty();
- return true;
- }
- return false;
- }
-
- @Nullable
public String getKeyboardLayout(String inputDeviceDescriptor, String key) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
return state != null ? state.getKeyboardLayout(key) : null;
@@ -171,43 +153,6 @@
return false;
}
- public String[] getKeyboardLayouts(String inputDeviceDescriptor) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
- if (state == null) {
- return (String[])ArrayUtils.emptyArray(String.class);
- }
- return state.getKeyboardLayouts();
- }
-
- public boolean addKeyboardLayout(String inputDeviceDescriptor,
- String keyboardLayoutDescriptor) {
- InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
- if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
- setDirty();
- return true;
- }
- return false;
- }
-
- public boolean removeKeyboardLayout(String inputDeviceDescriptor,
- String keyboardLayoutDescriptor) {
- InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
- if (state.removeKeyboardLayout(keyboardLayoutDescriptor)) {
- setDirty();
- return true;
- }
- return false;
- }
-
- public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
- if (state != null && state.switchKeyboardLayout(direction)) {
- setDirty();
- return true;
- }
- return false;
- }
-
public boolean setKeyboardBacklightBrightness(String inputDeviceDescriptor, int lightId,
int brightness) {
InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
@@ -417,9 +362,6 @@
"x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
private final TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
- @Nullable
- private String mCurrentKeyboardLayout;
- private final ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
private final SparseIntArray mKeyboardBacklightBrightnessMap = new SparseIntArray();
private final Map<String, String> mKeyboardLayoutMap = new ArrayMap<>();
@@ -465,49 +407,6 @@
return true;
}
- @Nullable
- public String getCurrentKeyboardLayout() {
- return mCurrentKeyboardLayout;
- }
-
- public boolean setCurrentKeyboardLayout(String keyboardLayout) {
- if (Objects.equals(mCurrentKeyboardLayout, keyboardLayout)) {
- return false;
- }
- addKeyboardLayout(keyboardLayout);
- mCurrentKeyboardLayout = keyboardLayout;
- return true;
- }
-
- public String[] getKeyboardLayouts() {
- if (mKeyboardLayouts.isEmpty()) {
- return (String[])ArrayUtils.emptyArray(String.class);
- }
- return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
- }
-
- public boolean addKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
- if (index >= 0) {
- return false;
- }
- mKeyboardLayouts.add(-index - 1, keyboardLayout);
- if (mCurrentKeyboardLayout == null) {
- mCurrentKeyboardLayout = keyboardLayout;
- }
- return true;
- }
-
- public boolean removeKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
- if (index < 0) {
- return false;
- }
- mKeyboardLayouts.remove(index);
- updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
- return true;
- }
-
public boolean setKeyboardBacklightBrightness(int lightId, int brightness) {
if (mKeyboardBacklightBrightnessMap.get(lightId, INVALID_VALUE) == brightness) {
return false;
@@ -521,48 +420,8 @@
return brightness == INVALID_VALUE ? OptionalInt.empty() : OptionalInt.of(brightness);
}
- private void updateCurrentKeyboardLayoutIfRemoved(
- String removedKeyboardLayout, int removedIndex) {
- if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
- if (!mKeyboardLayouts.isEmpty()) {
- int index = removedIndex;
- if (index == mKeyboardLayouts.size()) {
- index = 0;
- }
- mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
- } else {
- mCurrentKeyboardLayout = null;
- }
- }
- }
-
- public boolean switchKeyboardLayout(int direction) {
- final int size = mKeyboardLayouts.size();
- if (size < 2) {
- return false;
- }
- int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
- assert index >= 0;
- if (direction > 0) {
- index = (index + 1) % size;
- } else {
- index = (index + size - 1) % size;
- }
- mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
- return true;
- }
-
public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
boolean changed = false;
- for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
- String keyboardLayout = mKeyboardLayouts.get(i);
- if (!availableKeyboardLayouts.contains(keyboardLayout)) {
- Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
- mKeyboardLayouts.remove(i);
- updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
- changed = true;
- }
- }
List<String> removedEntries = new ArrayList<>();
for (String key : mKeyboardLayoutMap.keySet()) {
if (!availableKeyboardLayouts.contains(mKeyboardLayoutMap.get(key))) {
@@ -582,27 +441,7 @@
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals("keyboard-layout")) {
- String descriptor = parser.getAttributeValue(null, "descriptor");
- if (descriptor == null) {
- throw new XmlPullParserException(
- "Missing descriptor attribute on keyboard-layout.");
- }
- String current = parser.getAttributeValue(null, "current");
- if (mKeyboardLayouts.contains(descriptor)) {
- throw new XmlPullParserException(
- "Found duplicate keyboard layout.");
- }
-
- mKeyboardLayouts.add(descriptor);
- if (current != null && current.equals("true")) {
- if (mCurrentKeyboardLayout != null) {
- throw new XmlPullParserException(
- "Found multiple current keyboard layouts.");
- }
- mCurrentKeyboardLayout = descriptor;
- }
- } else if (parser.getName().equals("keyed-keyboard-layout")) {
+ if (parser.getName().equals("keyed-keyboard-layout")) {
String key = parser.getAttributeValue(null, "key");
if (key == null) {
throw new XmlPullParserException(
@@ -676,27 +515,9 @@
}
}
}
-
- // Maintain invariant that layouts are sorted.
- Collections.sort(mKeyboardLayouts);
-
- // Maintain invariant that there is always a current keyboard layout unless
- // there are none installed.
- if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
- mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
- }
}
public void saveToXml(TypedXmlSerializer serializer) throws IOException {
- for (String layout : mKeyboardLayouts) {
- serializer.startTag(null, "keyboard-layout");
- serializer.attribute(null, "descriptor", layout);
- if (layout.equals(mCurrentKeyboardLayout)) {
- serializer.attributeBoolean(null, "current", true);
- }
- serializer.endTag(null, "keyboard-layout");
- }
-
for (String key : mKeyboardLayoutMap.keySet()) {
serializer.startTag(null, "keyed-keyboard-layout");
serializer.attribute(null, "key", key);
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 0cd7654..dfb2b0a 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -157,6 +157,11 @@
}
@Override
+ public void expireTempEngaged() {
+ // NA as MediaSession2 doesn't support UserEngagementStates for FGS.
+ }
+
+ @Override
public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
KeyEvent ke, int sequenceId, ResultReceiver cb) {
// TODO(jaewan): Implement.
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index eb4e6e4..8f164d3 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,6 +24,7 @@
import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -85,6 +86,8 @@
import com.android.server.uri.UriGrantsManagerInternal;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -225,6 +228,49 @@
private int mPolicies;
+ private @UserEngagementState int mUserEngagementState = USER_DISENGAGED;
+
+ @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface UserEngagementState {}
+
+ /**
+ * Indicates that the session is active and in one of the user engaged states.
+ *
+ * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ */
+ private static final int USER_PERMANENTLY_ENGAGED = 0;
+
+ /**
+ * Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state.
+ *
+ * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ */
+ private static final int USER_TEMPORARY_ENGAGED = 1;
+
+ /**
+ * Indicates that the session is either not active or in one of the user disengaged states
+ *
+ * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ */
+ private static final int USER_DISENGAGED = 2;
+
+ /**
+ * Indicates the duration of the temporary engaged states.
+ *
+ * <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily
+ * engaged, meaning the corresponding session is only considered in an engaged state for the
+ * duration of this timeout, and only if coming from an engaged state.
+ *
+ * <p>For example, if a session is transitioning from a user-engaged state {@link
+ * PlaybackState#STATE_PLAYING} to a temporary user-engaged state {@link
+ * PlaybackState#STATE_PAUSED}, then the session will be considered in a user-engaged state for
+ * the duration of this timeout, starting at the transition instant. However, a temporary
+ * user-engaged state is not considered user-engaged when transitioning from a non-user engaged
+ * state {@link PlaybackState#STATE_STOPPED}.
+ */
+ private static final int TEMP_USER_ENGAGED_TIMEOUT = 600000;
+
public MediaSessionRecord(
int ownerPid,
int ownerUid,
@@ -548,6 +594,7 @@
mSessionCb.mCb.asBinder().unlinkToDeath(this, 0);
mDestroyed = true;
mPlaybackState = null;
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
mHandler.post(MessageHandler.MSG_DESTROYED);
}
}
@@ -559,6 +606,12 @@
}
}
+ @Override
+ public void expireTempEngaged() {
+ mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout);
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ }
+
/**
* Sends media button.
*
@@ -849,7 +902,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -876,7 +929,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -911,7 +964,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -938,7 +991,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -965,7 +1018,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -992,7 +1045,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -1017,7 +1070,7 @@
}
}
if (deadCallbackHolders != null) {
- mControllerCallbackHolders.removeAll(deadCallbackHolders);
+ removeControllerHoldersSafely(deadCallbackHolders);
}
}
@@ -1042,7 +1095,7 @@
}
}
// After notifying clear all listeners
- mControllerCallbackHolders.clear();
+ removeControllerHoldersSafely(null);
}
private PlaybackState getStateWithUpdatedPosition() {
@@ -1090,6 +1143,17 @@
return -1;
}
+ private void removeControllerHoldersSafely(
+ Collection<ISessionControllerCallbackHolder> holders) {
+ synchronized (mLock) {
+ if (holders == null) {
+ mControllerCallbackHolders.clear();
+ } else {
+ mControllerCallbackHolders.removeAll(holders);
+ }
+ }
+ }
+
private PlaybackInfo getVolumeAttributes() {
int volumeType;
AudioAttributes attributes;
@@ -1118,6 +1182,11 @@
}
};
+ private final Runnable mHandleTempEngagedSessionTimeout =
+ () -> {
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ };
+
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
private static boolean componentNameExists(
@NonNull ComponentName componentName, @NonNull Context context, int userId) {
@@ -1134,6 +1203,40 @@
return !resolveInfos.isEmpty();
}
+ private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) {
+ int oldUserEngagedState = mUserEngagementState;
+ int newUserEngagedState;
+ if (!isActive() || mPlaybackState == null) {
+ newUserEngagedState = USER_DISENGAGED;
+ } else if (isActive() && mPlaybackState.isActive()) {
+ newUserEngagedState = USER_PERMANENTLY_ENGAGED;
+ } else if (mPlaybackState.getState() == PlaybackState.STATE_PAUSED) {
+ newUserEngagedState =
+ oldUserEngagedState == USER_PERMANENTLY_ENGAGED || !isTimeoutExpired
+ ? USER_TEMPORARY_ENGAGED
+ : USER_DISENGAGED;
+ } else {
+ newUserEngagedState = USER_DISENGAGED;
+ }
+ if (oldUserEngagedState == newUserEngagedState) {
+ return;
+ }
+
+ if (newUserEngagedState == USER_TEMPORARY_ENGAGED) {
+ mHandler.postDelayed(mHandleTempEngagedSessionTimeout, TEMP_USER_ENGAGED_TIMEOUT);
+ } else if (oldUserEngagedState == USER_TEMPORARY_ENGAGED) {
+ mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout);
+ }
+
+ boolean wasUserEngaged = oldUserEngagedState != USER_DISENGAGED;
+ boolean isNowUserEngaged = newUserEngagedState != USER_DISENGAGED;
+ mUserEngagementState = newUserEngagedState;
+ if (wasUserEngaged != isNowUserEngaged) {
+ mService.onSessionUserEngagementStateChange(
+ /* mediaSessionRecord= */ this, /* isUserEngaged= */ isNowUserEngaged);
+ }
+ }
+
private final class SessionStub extends ISession.Stub {
@Override
public void destroySession() throws RemoteException {
@@ -1171,8 +1274,10 @@
.logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK,
callingUid, callingPid);
}
-
- mIsActive = active;
+ synchronized (mLock) {
+ mIsActive = active;
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false);
+ }
long token = Binder.clearCallingIdentity();
try {
mService.onSessionActiveStateChanged(MediaSessionRecord.this, mPlaybackState);
@@ -1330,6 +1435,7 @@
&& TRANSITION_PRIORITY_STATES.contains(newState));
synchronized (mLock) {
mPlaybackState = state;
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false);
}
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index 0999199..b57b148 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -196,6 +196,12 @@
*/
public abstract boolean isClosed();
+ /**
+ * Note: This method is only used for testing purposes If the session is temporary engaged, the
+ * timeout will expire and it will become disengaged.
+ */
+ public abstract void expireTempEngaged();
+
@Override
public final boolean equals(Object o) {
if (this == o) return true;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 53c32cf..2ca76a5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -367,11 +367,13 @@
}
boolean isUserEngaged = isUserEngaged(record, playbackState);
- Log.d(TAG, "onSessionActiveStateChanged: "
- + "record=" + record
- + "playbackState=" + playbackState
- + "allowRunningInForeground=" + isUserEngaged);
- setForegroundServiceAllowance(record, /* allowRunningInForeground= */ isUserEngaged);
+ Log.d(
+ TAG,
+ "onSessionActiveStateChanged:"
+ + " record="
+ + record
+ + " playbackState="
+ + playbackState);
reportMediaInteractionEvent(record, isUserEngaged);
mHandler.postSessionsChanged(record);
}
@@ -479,11 +481,13 @@
}
user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);
boolean isUserEngaged = isUserEngaged(record, playbackState);
- Log.d(TAG, "onSessionPlaybackStateChanged: "
- + "record=" + record
- + "playbackState=" + playbackState
- + "allowRunningInForeground=" + isUserEngaged);
- setForegroundServiceAllowance(record, /* allowRunningInForeground= */ isUserEngaged);
+ Log.d(
+ TAG,
+ "onSessionPlaybackStateChanged:"
+ + " record="
+ + record
+ + " playbackState="
+ + playbackState);
reportMediaInteractionEvent(record, isUserEngaged);
}
}
@@ -650,33 +654,54 @@
session.close();
Log.d(TAG, "destroySessionLocked: record=" + session);
- setForegroundServiceAllowance(session, /* allowRunningInForeground= */ false);
+
reportMediaInteractionEvent(session, /* userEngaged= */ false);
mHandler.postSessionsChanged(session);
}
- private void setForegroundServiceAllowance(
- MediaSessionRecordImpl record, boolean allowRunningInForeground) {
- if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
- return;
- }
- ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
- record.getForegroundServiceDelegationOptions();
- if (foregroundServiceDelegationOptions == null) {
- return;
- }
- if (allowRunningInForeground) {
- onUserSessionEngaged(record);
+ void onSessionUserEngagementStateChange(
+ MediaSessionRecordImpl mediaSessionRecord, boolean isUserEngaged) {
+ if (isUserEngaged) {
+ addUserEngagedSession(mediaSessionRecord);
+ startFgsIfSessionIsLinkedToNotification(mediaSessionRecord);
} else {
- onUserDisengaged(record);
+ removeUserEngagedSession(mediaSessionRecord);
+ stopFgsIfNoSessionIsLinkedToNotification(mediaSessionRecord);
}
}
- private void onUserSessionEngaged(MediaSessionRecordImpl mediaSessionRecord) {
+ private void addUserEngagedSession(MediaSessionRecordImpl mediaSessionRecord) {
synchronized (mLock) {
int uid = mediaSessionRecord.getUid();
mUserEngagedSessionsForFgs.putIfAbsent(uid, new HashSet<>());
mUserEngagedSessionsForFgs.get(uid).add(mediaSessionRecord);
+ }
+ }
+
+ private void removeUserEngagedSession(MediaSessionRecordImpl mediaSessionRecord) {
+ synchronized (mLock) {
+ int uid = mediaSessionRecord.getUid();
+ Set<MediaSessionRecordImpl> mUidUserEngagedSessionsForFgs =
+ mUserEngagedSessionsForFgs.get(uid);
+ if (mUidUserEngagedSessionsForFgs == null) {
+ return;
+ }
+
+ mUidUserEngagedSessionsForFgs.remove(mediaSessionRecord);
+ if (mUidUserEngagedSessionsForFgs.isEmpty()) {
+ mUserEngagedSessionsForFgs.remove(uid);
+ }
+ }
+ }
+
+ private void startFgsIfSessionIsLinkedToNotification(
+ MediaSessionRecordImpl mediaSessionRecord) {
+ Log.d(TAG, "startFgsIfSessionIsLinkedToNotification: record=" + mediaSessionRecord);
+ if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
+ synchronized (mLock) {
+ int uid = mediaSessionRecord.getUid();
for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid, Set.of())) {
if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) {
mActivityManagerInternal.startForegroundServiceDelegate(
@@ -688,30 +713,34 @@
}
}
- private void onUserDisengaged(MediaSessionRecordImpl mediaSessionRecord) {
+ private void stopFgsIfNoSessionIsLinkedToNotification(
+ MediaSessionRecordImpl mediaSessionRecord) {
+ Log.d(TAG, "stopFgsIfNoSessionIsLinkedToNotification: record=" + mediaSessionRecord);
+ if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
synchronized (mLock) {
int uid = mediaSessionRecord.getUid();
- if (mUserEngagedSessionsForFgs.containsKey(uid)) {
- mUserEngagedSessionsForFgs.get(uid).remove(mediaSessionRecord);
- if (mUserEngagedSessionsForFgs.get(uid).isEmpty()) {
- mUserEngagedSessionsForFgs.remove(uid);
- }
+ ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
+ mediaSessionRecord.getForegroundServiceDelegationOptions();
+ if (foregroundServiceDelegationOptions == null) {
+ return;
}
- boolean shouldStopFgs = true;
- for (MediaSessionRecordImpl sessionRecord :
+ for (MediaSessionRecordImpl record :
mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) {
- for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid,
- Set.of())) {
- if (sessionRecord.isLinkedToNotification(mediaNotification)) {
- shouldStopFgs = false;
+ for (Notification mediaNotification :
+ mMediaNotifications.getOrDefault(uid, Set.of())) {
+ if (record.isLinkedToNotification(mediaNotification)) {
+ // A user engaged session linked with a media notification is found.
+ // We shouldn't call stop FGS in this case.
+ return;
}
}
}
- if (shouldStopFgs) {
- mActivityManagerInternal.stopForegroundServiceDelegate(
- mediaSessionRecord.getForegroundServiceDelegationOptions());
- }
+
+ mActivityManagerInternal.stopForegroundServiceDelegate(
+ foregroundServiceDelegationOptions);
}
}
@@ -2502,7 +2531,6 @@
}
MediaSessionRecord session = null;
MediaButtonReceiverHolder mediaButtonReceiverHolder = null;
-
if (mCustomMediaKeyDispatcher != null) {
MediaSession.Token token = mCustomMediaKeyDispatcher.getMediaSession(
keyEvent, uid, asSystemService);
@@ -2630,6 +2658,18 @@
&& streamType <= AudioManager.STREAM_NOTIFICATION;
}
+ @Override
+ public void expireTempEngagedSessions() {
+ synchronized (mLock) {
+ for (Set<MediaSessionRecordImpl> uidSessions :
+ mUserEngagedSessionsForFgs.values()) {
+ for (MediaSessionRecordImpl sessionRecord : uidSessions) {
+ sessionRecord.expireTempEngaged();
+ }
+ }
+ }
+ }
+
private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
private final String mPackageName;
private final int mPid;
@@ -3127,7 +3167,6 @@
super.onNotificationPosted(sbn);
Notification postedNotification = sbn.getNotification();
int uid = sbn.getUid();
-
if (!postedNotification.isMediaNotification()) {
return;
}
@@ -3138,8 +3177,8 @@
mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) {
ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
mediaSessionRecord.getForegroundServiceDelegationOptions();
- if (mediaSessionRecord.isLinkedToNotification(postedNotification)
- && foregroundServiceDelegationOptions != null) {
+ if (foregroundServiceDelegationOptions != null
+ && mediaSessionRecord.isLinkedToNotification(postedNotification)) {
mActivityManagerInternal.startForegroundServiceDelegate(
foregroundServiceDelegationOptions,
/* connection= */ null);
@@ -3173,21 +3212,7 @@
return;
}
- boolean shouldStopFgs = true;
- for (MediaSessionRecordImpl mediaSessionRecord :
- mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) {
- for (Notification mediaNotification :
- mMediaNotifications.getOrDefault(uid, Set.of())) {
- if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) {
- shouldStopFgs = false;
- }
- }
- }
- if (shouldStopFgs
- && notificationRecord.getForegroundServiceDelegationOptions() != null) {
- mActivityManagerInternal.stopForegroundServiceDelegate(
- notificationRecord.getForegroundServiceDelegationOptions());
- }
+ stopFgsIfNoSessionIsLinkedToNotification(notificationRecord);
}
}
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index a563808..a20de31 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -92,6 +92,8 @@
runMonitor();
} else if (cmd.equals("volume")) {
runVolume();
+ } else if (cmd.equals("expire-temp-engaged-sessions")) {
+ expireTempEngagedSessions();
} else {
showError("Error: unknown command '" + cmd + "'");
return -1;
@@ -367,4 +369,8 @@
private void runVolume() throws Exception {
VolumeCtrl.run(this);
}
+
+ private void expireTempEngagedSessions() throws Exception {
+ mSessionService.expireTempEngagedSessions();
+ }
}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 4eb8b2b..c8fd7e4 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -184,6 +184,16 @@
throwInvalidBugreportFileForCallerException(
bugreportFile, callingInfo.second);
}
+
+ boolean keepBugreportOnRetrieval = false;
+ if (onboardingBugreportV2Enabled()) {
+ keepBugreportOnRetrieval = mBugreportFilesToPersist.contains(
+ bugreportFile);
+ }
+
+ if (!keepBugreportOnRetrieval) {
+ bugreportFilesForUid.remove(bugreportFile);
+ }
} else {
ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(callingInfo);
if (bugreportFilesForCaller != null
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7db83d7..b4919a4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -174,7 +174,6 @@
import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.MathUtils;
import android.util.MutableBoolean;
@@ -4121,14 +4120,10 @@
private void handleSwitchKeyboardLayout(@NonNull KeyEvent event, int direction,
IBinder focusedToken) {
- if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- IBinder targetWindowToken =
- mWindowManagerInternal.getTargetWindowTokenFromInputToken(focusedToken);
- InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction,
- event.getDisplayId(), targetWindowToken);
- } else {
- mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
- }
+ IBinder targetWindowToken =
+ mWindowManagerInternal.getTargetWindowTokenFromInputToken(focusedToken);
+ InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction,
+ event.getDisplayId(), targetWindowToken);
}
private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 2623025..9ca4e27 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -251,12 +251,6 @@
*/
public int getCameraLensCoverState();
- /**
- * Switch the keyboard layout for the given device.
- * Direction should be +1 or -1 to go to the next or previous keyboard layout.
- */
- public void switchKeyboardLayout(int deviceId, int direction);
-
public void shutdown(boolean confirm);
public void reboot(boolean confirm);
public void rebootSafeMode(boolean confirm);
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 55eeaf2..5c24eee 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -274,6 +274,12 @@
}
@Override
+ boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
+ // TODO(b/233286785): Support sync state for wallpaper. See WindowState#prepareSync.
+ return !mVisibleRequested || !hasVisibleNotDrawnWallpaper();
+ }
+
+ @Override
public String toString() {
if (stringName == null) {
StringBuilder sb = new StringBuilder();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index aeefc34..8a68afb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3685,12 +3685,6 @@
// Called by window manager policy. Not exposed externally.
@Override
- public void switchKeyboardLayout(int deviceId, int direction) {
- mInputManager.switchKeyboardLayout(deviceId, direction);
- }
-
- // Called by window manager policy. Not exposed externally.
- @Override
public void shutdown(boolean confirm) {
// Pass in the UI context, since ShutdownThread requires it (to show UI).
ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 52df010..eac9929 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -85,7 +85,6 @@
import android.os.test.TestLooper;
import android.service.dreams.DreamManagerInternal;
import android.telecom.TelecomManager;
-import android.util.FeatureFlagUtils;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -743,15 +742,8 @@
void assertSwitchKeyboardLayout(int direction, int displayId) {
mTestLooper.dispatchAll();
- if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
- verify(mInputMethodManagerInternal).onSwitchKeyboardLayoutShortcut(eq(direction),
- eq(displayId), eq(mImeTargetWindowToken));
- verify(mWindowManagerFuncsImpl, never()).switchKeyboardLayout(anyInt(), anyInt());
- } else {
- verify(mWindowManagerFuncsImpl).switchKeyboardLayout(anyInt(), eq(direction));
- verify(mInputMethodManagerInternal, never())
- .onSwitchKeyboardLayoutShortcut(anyInt(), anyInt(), any());
- }
+ verify(mInputMethodManagerInternal).onSwitchKeyboardLayoutShortcut(eq(direction),
+ eq(displayId), eq(mImeTargetWindowToken));
}
void assertTakeBugreport() {
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
index 511c948..1390218 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -17,8 +17,12 @@
package com.android.server.wm.flicker.activityembedding.rotation
import android.platform.test.annotations.Presubmit
+import android.tools.Position
+import android.tools.datatypes.Rect
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.Condition
+import android.tools.traces.DeviceStateDump
import android.tools.traces.component.ComponentNameMatcher
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.setRotation
@@ -30,7 +34,14 @@
override val transition: FlickerBuilder.() -> Unit = {
setup { this.setRotation(flicker.scenario.startRotation) }
teardown { testApp.exit(wmHelper) }
- transitions { this.setRotation(flicker.scenario.endRotation) }
+ transitions {
+ this.setRotation(flicker.scenario.endRotation)
+ if (!flicker.scenario.isTablet) {
+ wmHelper.StateSyncBuilder()
+ .add(navBarInPosition(flicker.scenario.isGesturalNavigation))
+ .waitForAndVerify()
+ }
+ }
}
/** {@inheritDoc} */
@@ -76,4 +87,37 @@
appLayerRotates_StartingPos()
appLayerRotates_EndingPos()
}
+
+ private fun navBarInPosition(isGesturalNavigation: Boolean): Condition<DeviceStateDump> {
+ return Condition("navBarPosition") { dump ->
+ val display =
+ dump.layerState.displays.filterNot { it.isOff }.minByOrNull { it.id }
+ ?: error("There is no display!")
+ val displayArea = display.layerStackSpace
+ val navBarPosition = display.navBarPosition(isGesturalNavigation)
+ val navBarRegion = dump.layerState
+ .getLayerWithBuffer(ComponentNameMatcher.NAV_BAR)
+ ?.visibleRegion?.bounds ?: Rect.EMPTY
+
+ when (navBarPosition) {
+ Position.TOP ->
+ navBarRegion.top == displayArea.top &&
+ navBarRegion.left == displayArea.left &&
+ navBarRegion.right == displayArea.right
+ Position.BOTTOM ->
+ navBarRegion.bottom == displayArea.bottom &&
+ navBarRegion.left == displayArea.left &&
+ navBarRegion.right == displayArea.right
+ Position.LEFT ->
+ navBarRegion.left == displayArea.left &&
+ navBarRegion.top == displayArea.top &&
+ navBarRegion.bottom == displayArea.bottom
+ Position.RIGHT ->
+ navBarRegion.right == displayArea.right &&
+ navBarRegion.top == displayArea.top &&
+ navBarRegion.bottom == displayArea.bottom
+ else -> error("Unknown position $navBarPosition")
+ }
+ }
+ }
}
diff --git a/tests/FlickerTests/README.md b/tests/FlickerTests/README.md
index 6b28fdf..7429250 100644
--- a/tests/FlickerTests/README.md
+++ b/tests/FlickerTests/README.md
@@ -7,82 +7,17 @@
## Adding a Test
-By default tests should inherit from `RotationTestBase` or `NonRotationTestBase` and must override the variable `transitionToRun` (Kotlin) or the function `getTransitionToRun()` (Java).
-Only tests that are not supported by these classes should inherit directly from the `FlickerTestBase` class.
+By default, tests should inherit from `TestBase` and override the variable `transition` (Kotlin) or the function `getTransition()` (Java).
-### Rotation animations and transitions
+Inheriting from this class ensures the common assertions will be executed, namely:
-Tests that rotate the device should inherit from `RotationTestBase`.
-Tests that inherit from the class automatically receive start and end rotation values.
-Moreover, these tests inherit the following checks:
* all regions on the screen are covered
* status bar is always visible
-* status bar rotates
+* status bar is at the correct position at the start and end of the transition
* nav bar is always visible
-* nav bar is rotates
+* nav bar is at the correct position at the start and end of the transition
The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
-### Non-Rotation animations and transitions
+For more examples of how a test looks like check `ChangeAppRotationTest` within the `Rotation` subdirectory.
-`NonRotationTestBase` was created to make it easier to write tests that do not involve rotation (e.g., `Pip`, `split screen` or `IME`).
-Tests that inherit from the class are automatically executed twice: once in portrait and once in landscape mode and the assertions are checked independently.
-Moreover, these tests inherit the following checks:
-* all regions on the screen are covered
-* status bar is always visible
-* nav bar is always visible
-
-The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
-
-### Exceptional cases
-
-Tests that rotate the device should inherit from `RotationTestBase`.
-This class allows the test to be freely configured and does not provide any assertions.
-
-
-### Example
-
-Start by defining common or error prone transitions using `TransitionRunner`.
-```kotlin
-@LargeTest
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MyTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- mTestApp = MyAppHelper(InstrumentationRegistry.getInstrumentation())
- }
-
- override val transitionToRun: TransitionRunner
- get() = TransitionRunner.newBuilder()
- .withTag("myTest")
- .recordAllRuns()
- .runBefore { device.pressHome() }
- .runBefore { device.waitForIdle() }
- .run { testApp.open() }
- .runAfter{ testApp.exit() }
- .repeat(2)
- .includeJankyRuns()
- .build()
-
- @Test
- fun myWMTest() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindow(MyTestApp)
- .forAllEntries()
- }
- }
-
- @Test
- fun mySFTest() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(MyTestApp)
- .forAllEntries()
- }
- }
-}
-```
diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index e60764f..80282c3 100644
--- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -33,7 +33,6 @@
import android.os.Bundle
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
-import android.provider.Settings
import android.util.proto.ProtoOutputStream
import android.view.InputDevice
import android.view.inputmethod.InputMethodInfo
@@ -47,9 +46,7 @@
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
-import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
-import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -234,631 +231,326 @@
}
@Test
- fun testDefaultUi_getKeyboardLayouts() {
- NewSettingsApiFlag(false).use {
- val keyboardLayouts = keyboardLayoutManager.keyboardLayouts
- assertNotEquals(
- "Default UI: Keyboard layout API should not return empty array",
- 0,
- keyboardLayouts.size
- )
- assertTrue(
- "Default UI: Keyboard layout API should provide English(US) layout",
- hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- }
+ fun testGetKeyboardLayouts() {
+ val keyboardLayouts = keyboardLayoutManager.keyboardLayouts
+ assertNotEquals(
+ "Keyboard layout API should not return empty array",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue(
+ "Keyboard layout API should provide English(US) layout",
+ hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
}
@Test
- fun testNewUi_getKeyboardLayouts() {
- NewSettingsApiFlag(true).use {
- val keyboardLayouts = keyboardLayoutManager.keyboardLayouts
- assertNotEquals(
- "New UI: Keyboard layout API should not return empty array",
- 0,
- keyboardLayouts.size
- )
- assertTrue(
- "New UI: Keyboard layout API should provide English(US) layout",
- hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- }
+ fun testGetKeyboardLayout() {
+ val keyboardLayout =
+ keyboardLayoutManager.getKeyboardLayout(ENGLISH_US_LAYOUT_DESCRIPTOR)
+ assertEquals("getKeyboardLayout API should return correct Layout from " +
+ "available layouts",
+ ENGLISH_US_LAYOUT_DESCRIPTOR,
+ keyboardLayout!!.descriptor
+ )
}
@Test
- fun testDefaultUi_getKeyboardLayoutsForInputDevice() {
- NewSettingsApiFlag(false).use {
- val keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutsForInputDevice(keyboardDevice.identifier)
- assertNotEquals(
- "Default UI: getKeyboardLayoutsForInputDevice API should not return empty array",
- 0,
- keyboardLayouts.size
- )
- assertTrue(
- "Default UI: getKeyboardLayoutsForInputDevice API should provide English(US) " +
- "layout",
- hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
+ fun testGetSetKeyboardLayoutForInputDevice_withImeInfo() {
+ val imeSubtype = createImeSubtype()
- val vendorSpecificKeyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutsForInputDevice(
- vendorSpecificKeyboardDevice.identifier
- )
- assertEquals(
- "Default UI: getKeyboardLayoutsForInputDevice API should return only vendor " +
- "specific layout",
+ keyboardLayoutManager.setKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
+ ENGLISH_UK_LAYOUT_DESCRIPTOR
+ )
+ var result =
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
+ )
+ assertEquals(
+ "getKeyboardLayoutForInputDevice API should return the set layout",
+ ENGLISH_UK_LAYOUT_DESCRIPTOR,
+ result.layoutDescriptor
+ )
+
+ // This should replace previously set layout
+ keyboardLayoutManager.setKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ result =
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
+ )
+ assertEquals(
+ "getKeyboardLayoutForInputDevice API should return the last set layout",
+ ENGLISH_US_LAYOUT_DESCRIPTOR,
+ result.layoutDescriptor
+ )
+ }
+
+ @Test
+ fun testGetKeyboardLayoutListForInputDevice() {
+ // Check Layouts for "hi-Latn". It should return all 'Latn' keyboard layouts
+ var keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("hi-Latn")
+ )
+ assertNotEquals(
+ "getKeyboardLayoutListForInputDevice API should return the list of " +
+ "supported layouts with matching script code",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(US) layout for hi-Latn",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(No script code) layout for hi-Latn",
+ containsLayout(
+ keyboardLayouts,
+ createLayoutDescriptor("keyboard_layout_english_without_script_code")
+ )
+ )
+
+ // Check Layouts for "hi" which by default uses 'Deva' script.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("hi")
+ )
+ assertEquals("getKeyboardLayoutListForInputDevice API should return empty " +
+ "list if no supported layouts available",
+ 0,
+ keyboardLayouts.size
+ )
+
+ // If user manually selected some layout, always provide it in the layout list
+ val imeSubtype = createImeSubtypeForLanguageTag("hi")
+ keyboardLayoutManager.setKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ imeSubtype
+ )
+ assertEquals("getKeyboardLayoutListForInputDevice API should return user " +
+ "selected layout even if the script is incompatible with IME",
1,
- vendorSpecificKeyboardLayouts.size
- )
- assertEquals(
- "Default UI: getKeyboardLayoutsForInputDevice API should return vendor specific " +
- "layout",
- VENDOR_SPECIFIC_LAYOUT_DESCRIPTOR,
- vendorSpecificKeyboardLayouts[0].descriptor
- )
- }
- }
+ keyboardLayouts.size
+ )
- @Test
- fun testNewUi_getKeyboardLayoutsForInputDevice() {
- NewSettingsApiFlag(true).use {
- val keyboardLayouts = keyboardLayoutManager.keyboardLayouts
- assertNotEquals(
- "New UI: getKeyboardLayoutsForInputDevice API should not return empty array",
- 0,
- keyboardLayouts.size
- )
- assertTrue(
- "New UI: getKeyboardLayoutsForInputDevice API should provide English(US) " +
- "layout",
- hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- }
- }
-
- @Test
- fun testDefaultUi_getSetCurrentKeyboardLayoutForInputDevice() {
- NewSettingsApiFlag(false).use {
- assertNull(
- "Default UI: getCurrentKeyboardLayoutForInputDevice API should return null if " +
- "nothing was set",
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
-
- keyboardLayoutManager.setCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier,
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- val keyboardLayout =
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- assertEquals(
- "Default UI: getCurrentKeyboardLayoutForInputDevice API should return the set " +
- "layout",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayout
- )
- }
- }
-
- @Test
- fun testNewUi_getSetCurrentKeyboardLayoutForInputDevice() {
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.setCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier,
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- assertNull(
- "New UI: getCurrentKeyboardLayoutForInputDevice API should always return null " +
- "even after setCurrentKeyboardLayoutForInputDevice",
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
- }
- }
-
- @Test
- fun testDefaultUi_getEnabledKeyboardLayoutsForInputDevice() {
- NewSettingsApiFlag(false).use {
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_US_LAYOUT_DESCRIPTOR
- )
-
- val keyboardLayouts =
- keyboardLayoutManager.getEnabledKeyboardLayoutsForInputDevice(
- keyboardDevice.identifier
- )
- assertEquals(
- "Default UI: getEnabledKeyboardLayoutsForInputDevice API should return added " +
- "layout",
- 1,
- keyboardLayouts.size
- )
- assertEquals(
- "Default UI: getEnabledKeyboardLayoutsForInputDevice API should return " +
- "English(US) layout",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayouts[0]
- )
- assertEquals(
- "Default UI: getCurrentKeyboardLayoutForInputDevice API should return " +
- "English(US) layout (Auto select the first enabled layout)",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
-
- keyboardLayoutManager.removeKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- assertEquals(
- "Default UI: getKeyboardLayoutsForInputDevice API should return 0 layouts",
- 0,
- keyboardLayoutManager.getEnabledKeyboardLayoutsForInputDevice(
- keyboardDevice.identifier
- ).size
- )
- assertNull(
- "Default UI: getCurrentKeyboardLayoutForInputDevice API should return null after " +
- "the enabled layout is removed",
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
- }
- }
-
- @Test
- fun testNewUi_getEnabledKeyboardLayoutsForInputDevice() {
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_US_LAYOUT_DESCRIPTOR
- )
-
- assertEquals(
- "New UI: getEnabledKeyboardLayoutsForInputDevice API should return always return " +
- "an empty array",
- 0,
- keyboardLayoutManager.getEnabledKeyboardLayoutsForInputDevice(
- keyboardDevice.identifier
- ).size
- )
- assertNull(
- "New UI: getCurrentKeyboardLayoutForInputDevice API should always return null",
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
- }
- }
-
- @Test
- fun testDefaultUi_switchKeyboardLayout() {
- NewSettingsApiFlag(false).use {
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
- assertEquals(
- "Default UI: getCurrentKeyboardLayoutForInputDevice API should return " +
- "English(US) layout",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
-
- keyboardLayoutManager.switchKeyboardLayout(DEVICE_ID, 1)
-
- // Throws null pointer because trying to show toast using TestLooper
- assertThrows(NullPointerException::class.java) { testLooper.dispatchAll() }
- assertEquals("Default UI: getCurrentKeyboardLayoutForInputDevice API should return " +
- "English(UK) layout",
- ENGLISH_UK_LAYOUT_DESCRIPTOR,
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
- }
- }
-
- @Test
- fun testNewUi_switchKeyboardLayout() {
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- keyboardLayoutManager.addKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
-
- keyboardLayoutManager.switchKeyboardLayout(DEVICE_ID, 1)
- testLooper.dispatchAll()
-
- assertNull("New UI: getCurrentKeyboardLayoutForInputDevice API should always return " +
- "null",
- keyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(
- keyboardDevice.identifier
- )
- )
- }
- }
-
- @Test
- fun testDefaultUi_getKeyboardLayout() {
- NewSettingsApiFlag(false).use {
- val keyboardLayout =
- keyboardLayoutManager.getKeyboardLayout(ENGLISH_US_LAYOUT_DESCRIPTOR)
- assertEquals("Default UI: getKeyboardLayout API should return correct Layout from " +
- "available layouts",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayout!!.descriptor
- )
- }
- }
-
- @Test
- fun testNewUi_getKeyboardLayout() {
- NewSettingsApiFlag(true).use {
- val keyboardLayout =
- keyboardLayoutManager.getKeyboardLayout(ENGLISH_US_LAYOUT_DESCRIPTOR)
- assertEquals("New UI: getKeyboardLayout API should return correct Layout from " +
- "available layouts",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- keyboardLayout!!.descriptor
- )
- }
- }
-
- @Test
- fun testDefaultUi_getSetKeyboardLayoutForInputDevice_WithImeInfo() {
- NewSettingsApiFlag(false).use {
- val imeSubtype = createImeSubtype()
- keyboardLayoutManager.setKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
- ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
- assertEquals(
- "Default UI: getKeyboardLayoutForInputDevice API should always return " +
- "KeyboardLayoutSelectionResult.FAILED",
- KeyboardLayoutSelectionResult.FAILED,
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
- )
- )
- }
- }
-
- @Test
- fun testNewUi_getSetKeyboardLayoutForInputDevice_withImeInfo() {
- NewSettingsApiFlag(true).use {
- val imeSubtype = createImeSubtype()
-
- keyboardLayoutManager.setKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
- ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
- var result =
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
- )
- assertEquals(
- "New UI: getKeyboardLayoutForInputDevice API should return the set layout",
- ENGLISH_UK_LAYOUT_DESCRIPTOR,
- result.layoutDescriptor
- )
-
- // This should replace previously set layout
- keyboardLayoutManager.setKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- result =
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
- )
- assertEquals(
- "New UI: getKeyboardLayoutForInputDevice API should return the last set layout",
- ENGLISH_US_LAYOUT_DESCRIPTOR,
- result.layoutDescriptor
- )
- }
- }
-
- @Test
- fun testDefaultUi_getKeyboardLayoutListForInputDevice() {
- NewSettingsApiFlag(false).use {
- val keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ // Special case Japanese: UScript ignores provided script code for certain language tags
+ // Should manually match provided script codes and then rely on Uscript to derive
+ // script from language tags and match those.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtype()
- )
- assertEquals("Default UI: getKeyboardLayoutListForInputDevice API should always " +
- "return empty array",
- 0,
- keyboardLayouts.size
+ createImeSubtypeForLanguageTag("ja-Latn-JP")
)
- }
- }
+ assertNotEquals(
+ "getKeyboardLayoutListForInputDevice API should return the list of " +
+ "supported layouts with matching script code for ja-Latn-JP",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(US) layout for ja-Latn-JP",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(No script code) layout for ja-Latn-JP",
+ containsLayout(
+ keyboardLayouts,
+ createLayoutDescriptor("keyboard_layout_english_without_script_code")
+ )
+ )
- @Test
- fun testNewUi_getKeyboardLayoutListForInputDevice() {
- NewSettingsApiFlag(true).use {
- // Check Layouts for "hi-Latn". It should return all 'Latn' keyboard layouts
- var keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ // If script code not explicitly provided for Japanese should rely on Uscript to find
+ // derived script code and hence no suitable layout will be found.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("hi-Latn")
- )
- assertNotEquals(
- "New UI: getKeyboardLayoutListForInputDevice API should return the list of " +
- "supported layouts with matching script code",
- 0,
- keyboardLayouts.size
+ createImeSubtypeForLanguageTag("ja-JP")
)
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
- "containing English(US) layout for hi-Latn",
- containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
- "containing English(No script code) layout for hi-Latn",
- containsLayout(
- keyboardLayouts,
- createLayoutDescriptor("keyboard_layout_english_without_script_code")
- )
- )
+ assertEquals(
+ "getKeyboardLayoutListForInputDevice API should return empty list of " +
+ "supported layouts with matching script code for ja-JP",
+ 0,
+ keyboardLayouts.size
+ )
- // Check Layouts for "hi" which by default uses 'Deva' script.
- keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("hi")
- )
- assertEquals("New UI: getKeyboardLayoutListForInputDevice API should return empty " +
- "list if no supported layouts available",
- 0,
- keyboardLayouts.size
+ // If IME doesn't have a corresponding language tag, then should show all available
+ // layouts no matter the script code.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo, null
)
-
- // If user manually selected some layout, always provide it in the layout list
- val imeSubtype = createImeSubtypeForLanguageTag("hi")
- keyboardLayoutManager.setKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- imeSubtype
- )
- assertEquals("New UI: getKeyboardLayoutListForInputDevice API should return user " +
- "selected layout even if the script is incompatible with IME",
- 1,
- keyboardLayouts.size
- )
-
- // Special case Japanese: UScript ignores provided script code for certain language tags
- // Should manually match provided script codes and then rely on Uscript to derive
- // script from language tags and match those.
- keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("ja-Latn-JP")
- )
- assertNotEquals(
- "New UI: getKeyboardLayoutListForInputDevice API should return the list of " +
- "supported layouts with matching script code for ja-Latn-JP",
- 0,
- keyboardLayouts.size
- )
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
- "containing English(US) layout for ja-Latn-JP",
- containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
- "containing English(No script code) layout for ja-Latn-JP",
- containsLayout(
- keyboardLayouts,
- createLayoutDescriptor("keyboard_layout_english_without_script_code")
- )
- )
-
- // If script code not explicitly provided for Japanese should rely on Uscript to find
- // derived script code and hence no suitable layout will be found.
- keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("ja-JP")
- )
- assertEquals(
- "New UI: getKeyboardLayoutListForInputDevice API should return empty list of " +
- "supported layouts with matching script code for ja-JP",
- 0,
- keyboardLayouts.size
- )
-
- // If IME doesn't have a corresponding language tag, then should show all available
- // layouts no matter the script code.
- keyboardLayouts =
- keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo, null
- )
- assertNotEquals(
- "New UI: getKeyboardLayoutListForInputDevice API should return all layouts if" +
- "language tag or subtype not provided",
- 0,
- keyboardLayouts.size
- )
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should contain Latin " +
- "layouts if language tag or subtype not provided",
- containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
- )
- assertTrue("New UI: getKeyboardLayoutListForInputDevice API should contain Cyrillic " +
- "layouts if language tag or subtype not provided",
- containsLayout(
- keyboardLayouts,
- createLayoutDescriptor("keyboard_layout_russian")
- )
- )
- }
- }
-
- @Test
- fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withImeLanguageTag() {
- NewSettingsApiFlag(true).use {
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTag("en-US"),
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTag("en-GB"),
- ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTag("de"),
- GERMAN_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTag("fr-FR"),
- createLayoutDescriptor("keyboard_layout_french")
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTag("ru"),
+ assertNotEquals(
+ "getKeyboardLayoutListForInputDevice API should return all layouts if" +
+ "language tag or subtype not provided",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should contain Latin " +
+ "layouts if language tag or subtype not provided",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("getKeyboardLayoutListForInputDevice API should contain Cyrillic " +
+ "layouts if language tag or subtype not provided",
+ containsLayout(
+ keyboardLayouts,
createLayoutDescriptor("keyboard_layout_russian")
)
- assertEquals(
- "New UI: getDefaultKeyboardLayoutForInputDevice should return " +
- "KeyboardLayoutSelectionResult.FAILED when no layout available",
- KeyboardLayoutSelectionResult.FAILED,
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("it")
- )
- )
- assertEquals(
- "New UI: getDefaultKeyboardLayoutForInputDevice should return " +
- "KeyboardLayoutSelectionResult.FAILED when no layout for script code is" +
- "available",
- KeyboardLayoutSelectionResult.FAILED,
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTag("en-Deva")
- )
- )
- }
+ )
}
@Test
- fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withImeLanguageTagAndLayoutType() {
- NewSettingsApiFlag(true).use {
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en-US", "qwerty"),
- ENGLISH_US_LAYOUT_DESCRIPTOR
+ fun testGetDefaultKeyboardLayoutForInputDevice_withImeLanguageTag() {
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTag("en-US"),
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTag("en-GB"),
+ ENGLISH_UK_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTag("de"),
+ GERMAN_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTag("fr-FR"),
+ createLayoutDescriptor("keyboard_layout_french")
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTag("ru"),
+ createLayoutDescriptor("keyboard_layout_russian")
+ )
+ assertEquals(
+ "getDefaultKeyboardLayoutForInputDevice should return " +
+ "KeyboardLayoutSelectionResult.FAILED when no layout available",
+ KeyboardLayoutSelectionResult.FAILED,
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("it")
)
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en-US", "dvorak"),
- createLayoutDescriptor("keyboard_layout_english_us_dvorak")
- )
- // Try to match layout type even if country doesn't match
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en-GB", "dvorak"),
- createLayoutDescriptor("keyboard_layout_english_us_dvorak")
- )
- // Choose layout based on layout type priority, if layout type is not provided by IME
- // (Qwerty > Dvorak > Extended)
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en-US", ""),
- ENGLISH_US_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("en-GB", "qwerty"),
- ENGLISH_UK_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("de", "qwertz"),
- GERMAN_LAYOUT_DESCRIPTOR
- )
- // Wrong layout type should match with language if provided layout type not available
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("de", "qwerty"),
- GERMAN_LAYOUT_DESCRIPTOR
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("fr-FR", "azerty"),
- createLayoutDescriptor("keyboard_layout_french")
- )
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("ru", "qwerty"),
- createLayoutDescriptor("keyboard_layout_russian_qwerty")
- )
- // If layout type is empty then prioritize KCM with empty layout type
- assertCorrectLayout(
- keyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("ru", ""),
- createLayoutDescriptor("keyboard_layout_russian")
- )
- assertEquals("New UI: getDefaultKeyboardLayoutForInputDevice should return " +
+ )
+ assertEquals(
+ "getDefaultKeyboardLayoutForInputDevice should return " +
"KeyboardLayoutSelectionResult.FAILED when no layout for script code is" +
"available",
- KeyboardLayoutSelectionResult.FAILED,
- keyboardLayoutManager.getKeyboardLayoutForInputDevice(
- keyboardDevice.identifier, USER_ID, imeInfo,
- createImeSubtypeForLanguageTagAndLayoutType("en-Deva-US", "")
- )
+ KeyboardLayoutSelectionResult.FAILED,
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("en-Deva")
)
- }
+ )
}
@Test
- fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withHwLanguageTagAndLayoutType() {
- NewSettingsApiFlag(true).use {
- val frenchSubtype = createImeSubtypeForLanguageTagAndLayoutType("fr", "azerty")
- // Should return English dvorak even if IME current layout is French, since HW says the
- // keyboard is a Dvorak keyboard
- assertCorrectLayout(
- englishDvorakKeyboardDevice,
- frenchSubtype,
- createLayoutDescriptor("keyboard_layout_english_us_dvorak")
+ fun testGetDefaultKeyboardLayoutForInputDevice_withImeLanguageTagAndLayoutType() {
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("en-US", "qwerty"),
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("en-US", "dvorak"),
+ createLayoutDescriptor("keyboard_layout_english_us_dvorak")
+ )
+ // Try to match layout type even if country doesn't match
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("en-GB", "dvorak"),
+ createLayoutDescriptor("keyboard_layout_english_us_dvorak")
+ )
+ // Choose layout based on layout type priority, if layout type is not provided by IME
+ // (Qwerty > Dvorak > Extended)
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("en-US", ""),
+ ENGLISH_US_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("en-GB", "qwerty"),
+ ENGLISH_UK_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("de", "qwertz"),
+ GERMAN_LAYOUT_DESCRIPTOR
+ )
+ // Wrong layout type should match with language if provided layout type not available
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("de", "qwerty"),
+ GERMAN_LAYOUT_DESCRIPTOR
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("fr-FR", "azerty"),
+ createLayoutDescriptor("keyboard_layout_french")
+ )
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("ru", "qwerty"),
+ createLayoutDescriptor("keyboard_layout_russian_qwerty")
+ )
+ // If layout type is empty then prioritize KCM with empty layout type
+ assertCorrectLayout(
+ keyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("ru", ""),
+ createLayoutDescriptor("keyboard_layout_russian")
+ )
+ assertEquals("getDefaultKeyboardLayoutForInputDevice should return " +
+ "KeyboardLayoutSelectionResult.FAILED when no layout for script code is" +
+ "available",
+ KeyboardLayoutSelectionResult.FAILED,
+ keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTagAndLayoutType("en-Deva-US", "")
)
+ )
+ }
- // Back to back changing HW keyboards with same product and vendor ID but different
- // language and layout type should configure the layouts correctly.
- assertCorrectLayout(
- englishQwertyKeyboardDevice,
- frenchSubtype,
- createLayoutDescriptor("keyboard_layout_english_us")
- )
+ @Test
+ fun testGetDefaultKeyboardLayoutForInputDevice_withHwLanguageTagAndLayoutType() {
+ val frenchSubtype = createImeSubtypeForLanguageTagAndLayoutType("fr", "azerty")
+ // Should return English dvorak even if IME current layout is French, since HW says the
+ // keyboard is a Dvorak keyboard
+ assertCorrectLayout(
+ englishDvorakKeyboardDevice,
+ frenchSubtype,
+ createLayoutDescriptor("keyboard_layout_english_us_dvorak")
+ )
- // Fallback to IME information if the HW provided layout script is incompatible with the
- // provided IME subtype
- assertCorrectLayout(
- englishDvorakKeyboardDevice,
- createImeSubtypeForLanguageTagAndLayoutType("ru", ""),
- createLayoutDescriptor("keyboard_layout_russian")
- )
- }
+ // Back to back changing HW keyboards with same product and vendor ID but different
+ // language and layout type should configure the layouts correctly.
+ assertCorrectLayout(
+ englishQwertyKeyboardDevice,
+ frenchSubtype,
+ createLayoutDescriptor("keyboard_layout_english_us")
+ )
+
+ // Fallback to IME information if the HW provided layout script is incompatible with the
+ // provided IME subtype
+ assertCorrectLayout(
+ englishDvorakKeyboardDevice,
+ createImeSubtypeForLanguageTagAndLayoutType("ru", ""),
+ createLayoutDescriptor("keyboard_layout_russian")
+ )
}
@Test
@@ -867,27 +559,25 @@
KeyboardLayoutManager.ImeInfo(0, imeInfo,
createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz")))
Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
- ExtendedMockito.verify {
- FrameworkStatsLog.write(
- ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
- ArgumentMatchers.anyBoolean(),
- ArgumentMatchers.eq(keyboardDevice.vendorId),
- ArgumentMatchers.eq(keyboardDevice.productId),
- ArgumentMatchers.eq(
- createByteArray(
- KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
- LAYOUT_TYPE_DEFAULT,
- GERMAN_LAYOUT_NAME,
- KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
- "de-Latn",
- LAYOUT_TYPE_QWERTZ
- ),
+ keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
+ ExtendedMockito.verify {
+ FrameworkStatsLog.write(
+ ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+ ArgumentMatchers.anyBoolean(),
+ ArgumentMatchers.eq(keyboardDevice.vendorId),
+ ArgumentMatchers.eq(keyboardDevice.productId),
+ ArgumentMatchers.eq(
+ createByteArray(
+ KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+ LAYOUT_TYPE_DEFAULT,
+ GERMAN_LAYOUT_NAME,
+ KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
+ "de-Latn",
+ LAYOUT_TYPE_QWERTZ
),
- ArgumentMatchers.eq(keyboardDevice.deviceBus),
- )
- }
+ ),
+ ArgumentMatchers.eq(keyboardDevice.deviceBus),
+ )
}
}
@@ -897,27 +587,25 @@
KeyboardLayoutManager.ImeInfo(0, imeInfo,
createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz")))
Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceAdded(englishQwertyKeyboardDevice.id)
- ExtendedMockito.verify {
- FrameworkStatsLog.write(
- ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
- ArgumentMatchers.anyBoolean(),
- ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId),
- ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId),
- ArgumentMatchers.eq(
- createByteArray(
- "en",
- LAYOUT_TYPE_QWERTY,
- ENGLISH_US_LAYOUT_NAME,
- KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE,
- "de-Latn",
- LAYOUT_TYPE_QWERTZ
- )
- ),
- ArgumentMatchers.eq(keyboardDevice.deviceBus),
- )
- }
+ keyboardLayoutManager.onInputDeviceAdded(englishQwertyKeyboardDevice.id)
+ ExtendedMockito.verify {
+ FrameworkStatsLog.write(
+ ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+ ArgumentMatchers.anyBoolean(),
+ ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId),
+ ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId),
+ ArgumentMatchers.eq(
+ createByteArray(
+ "en",
+ LAYOUT_TYPE_QWERTY,
+ ENGLISH_US_LAYOUT_NAME,
+ KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE,
+ "de-Latn",
+ LAYOUT_TYPE_QWERTZ
+ )
+ ),
+ ArgumentMatchers.eq(keyboardDevice.deviceBus),
+ )
}
}
@@ -925,27 +613,25 @@
fun testConfigurationLogged_onInputDeviceAdded_DefaultSelection() {
val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype()))
Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
- ExtendedMockito.verify {
- FrameworkStatsLog.write(
- ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
- ArgumentMatchers.anyBoolean(),
- ArgumentMatchers.eq(keyboardDevice.vendorId),
- ArgumentMatchers.eq(keyboardDevice.productId),
- ArgumentMatchers.eq(
- createByteArray(
- KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
- LAYOUT_TYPE_DEFAULT,
- "Default",
- KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT,
- KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
- LAYOUT_TYPE_DEFAULT
- ),
+ keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id)
+ ExtendedMockito.verify {
+ FrameworkStatsLog.write(
+ ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+ ArgumentMatchers.anyBoolean(),
+ ArgumentMatchers.eq(keyboardDevice.vendorId),
+ ArgumentMatchers.eq(keyboardDevice.productId),
+ ArgumentMatchers.eq(
+ createByteArray(
+ KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+ LAYOUT_TYPE_DEFAULT,
+ "Default",
+ KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT,
+ KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
+ LAYOUT_TYPE_DEFAULT
),
- ArgumentMatchers.eq(keyboardDevice.deviceBus),
- )
- }
+ ),
+ ArgumentMatchers.eq(keyboardDevice.deviceBus),
+ )
}
}
@@ -953,19 +639,17 @@
fun testConfigurationNotLogged_onInputDeviceChanged() {
val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype()))
Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
- ExtendedMockito.verify({
- FrameworkStatsLog.write(
- ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
- ArgumentMatchers.anyBoolean(),
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.any(ByteArray::class.java),
- ArgumentMatchers.anyInt(),
- )
- }, Mockito.times(0))
- }
+ keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
+ ExtendedMockito.verify({
+ FrameworkStatsLog.write(
+ ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED),
+ ArgumentMatchers.anyBoolean(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any(ByteArray::class.java),
+ ArgumentMatchers.anyInt(),
+ )
+ }, Mockito.times(0))
}
@Test
@@ -975,18 +659,16 @@
Mockito.doReturn(false).`when`(keyboardLayoutManager).isVirtualDevice(
ArgumentMatchers.eq(keyboardDevice.id)
)
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
- ExtendedMockito.verify(
- notificationManager,
- Mockito.times(1)
- ).notifyAsUser(
- ArgumentMatchers.isNull(),
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.any(),
- ArgumentMatchers.any()
- )
- }
+ keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
+ ExtendedMockito.verify(
+ notificationManager,
+ Mockito.times(1)
+ ).notifyAsUser(
+ ArgumentMatchers.isNull(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
}
@Test
@@ -996,18 +678,16 @@
Mockito.doReturn(true).`when`(keyboardLayoutManager).isVirtualDevice(
ArgumentMatchers.eq(keyboardDevice.id)
)
- NewSettingsApiFlag(true).use {
- keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
- ExtendedMockito.verify(
- notificationManager,
- Mockito.never()
- ).notifyAsUser(
- ArgumentMatchers.isNull(),
- ArgumentMatchers.anyInt(),
- ArgumentMatchers.any(),
- ArgumentMatchers.any()
- )
- }
+ keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id)
+ ExtendedMockito.verify(
+ notificationManager,
+ Mockito.never()
+ ).notifyAsUser(
+ ArgumentMatchers.isNull(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
}
private fun assertCorrectLayout(
@@ -1019,7 +699,7 @@
device.identifier, USER_ID, imeInfo, imeSubtype
)
assertEquals(
- "New UI: getDefaultKeyboardLayoutForInputDevice should return $expectedLayout",
+ "getDefaultKeyboardLayoutForInputDevice should return $expectedLayout",
expectedLayout,
result.layoutDescriptor
)
@@ -1123,21 +803,4 @@
info.serviceInfo.name = RECEIVER_NAME
return info
}
-
- private inner class NewSettingsApiFlag constructor(enabled: Boolean) : AutoCloseable {
- init {
- Settings.Global.putString(
- context.contentResolver,
- "settings_new_keyboard_ui", enabled.toString()
- )
- }
-
- override fun close() {
- Settings.Global.putString(
- context.contentResolver,
- "settings_new_keyboard_ui",
- ""
- )
- }
- }
}