diff options
40 files changed, 344 insertions, 112 deletions
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 6c2ce3685b30..c41a5ce02e61 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -213,3 +213,12 @@ flag { is_fixed_read_only: true } +flag { + name: "fix_search_modifier_fallbacks" + namespace: "input" + description: "Fixes a bug in which fallbacks from Search based key combinations were not activating." + bug: "384113980" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1a74fe6719e3..7bb799a24ef1 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3209,6 +3209,10 @@ Note that HSUM devices without this enabled will not automatically have a main user. --> <bool name="config_isMainUserPermanentAdmin">true</bool> + <!-- Whether all secondary users (and the system user) are eligible to have profiles. + If false, only the MainUser is eligible to have profiles. --> + <bool name="config_supportProfilesOnNonMainUser">false</bool> + <!-- Whether switch to headless system user is allowed. If allowed, headless system user can run in the foreground even though it is not a full user. --> <bool name="config_canSwitchToHeadlessSystemUser">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a37ca2847638..2dc5687a1253 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -363,6 +363,7 @@ <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" /> <java-symbol type="bool" name="config_useFixedVolume" /> <java-symbol type="bool" name="config_isMainUserPermanentAdmin"/> + <java-symbol type="bool" name="config_supportProfilesOnNonMainUser"/> <java-symbol type="bool" name="config_canSwitchToHeadlessSystemUser"/> <java-symbol type="bool" name="config_enableMultiUserUI"/> <java-symbol type="bool" name="config_enableMultipleAdmins"/> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml index dd1a1b1dca13..75ec2ab9f6f9 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml @@ -18,15 +18,15 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:id="@+id/indicator_solid"> <shape android:shape="rectangle"> - <solid android:color="@androidprv:color/materialColorPrimaryContainer" /> + <solid android:color="@androidprv:color/materialColorPrimaryFixed" /> <corners android:radius="28dp" /> </shape> </item> <item android:id="@+id/indicator_stroke"> <shape android:shape="rectangle"> <corners android:radius="28dp" /> - <stroke android:width="1dp" - android:color="@androidprv:color/materialColorPrimaryContainer"/> + <stroke android:width="2dp" + android:color="@androidprv:color/materialColorPrimaryFixed"/> </shape> </item> </layer-list> diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 8d18f959951b..5732fc936b47 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -68,8 +68,6 @@ <color name="desktop_mode_caption_button_on_hover_light">#11000000</color> <color name="desktop_mode_caption_button_on_hover_dark">#11FFFFFF</color> <color name="desktop_mode_caption_button">#00000000</color> - <color name="tiling_divider_background_light">#C9C7B6</color> - <color name="tiling_divider_background_dark">#4A4739</color> <color name="tiling_handle_background_light">#000000</color> <color name="tiling_handle_background_dark">#FFFFFF</color> </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 733f3bb8d6d0..ca18c97f9127 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -304,6 +304,8 @@ <dimen name="bubble_transform_area_width">140dp</dimen> <!-- Width of the box at the corner of the screen where drag leads to app moving to bubble --> <dimen name="bubble_transform_area_height">140dp</dimen> + <!-- How much elevation a bubble ui needs when dragged, must be above drop target & dismiss. --> + <dimen name="dragged_bubble_elevation">3dp</dimen> <!-- Bottom and end margin for compat buttons. --> <dimen name="compat_button_margin">24dp</dimen> diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml index 3b504cf713f1..74b6023bde36 100644 --- a/libs/WindowManager/Shell/shared/res/values/dimen.xml +++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml @@ -39,9 +39,9 @@ <dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen> <!-- Bubble drop target dimensions --> - <dimen name="drop_target_elevation">1dp</dimen> + <dimen name="drop_target_elevation">2dp</dimen> <dimen name="drop_target_radius">28dp</dimen> - <dimen name="drop_target_stroke">1dp</dimen> + <dimen name="drop_target_stroke">2dp</dimen> <dimen name="drop_target_full_screen_padding">20dp</dimen> <dimen name="drop_target_desktop_window_padding_small">100dp</dimen> <dimen name="drop_target_desktop_window_padding_large">130dp</dimen> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt index 73277310ffe4..df101fe44b75 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt @@ -30,15 +30,15 @@ import com.android.wm.shell.shared.R class DropTargetView(context: Context) : View(context) { private val rectPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer) + color = context.getColor(com.android.internal.R.color.materialColorPrimaryFixed) style = Paint.Style.FILL alpha = (0.35f * 255).toInt() } private val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer) + color = context.getColor(com.android.internal.R.color.materialColorPrimaryFixed) style = Paint.Style.STROKE - strokeWidth = 1.dpToPx() + strokeWidth = 2.dpToPx() } private val cornerRadius = 28.dpToPx() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt index 35435569d8b1..44d859dfb9ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt @@ -17,9 +17,11 @@ package com.android.wm.shell.bubbles.bar import android.annotation.SuppressLint +import android.content.Context import android.view.MotionEvent import android.view.View import androidx.annotation.VisibleForTesting +import com.android.wm.shell.R import com.android.wm.shell.bubbles.BubblePositioner import com.android.wm.shell.shared.bubbles.BubbleBarLocation import com.android.wm.shell.shared.bubbles.DismissView @@ -32,6 +34,7 @@ import com.android.wm.shell.shared.magnetictarget.MagnetizedObject /** Controller for handling drag interactions with [BubbleBarExpandedView] */ @SuppressLint("ClickableViewAccessibility") class BubbleBarExpandedViewDragController( + private val context: Context, private val expandedView: BubbleBarExpandedView, private val dismissView: DismissView, private val animationHelper: BubbleBarAnimationHelper, @@ -54,6 +57,8 @@ class BubbleBarExpandedViewDragController( MagnetizedObject.magnetizeView(expandedView) private val magnetizedDismissTarget: MagnetizedObject.MagneticTarget + private val draggedBubbleElevation: Float + init { magnetizedExpandedView.magnetListener = MagnetListener() magnetizedExpandedView.animateStuckToTarget = @@ -70,6 +75,8 @@ class BubbleBarExpandedViewDragController( MagnetizedObject.MagneticTarget(dismissView.circle, dismissView.circle.width) magnetizedExpandedView.addTarget(magnetizedDismissTarget) + draggedBubbleElevation = context.resources.getDimension( + R.dimen.dragged_bubble_elevation) val dragMotionEventHandler = HandleDragListener() expandedView.handleView.setOnTouchListener { view, event -> @@ -103,6 +110,7 @@ class BubbleBarExpandedViewDragController( override fun onDown(v: View, ev: MotionEvent): Boolean { // While animating, don't allow new touch events if (expandedView.isAnimating) return false + expandedView.z = draggedBubbleElevation if (dropTargetManager != null && dragZoneFactory != null) { val draggedObject = DraggedObject.ExpandedView( if (bubblePositioner.isBubbleBarOnLeft) { @@ -154,11 +162,13 @@ class BubbleBarExpandedViewDragController( velX: Float, velY: Float, ) { + v.translationZ = 0f finishDrag() } override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) { isStuckToDismiss = false + v.translationZ = 0f finishDrag() } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index 2cc9387bd1e9..dd86725f7944 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -349,6 +349,7 @@ public class BubbleBarLayerView extends FrameLayout } }; mDragController = new BubbleBarExpandedViewDragController( + mContext, mExpandedView, mDismissView, mAnimationHelper, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java index cf0ecae7c815..a1e7ff04347f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java @@ -106,31 +106,37 @@ public class DividerRoundedCorner extends View { * of non split screen. * * @param isSplitScreen Whether the divider is used by split screen or tiling. - * @param isDarkMode Whether the mode is ui dark mode. + * @param color Rounded corner color. */ - public void setup(boolean isSplitScreen, boolean isDarkMode) { + public void setup(boolean isSplitScreen, int color) { mIsSplitScreen = isSplitScreen; if (!isSplitScreen) { - mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode)); + mDividerBarBackground.setColor(color); } } /** - * Notifies the divider of ui mode change. + * Notifies the divider of ui mode change and provides a new color. * - * @param isDarkMode Whether the mode is ui dark mode. + * @param color The new divider rounded corner color. */ - public void onUiModeChange(boolean isDarkMode) { + public void onUiModeChange(int color) { if (!mIsSplitScreen) { - mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode)); + mDividerBarBackground.setColor(color); invalidate(); } } - private int getTilingHandleColor(boolean isDarkMode) { - return isDarkMode ? getResources().getColor( - R.color.tiling_divider_background_dark, null /* theme */) : getResources().getColor( - R.color.tiling_divider_background_light, null /* theme */); + /** + * Notifies rounded corner view of color change. + * + * @param color The new divider rounded corner color. + */ + public void onCornerColorChange(int color) { + if (!mIsSplitScreen) { + mDividerBarBackground.setColor(color); + invalidate(); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index 8495f71ccba8..25fdbb348356 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -1299,6 +1299,7 @@ class DesktopRepository( deskByDisplayId[displayId]?.let { sequenceOf(it) } ?: emptySequence() override fun remove(deskId: Int) { + setDeskInactive(deskId) deskByDisplayId[deskId]?.clear() } @@ -1398,6 +1399,7 @@ class DesktopRepository( desktopDisplays[displayId]?.orderedDesks?.asSequence() ?: emptySequence() override fun remove(deskId: Int) { + setDeskInactive(deskId) desktopDisplays.forEach { _, display -> display.orderedDesks.removeIf { it.deskId == deskId } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt index c5057aa3cc18..f09f22fb1951 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt @@ -92,4 +92,7 @@ internal class DecorThemeUtil(private val context: Context) { Theme.LIGHT -> lightColors Theme.DARK -> darkColors } + + fun getColorScheme(isDarkMode: Boolean): ColorScheme = + if (isDarkMode) darkColors else lightColors } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt index 57f8046065b4..ab6b72947586 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt @@ -198,6 +198,11 @@ class DesktopTilingDividerWindowManager( tilingDividerView?.onUiModeChange(isDarkMode) } + /** Notifies the divider view of task info change and possible color change. */ + fun onTaskInfoChange() { + tilingDividerView?.onTaskInfoChange() + } + /** Hides the divider bar. */ fun hideDividerBar() { if (!dividerShown) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt index b57931121881..3e92d7d994a6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt @@ -375,6 +375,7 @@ class DesktopTilingWindowDecoration( fun onTaskInfoChange(taskInfo: RunningTaskInfo) { val isCurrentTaskInDarkMode = isTaskInDarkMode(taskInfo) + desktopTilingDividerWindowManager?.onTaskInfoChange() if (isCurrentTaskInDarkMode == isDarkMode || !isTilingManagerInitialised) return isDarkMode = isCurrentTaskInDarkMode desktopTilingDividerWindowManager?.onUiModeChange(isDarkMode) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt index 54dcd2d082dc..e9bd6f8ef85c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt @@ -29,6 +29,7 @@ import android.view.RoundedCorner import android.view.View import android.view.ViewConfiguration import android.widget.FrameLayout +import androidx.compose.ui.graphics.toArgb import com.android.internal.annotations.VisibleForTesting import com.android.internal.config.sysui.SystemUiDeviceConfigFlags import com.android.wm.shell.R @@ -36,6 +37,7 @@ import com.android.wm.shell.common.split.DividerHandleView import com.android.wm.shell.common.split.DividerRoundedCorner import com.android.wm.shell.shared.animation.Interpolators import com.android.wm.shell.windowdecor.DragDetector +import com.android.wm.shell.windowdecor.common.DecorThemeUtil /** Divider for tiling split screen, currently mostly a copy of [DividerView]. */ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.MotionEventHandler { @@ -56,6 +58,9 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion @VisibleForTesting var handleY: IntRange = 0..0 private var canResize = false private var resized = false + private var isDarkMode = false + private var decorThemeUtil = DecorThemeUtil(context) + /** * Tracks divider bar visible bounds in screen-based coordination. Used to calculate with * insets. @@ -90,10 +95,12 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion ) { callback = dividerMoveCallback this.dividerBounds.set(dividerBounds) + this.isDarkMode = isDarkMode + paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb() handle.setIsLeftRightSplit(true) handle.setup(/* isSplitScreen= */ false, isDarkMode) corners.setIsLeftRightSplit(true) - corners.setup(/* isSplitScreen= */ false, isDarkMode) + corners.setup(/* isSplitScreen= */ false, paint.color) handleRegionHeight = handleRegionSize.height handleRegionWidth = handleRegionSize.width cornersRadius = @@ -108,17 +115,22 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion } fun onUiModeChange(isDarkMode: Boolean) { + this.isDarkMode = isDarkMode handle.onUiModeChange(isDarkMode) - corners.onUiModeChange(isDarkMode) - paint.color = - if (isDarkMode) { - resources.getColor(R.color.tiling_divider_background_dark, null /* theme */) - } else { - resources.getColor(R.color.tiling_divider_background_light, null /* theme */) - } + paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb() + corners.onUiModeChange(paint.color) invalidate() } + fun onTaskInfoChange() { + decorThemeUtil = DecorThemeUtil(context) + if (paint.color != decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()) { + paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb() + corners.onCornerColorChange(paint.color) + invalidate() + } + } + override fun onFinishInflate() { super.onFinishInflate() dividerBar = requireViewById(R.id.divider_bar) @@ -128,15 +140,10 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion resources.getDimensionPixelSize(R.dimen.docked_stack_divider_lift_elevation) setOnTouchListener(this) setWillNotDraw(false) - paint.color = - if ( - context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == - Configuration.UI_MODE_NIGHT_YES - ) { - resources.getColor(R.color.tiling_divider_background_dark, /* theme= */null) - } else { - resources.getColor(R.color.tiling_divider_background_light, /* theme= */ null) - } + val isDarkMode = + context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == + Configuration.UI_MODE_NIGHT_YES + paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb() paint.isAntiAlias = true paint.style = Paint.Style.FILL } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt index 3fb008377d6e..6ede990df15e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt @@ -1280,6 +1280,18 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() { @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun removeDesk_multipleDesks_active_marksInactiveInDisplay() { + repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2) + repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3) + repo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 3) + + repo.removeDesk(deskId = 3) + + assertThat(repo.getActiveDeskId(displayId = DEFAULT_DISPLAY)).isNull() + } + + @Test + @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun removeDesk_multipleDesks_inactive_removes() { repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2) repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3) @@ -1292,6 +1304,18 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun removeDesk_multipleDesks_inactive_keepsOtherDeskActiveInDisplay() { + repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2) + repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3) + repo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 3) + + repo.removeDesk(deskId = 2) + + assertThat(repo.getActiveDeskId(displayId = DEFAULT_DISPLAY)).isEqualTo(3) + } + + @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) fun removeDesk_removesFromPersistence() = runTest(StandardTestDispatcher()) { diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp index 476b6fda5007..6c82aa1ca27d 100644 --- a/libs/hwui/jni/GIFMovie.cpp +++ b/libs/hwui/jni/GIFMovie.cpp @@ -63,7 +63,7 @@ GIFMovie::GIFMovie(SkStream* stream) } fCurrIndex = -1; fLastDrawIndex = -1; - fPaintingColor = SK_AlphaTRANSPARENT; + fPaintingColor = SkPackARGB32(0, 0, 0, 0); } GIFMovie::~GIFMovie() @@ -127,7 +127,7 @@ static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObje for (; width > 0; width--, src++, dst++) { if (*src != transparent && *src < cmap->ColorCount) { const GifColorType& col = cmap->Colors[*src]; - *dst = SkColorSetRGB(col.Red, col.Green, col.Blue); + *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue); } } } @@ -395,10 +395,10 @@ bool GIFMovie::onGetBitmap(SkBitmap* bm) lastIndex = fGIF->ImageCount - 1; } - SkColor bgColor = SK_ColorTRANSPARENT; + SkColor bgColor = SkPackARGB32(0, 0, 0, 0); if (gif->SColorMap != nullptr && gif->SBackGroundColor < gif->SColorMap->ColorCount) { const GifColorType& col = gif->SColorMap->Colors[gif->SBackGroundColor]; - bgColor = SkColorSetRGB(col.Red, col.Green, col.Blue); + bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue); } // draw each frames - not intelligent way @@ -411,7 +411,7 @@ bool GIFMovie::onGetBitmap(SkBitmap* bm) if (!trans && gif->SColorMap != nullptr) { fPaintingColor = bgColor; } else { - fPaintingColor = SK_ColorTRANSPARENT; + fPaintingColor = SkColorSetARGB(0, 0, 0, 0); } bm->eraseColor(fPaintingColor); diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index a696b65deabf..9da07170430f 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -2179,3 +2179,10 @@ flag { description: "Allow users to add shortcuts to open apps that are not present in the apps category in shortcut helper by default" bug: "394290928" } + +flag { + name: "use_aad_prox_sensor" + namespace: "systemui" + description: "Use AAD proximity sensor if flag is enabled and sensor is present" + bug: "402534470" +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt index 80ce43d61003..ffcd95bc7a4a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt @@ -157,7 +157,7 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { } @Test - fun showMedia_noActiveMedia_false() = + fun showMedia_InactiveMedia_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false)) runCurrent() @@ -166,6 +166,16 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { } @Test + fun showMedia_noMedia_false() = + testScope.runTest { + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) + kosmos.mediaFilterRepository.clearSelectedUserMedia() + runCurrent() + + assertThat(underTest.showMedia).isFalse() + } + + @Test fun showMedia_qsDisabled_false() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt index 701e55d0759d..d11701570e32 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt @@ -95,11 +95,21 @@ class QuickSettingsContainerViewModelTest : SysuiTestCase() { } @Test - fun showMedia_noActiveMedia_false() = + fun showMedia_InactiveMedia_true() = testScope.runTest { kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false)) runCurrent() + assertThat(underTest.showMedia).isTrue() + } + + @Test + fun showMedia_noMedia_false() = + testScope.runTest { + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) + kosmos.mediaFilterRepository.clearSelectedUserMedia() + runCurrent() + assertThat(underTest.showMedia).isFalse() } } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt index 7be323073692..9c3b9b273ab5 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt @@ -20,4 +20,8 @@ import android.content.Context import android.view.View /** Overlay to handle under-fingerprint sensor accessibility events. */ -class UdfpsAccessibilityOverlay(context: Context?) : View(context) +class UdfpsAccessibilityOverlay(context: Context?) : View(context) { + init { + accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_ASSERTIVE + } +} diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt index fa849bf5e413..1849bf20abdb 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt @@ -56,7 +56,7 @@ abstract class UdfpsAccessibilityOverlayViewModel( event.getPointerId(0), event, overlayParams, /* rotateToPortrait */ - false + false, ) if ( @@ -64,7 +64,7 @@ abstract class UdfpsAccessibilityOverlayViewModel( event.getPointerId(0), event, overlayParams, - /* rotateTouchToPortrait */ false + /* rotateTouchToPortrait */ false, ) ) { // view only receives motionEvents when [visible] which requires touchExplorationEnabled @@ -75,10 +75,10 @@ abstract class UdfpsAccessibilityOverlayViewModel( scaledTouch.x, scaledTouch.y, overlayParams, - /* touchRotatedToPortrait */ false + /* touchRotatedToPortrait */ false, ) if (announceStr != null) { - v.announceForAccessibility(announceStr) + v.contentDescription = announceStr } } // always let the motion events go through to underlying views diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java index ac1672db9375..e3990d25f94e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java @@ -237,8 +237,7 @@ public abstract class MediaOutputAdapterBase extends RecyclerView.Adapter<Recycl clickListener = v -> onItemClick(v, device); } } else { - deviceStatusIcon = getDeviceStatusIcon(device, - device.hasOngoingSession()); + deviceStatusIcon = getDeviceStatusIcon(device); clickListener = getClickListenerBasedOnSelectionBehavior(device); } deviceDisabled = clickListener == null; @@ -302,12 +301,8 @@ public abstract class MediaOutputAdapterBase extends RecyclerView.Adapter<Recycl } @Nullable - private Drawable getDeviceStatusIcon(MediaDevice device, boolean hasOngoingSession) { - if (hasOngoingSession) { - return mContext.getDrawable(R.drawable.ic_sound_bars_anim); - } else { - return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext); - } + private Drawable getDeviceStatusIcon(MediaDevice device) { + return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext); } protected void onExpandGroupButtonClicked() { diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java index 6ab4a52dc919..7ab6b3cfb8b1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java @@ -231,7 +231,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { updateFullItemClickListener(clickListener); updateContentAlpha(deviceDisabled); updateSubtitle(subtitle); - updateDeviceStatusIcon(deviceStatusIcon); + updateDeviceStatusIcon(deviceStatusIcon, ongoingSessionStatus, connectionState); updateItemBackground(connectionState); } @@ -523,11 +523,20 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mStatusIcon.setAlpha(alphaValue); } - private void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon) { - if (deviceStatusIcon == null) { + private void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon, + @Nullable OngoingSessionStatus ongoingSessionStatus, + ConnectionState connectionState) { + boolean showOngoingSession = + ongoingSessionStatus != null && connectionState == ConnectionState.DISCONNECTED; + if (deviceStatusIcon == null && !showOngoingSession) { mStatusIcon.setVisibility(View.GONE); } else { - mStatusIcon.setImageDrawable(deviceStatusIcon); + if (showOngoingSession) { + mStatusIcon.setImageDrawable( + mContext.getDrawable(R.drawable.ic_sound_bars_anim)); + } else { + mStatusIcon.setImageDrawable(deviceStatusIcon); + } mStatusIcon.setImageTintList(ColorStateList.valueOf( mController.getColorSchemeLegacy().getColorItemContent())); if (deviceStatusIcon instanceof AnimatedVectorDrawable) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt index f9b1a36621b2..11622be3d417 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt @@ -77,7 +77,7 @@ constructor( val showMedia: Boolean by hydrator.hydratedStateOf( traceName = "showMedia", - source = mediaCarouselInteractor.hasActiveMediaOrRecommendation, + source = mediaCarouselInteractor.hasAnyMediaOrRecommendation, ) override suspend fun onActivated(): Nothing { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a8bb5231d8c0..797ee002affb 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4190,7 +4190,13 @@ public class AudioService extends IAudioService.Stub Log.d(TAG, "adjustStreamVolume postSetHearingAidVolumeIndex index=" + newIndex + " stream=" + streamType); } - mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType); + int haIndex; + final VolumeStreamState vss = getVssForStreamOrDefault(streamType); + synchronized (mVolumeStateLock) { + haIndex = (int) (vss.getMinIndex() + (newIndex - vss.getMinIndex()) + / vss.getIndexStepFactor()); + } + mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType); } } @@ -5149,7 +5155,13 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.postSetLeAudioVolumeIndex(index * 10, getVssForStreamOrDefault(streamType).getMaxIndex(), streamType); } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { - mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType); + int haIndex = index * 10; + final VolumeStreamState vss = getVssForStreamOrDefault(streamType); + synchronized (mVolumeStateLock) { + haIndex = (int) (vss.getMinIndex() + + (haIndex - vss.getMinIndex()) / vss.getIndexStepFactor()); + } + mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType); } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) { mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index); } else { @@ -5280,7 +5292,13 @@ public class AudioService extends IAudioService.Stub && streamType == getBluetoothContextualVolumeStream()) { Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index + " stream=" + streamType); - mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType); + int haIndex; + final VolumeStreamState vss = getVssForStreamOrDefault(streamType); + synchronized (mVolumeStateLock) { + haIndex = (int) (vss.getMinIndex() + + (index - vss.getMinIndex()) / vss.getIndexStepFactor()); + } + mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType); } synchronized (mHdmiClientLock) { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index fa18d96d0dab..6af55300d0b3 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -25,6 +25,7 @@ import static android.view.KeyEvent.KEYCODE_UNKNOWN; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.hardware.input.Flags.enableCustomizableInputGestures; +import static com.android.hardware.input.Flags.fixSearchModifierFallbacks; import static com.android.hardware.input.Flags.keyEventActivityDetection; import static com.android.hardware.input.Flags.touchpadVisualizer; import static com.android.hardware.input.Flags.useKeyGestureEventHandler; @@ -2659,6 +2660,8 @@ public class InputManagerService extends IInputManager.Stub @SuppressWarnings("unused") @VisibleForTesting long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { + final long keyNotConsumedGoFallback = -2; + final long keyConsumed = -1; final long keyNotConsumed = 0; long value = keyNotConsumed; // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts @@ -2673,6 +2676,16 @@ public class InputManagerService extends IInputManager.Stub value = mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); } + if (fixSearchModifierFallbacks() && value == keyNotConsumed && event.isMetaPressed()) { + // If the key has not been consumed and includes the meta key, do not send the event + // to the app and attempt to generate a fallback. + final KeyCharacterMap kcm = event.getKeyCharacterMap(); + final KeyCharacterMap.FallbackAction fallbackAction = + kcm.getFallbackAction(event.getKeyCode(), event.getMetaState()); + if (fallbackAction != null) { + return keyNotConsumedGoFallback; + } + } return value; } @@ -3316,9 +3329,10 @@ public class InputManagerService extends IInputManager.Stub * @param token the window token that's about to receive this event * @param event the key event that's being dispatched * @param policyFlags the policy flags - * @return negative value if the key should be skipped (not sent to the app). 0 if the key - * should proceed getting dispatched to the app. positive value to indicate the additional - * time delay, in nanoseconds, to wait before sending this key to the app. + * @return -1 if the key should be skipped (not sent to the app). -2 if the key should not + * be sent to the app, but it should still generate a fallback. + * 0 if the key should proceed getting dispatched to the app. positive value to indicate the + * additional time delay, in nanoseconds, to wait before sending this key to the app. */ long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2744721c3a46..e9f522d08328 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -86,6 +86,7 @@ import static android.view.contentprotection.flags.Flags.createAccessibilityOver import static com.android.hardware.input.Flags.enableNew25q2Keycodes; import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures; import static com.android.hardware.input.Flags.enableVoiceAccessKeyGestures; +import static com.android.hardware.input.Flags.fixSearchModifierFallbacks; import static com.android.hardware.input.Flags.inputManagerLifecycleSupport; import static com.android.hardware.input.Flags.keyboardA11yShortcutControl; import static com.android.hardware.input.Flags.modifierShortcutDump; @@ -4181,6 +4182,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } + if (fixSearchModifierFallbacks()) { + // Pass event as unhandled to give other services, e.g. InputManagerService, the + // opportunity to determine if the event can be modified, e.g. generating a fallback for + // meta/search events. + return false; + } + // Reserve all the META modifier combos for system behavior return (metaState & KeyEvent.META_META_ON) != 0; } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 51c3da098020..02b53b0106b8 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -512,9 +512,14 @@ class TransitionController { return false; } + /** Returns {@code true} if the display contains a collecting transition. */ + boolean isCollectingTransitionOnDisplay(@NonNull DisplayContent dc) { + return mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc); + } + /** Returns {@code true} if the display contains a running or pending transition. */ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) { - if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) { + if (isCollectingTransitionOnDisplay(dc)) { return true; } for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a9bb690d4e53..3ccbc868377e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1845,9 +1845,12 @@ public class WindowManagerService extends IWindowManager.Stub // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && win.isPresentation()) { - Transition transition = null; + final boolean wasTransitionOnDisplay = + win.mTransitionController.isCollectingTransitionOnDisplay(displayContent); + Transition newlyCreatedTransition = null; if (!win.mTransitionController.isCollecting()) { - transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN); + newlyCreatedTransition = + win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN); } win.mTransitionController.collect(win.mToken); res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, @@ -1856,9 +1859,14 @@ public class WindowManagerService extends IWindowManager.Stub // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); - win.mTransitionController.getCollectingTransition().setReady(win.mToken, true); - if (transition != null) { - win.mTransitionController.requestStartTransition(transition, null, + if (!wasTransitionOnDisplay && win.mTransitionController + .isCollectingTransitionOnDisplay(displayContent)) { + // Set the display ready only when the display gets added to the collecting + // transition in this operation. + win.mTransitionController.setReady(win.mToken); + } + if (newlyCreatedTransition != null) { + win.mTransitionController.requestStartTransition(newlyCreatedTransition, null, null /* remoteTransition */, null /* displayChange */); } } else { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 22ddd5f39b24..d43aba0d218d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2365,9 +2365,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && isPresentation()) { - Transition transition = null; + final boolean wasTransitionOnDisplay = + mTransitionController.isCollectingTransitionOnDisplay(displayContent); + Transition newlyCreatedTransition = null; if (!mTransitionController.isCollecting()) { - transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE); + newlyCreatedTransition = + mTransitionController.createAndStartCollecting(TRANSIT_CLOSE); } mTransitionController.collect(mToken); mAnimatingExit = true; @@ -2376,9 +2379,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // A presentation hides all activities behind on the same display. mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); - mTransitionController.getCollectingTransition().setReady(mToken, true); - if (transition != null) { - mTransitionController.requestStartTransition(transition, null, + if (!wasTransitionOnDisplay && mTransitionController + .isCollectingTransitionOnDisplay(displayContent)) { + // Set the display ready only when the display gets added to the collecting + // transition in this operation. + mTransitionController.setReady(mToken); + } + if (newlyCreatedTransition != null) { + mTransitionController.requestStartTransition(newlyCreatedTransition, null, null /* remoteTransition */, null /* displayChange */); } } else { diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index ec8794f8073f..017284cded8e 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1978,6 +1978,11 @@ NativeInputManager::interceptKeyBeforeDispatching(const sp<IBinder>& token, return inputdispatcher::KeyEntry::InterceptKeyResult::SKIP; } + // -2 : Skip sending even to application and go directly to post processing e.g. fallbacks. + if (delayMillis == -2) { + return inputdispatcher::KeyEntry::InterceptKeyResult::FALLBACK; + } + return milliseconds_to_nanoseconds(delayMillis); } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java index 554b5b4297f2..740424813c2a 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java @@ -98,9 +98,9 @@ public class UserDataPreparerTest { File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID); systemDeDir.mkdirs(); mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_DE); - verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), + verify(mStorageManagerMock).prepareUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_DE)); - verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID), + verify(mInstaller).createUserData(isNull(), eq(TEST_USER_ID), eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE)); int serialNumber = UserDataPreparer.getSerialNumber(userDeDir); assertEquals(TEST_USER_SERIAL, serialNumber); @@ -115,9 +115,9 @@ public class UserDataPreparerTest { File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID); systemCeDir.mkdirs(); mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE); - verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), + verify(mStorageManagerMock).prepareUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); - verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID), + verify(mInstaller).createUserData(isNull(), eq(TEST_USER_ID), eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE)); int serialNumber = UserDataPreparer.getSerialNumber(userCeDir); assertEquals(TEST_USER_SERIAL, serialNumber); @@ -129,10 +129,10 @@ public class UserDataPreparerTest { public void testPrepareUserData_forNewUser_destroysOnFailure() throws Exception { TEST_USER.lastLoggedInTime = 0; doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock) - .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), + .prepareUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE); - verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID), + verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); } @@ -140,10 +140,10 @@ public class UserDataPreparerTest { public void testPrepareUserData_forExistingUser_doesNotDestroyOnFailure() throws Exception { TEST_USER.lastLoggedInTime = System.currentTimeMillis(); doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock) - .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), + .prepareUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE); - verify(mStorageManagerMock, never()).destroyUserStorage(isNull(String.class), + verify(mStorageManagerMock, never()).destroyUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); } @@ -171,9 +171,9 @@ public class UserDataPreparerTest { mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE); - verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID), + verify(mInstaller).destroyUserData(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_DE)); - verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID), + verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_DE)); // systemDir (normal path: /data/system/users/$userId) should have been deleted. @@ -195,9 +195,9 @@ public class UserDataPreparerTest { mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE); - verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID), + verify(mInstaller).destroyUserData(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); - verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID), + verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE)); // systemCeDir (normal path: /data/system_ce/$userId) should still exist but be empty, since @@ -225,7 +225,7 @@ public class UserDataPreparerTest { .reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2), Arrays.asList(dir1, dir2, dir3)); // Verify that user 3 data is removed - verify(mInstaller).destroyUserData(isNull(String.class), eq(3), + verify(mInstaller).destroyUserData(isNull(), eq(3), eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE)); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index c50c62323212..a1f73170e549 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -816,14 +816,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkIntentAction( DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED), MockUtils.checkUserHandle(CALLER_USER_HANDLE), - isNull(String.class), + isNull(), eq(AppOpsManager.OP_NONE), any(Bundle.class), any(BroadcastReceiver.class), eq(dpms.mHandler), eq(Activity.RESULT_OK), - isNull(String.class), - isNull(Bundle.class)); + isNull(), + isNull()); assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( @@ -873,14 +873,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkIntentAction( DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED), MockUtils.checkUserHandle(CALLER_USER_HANDLE), - isNull(String.class), + isNull(), eq(AppOpsManager.OP_NONE), any(Bundle.class), any(BroadcastReceiver.class), eq(dpms.mHandler), eq(Activity.RESULT_OK), - isNull(String.class), - isNull(Bundle.class)); + isNull(), + isNull()); assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java index 88395a4889c4..071bd739072b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java @@ -306,9 +306,9 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { // This method is always called, even with PI == null. if (resultIntent == null) { - verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(isNull()); } else { - verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(notNull()); } runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -619,7 +619,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { makeResultIntent())); // The intent should be sent right away. - verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(notNull()); }); // Already pinned. @@ -661,7 +661,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertTrue(request.accept()); // The intent is only sent once, so times(1). - verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(isNull()); }); // Still pinned. @@ -698,7 +698,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { makeResultIntent())); // The intent should be sent right away. - verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(notNull()); }); // Already pinned. @@ -742,7 +742,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertTrue(request.accept()); // The intent is only sent once, so times(1). - verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class)); + verify(mServiceContext, times(1)).sendIntentSender(isNull()); }); // Still pinned. diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java index 4a97b4670289..291d0ec8fbfc 100644 --- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java @@ -85,7 +85,7 @@ public class DiskStatsLoggingServiceTest extends AndroidTestCase { mDownloads = new TemporaryFolder(); mDownloads.create(); mStorageStats = new ExternalStorageStats(); - when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class))) + when(mSsm.queryExternalStatsForUser((String)isNull(), any(UserHandle.class))) .thenReturn(mStorageStats); when(mJobService.getSystemService(anyString())).thenReturn(mSsm); } diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java index f3d5e39ec127..8d164e1acf74 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java @@ -53,14 +53,16 @@ import android.app.AppOpsManager; import android.content.Context; import android.hardware.input.InputManager; import android.os.Bundle; +import android.os.IBinder; import android.os.PowerManager; import android.os.PowerManagerInternal; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; import android.testing.TestableContext; -import android.view.contentprotection.flags.Flags; +import android.view.KeyEvent; import androidx.test.filters.SmallTest; @@ -102,6 +104,8 @@ public class PhoneWindowManagerTests { public final TestableContext mContext = spy( new TestableContext(getInstrumentation().getContext())); + @Mock private IBinder mInputToken; + PhoneWindowManager mPhoneWindowManager; @Mock private ActivityTaskManagerInternal mAtmInternal; @@ -125,6 +129,8 @@ public class PhoneWindowManagerTests { @Mock private LockPatternUtils mLockPatternUtils; + private static final int INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY = 0; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -216,7 +222,7 @@ public class PhoneWindowManagerTests { @Test public void testCheckAddPermission_withoutAccessibilityOverlay_noAccessibilityAppOpLogged() { - mSetFlagsRule.enableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_WALLPAPER, /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); @@ -225,7 +231,7 @@ public class PhoneWindowManagerTests { @Test public void testCheckAddPermission_withAccessibilityOverlay() { - mSetFlagsRule.enableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); @@ -234,7 +240,7 @@ public class PhoneWindowManagerTests { @Test public void testCheckAddPermission_withAccessibilityOverlay_flagDisabled() { - mSetFlagsRule.disableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); int[] outAppOp = new int[1]; assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY)); @@ -401,6 +407,35 @@ public class PhoneWindowManagerTests { verify(mDreamManagerInternal).requestDream(); } + @EnableFlags(com.android.hardware.input.Flags.FLAG_FIX_SEARCH_MODIFIER_FALLBACKS) + public void testInterceptKeyBeforeDispatching() { + // Handle sub-tasks of init(). + doNothing().when(mPhoneWindowManager).updateSettings(any()); + doNothing().when(mPhoneWindowManager).initializeHdmiState(); + final DisplayPolicy displayPolicy = mock(DisplayPolicy.class); + mPhoneWindowManager.mDefaultDisplayPolicy = displayPolicy; + mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class); + final PowerManager pm = mock(PowerManager.class); + doReturn(true).when(pm).isInteractive(); + doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE)); + + mContext.getMainThreadHandler().runWithScissors(() -> mPhoneWindowManager.init( + new PhoneWindowManager.Injector(mContext, + mock(WindowManagerPolicy.WindowManagerFuncs.class))), 0); + + // Case: KeyNotConsumed with meta key. + KeyEvent keyEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, + KeyEvent.KEYCODE_A, 0, KeyEvent.META_META_ON); + long result = mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, keyEvent, 0); + assertEquals(INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY, result); + + // Case: KeyNotConsumed without meta key. + KeyEvent keyEvent1 = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, + KeyEvent.KEYCODE_ESCAPE, 0, 0); + long result1 = mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, keyEvent1, 0); + assertEquals(INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY, result1); + } + private void initPhoneWindowManager() { mPhoneWindowManager.mDefaultDisplayPolicy = mDisplayPolicy; mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class); diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index 7ec8f9ce9864..71c7a6b1119d 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -35,8 +35,8 @@ import android.os.PermissionEnforcer import android.os.SystemClock import android.os.test.FakePermissionEnforcer import android.os.test.TestLooper -import android.platform.test.annotations.Presubmit import android.platform.test.annotations.EnableFlags +import android.platform.test.annotations.Presubmit import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import android.view.View.OnKeyListener @@ -373,6 +373,29 @@ class InputManagerServiceTests { } @Test + @EnableFlags(com.android.hardware.input.Flags.FLAG_FIX_SEARCH_MODIFIER_FALLBACKS) + fun testInterceptKeyBeforeDispatchingWithFallthroughEvent() { + service.systemRunning() + overrideSendActionKeyEventsToFocusedWindow( + /* hasPermission = */false, + /* hasPrivateFlag = */false + ) + whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(0) + + // Create a fallback for a key event with a meta modifier. Should result in -2, + // which represents the fallback event, which indicates that original key event will + // be ignored (not sent to app) and instead the fallback will be created and sent to the + // app. + val fallbackAction: KeyCharacterMap.FallbackAction = KeyCharacterMap.FallbackAction.obtain() + fallbackAction.keyCode = KeyEvent.KEYCODE_SEARCH + whenever(kcm.getFallbackAction(anyInt(), anyInt())).thenReturn(fallbackAction) + + val event = KeyEvent( /* downTime= */0, /* eventTime= */0, KeyEvent.ACTION_DOWN, + KeyEvent.KEYCODE_SPACE, /* repeat= */0, KeyEvent.META_META_ON) + assertEquals(-2, service.interceptKeyBeforeDispatching(null, event, 0)) + } + + @Test fun testKeyEventsNotForwardedToFocusedWindow_whenWmConsumes() { service.systemRunning() overrideSendActionKeyEventsToFocusedWindow( diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java index adefac64dbae..6846d489ecaa 100644 --- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java +++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java @@ -231,7 +231,7 @@ public class SmsApplicationTest { .replacePreferredActivity(intentFilterCaptor.capture(), eq(IntentFilter.MATCH_CATEGORY_SCHEME | IntentFilter.MATCH_ADJUSTMENT_NORMAL), - isNotNull(List.class), + (List<ComponentName>)isNotNull(), eq(new ComponentName(TEST_COMPONENT_NAME.getPackageName(), SEND_TO_NAME))); Set<String> capturedSchemes = intentFilterCaptor.getAllValues().stream() |