Merge "Add "Sensitive Content" public view" into main
diff --git a/MEMORY_OWNERS b/MEMORY_OWNERS
index 89ce5140..12aa295 100644
--- a/MEMORY_OWNERS
+++ b/MEMORY_OWNERS
@@ -2,5 +2,4 @@
tjmercier@google.com
kaleshsingh@google.com
jyescas@google.com
-carlosgalo@google.com
jji@google.com
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 313bad5..c4d11cd 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -204,3 +204,10 @@
description: "Allows the user to disable input scrolling acceleration for mouse."
bug: "383555305"
}
+
+flag {
+ name: "remove_fallback_modifiers"
+ namespace: "input"
+ description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent."
+ bug: "382545048"
+}
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
index 90136ae..ffe8086 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
@@ -93,6 +93,10 @@
* must do its own state management (keeping in mind that the service's process might be killed
* by the Android System when unbound; for example, if the device is running low in memory).
*
+ * <p> The service also provides pending intents to override the system's Quick Access activities
+ * via the {@link #getTargetActivityPendingIntent} and the
+ * {@link #getGestureTargetActivityPendingIntent} method.
+ *
* <p>
* <a name="ErrorHandling"></a>
* <h3>Error handling</h3>
@@ -384,6 +388,10 @@
*
* <p>The pending intent will be sent when the user performs a gesture to open Wallet.
* The pending intent should launch an activity.
+ *
+ * <p> If the gesture is performed and this method returns null, the system will launch the
+ * activity specified by the {@link #getTargetActivityPendingIntent} method. If that method
+ * also returns null, the system will launch the system-provided card switcher activity.
*/
@Nullable
@FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index a8d4e2d..48dfdd4 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,6 +16,9 @@
package android.view;
+
+import static com.android.hardware.input.Flags.removeFallbackModifiers;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -458,7 +461,15 @@
FallbackAction action = FallbackAction.obtain();
metaState = KeyEvent.normalizeMetaState(metaState);
if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) {
- action.metaState = KeyEvent.normalizeMetaState(action.metaState);
+ if (removeFallbackModifiers()) {
+ // Strip all modifiers. This is safe to do since only exact keyCode + metaState
+ // modifiers will trigger a fallback.
+ // E.g. Ctrl + Space -> language_switch (fallback generated)
+ // Ctrl + Alt + Space -> Ctrl + Alt + Space (no fallback generated)
+ action.metaState = 0;
+ } else {
+ action.metaState = KeyEvent.normalizeMetaState(action.metaState);
+ }
return action;
}
action.recycle();
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index c97d3ec..abd93cf 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -105,6 +105,13 @@
flag {
namespace: "windowing_sdk"
+ name: "activity_embedding_support_for_connected_displays"
+ description: "Enables activity embedding support for connected displays, including enabling AE optimization for Settings."
+ bug: "369438353"
+}
+
+flag {
+ namespace: "windowing_sdk"
name: "wlinfo_oncreate"
description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()"
bug: "337820752"
diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp
index 41d1b5c..eecf199 100644
--- a/libs/WindowManager/Shell/multivalentTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentTests/Android.bp
@@ -55,6 +55,7 @@
"truth",
"flag-junit-base",
"flag-junit",
+ "testables",
],
auto_gen_config: true,
}
@@ -77,6 +78,7 @@
"truth",
"platform-test-annotations",
"platform-test-rules",
+ "testables",
],
libs: [
"android.test.base.stubs.system",
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
index 0d8f809..3e01256 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles.bar
+import android.animation.AnimatorTestRule
+import android.app.ActivityManager
import android.content.Context
import android.graphics.Insets
import android.graphics.Rect
@@ -23,7 +25,6 @@
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -36,27 +37,34 @@
import com.android.wm.shell.bubbles.BubbleLogger
import com.android.wm.shell.bubbles.BubbleOverflow
import com.android.wm.shell.bubbles.BubblePositioner
+import com.android.wm.shell.bubbles.BubbleTaskView
import com.android.wm.shell.bubbles.DeviceConfig
import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager
import com.android.wm.shell.bubbles.FakeBubbleFactory
-import com.android.wm.shell.bubbles.FakeBubbleTaskViewFactory
+import com.android.wm.shell.taskview.TaskView
+import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import org.junit.After
import org.junit.Before
-import org.junit.ClassRule
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
/** Tests for [BubbleBarAnimationHelper] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class BubbleBarAnimationHelperTest {
- companion object {
- @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule()
+ @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
+ companion object {
const val SCREEN_WIDTH = 2000
const val SCREEN_HEIGHT = 1000
}
@@ -148,6 +156,26 @@
}
@Test
+ fun animateSwitch_bubbleToBubble_updateTaskBounds() {
+ val fromBubble = createBubble("from").initialize(container)
+ val toBubbleTaskController = mock<TaskViewTaskController>()
+ val toBubble = createBubble("to", toBubbleTaskController).initialize(container)
+
+ getInstrumentation().runOnMainSync {
+ animationHelper.animateSwitch(fromBubble, toBubble) {}
+ // Start the animation, but don't finish
+ animatorTestRule.advanceTimeBy(100)
+ }
+ getInstrumentation().waitForIdleSync()
+ // Clear invocations to ensure that bounds update happens after animation ends
+ clearInvocations(toBubbleTaskController)
+ getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) }
+ getInstrumentation().waitForIdleSync()
+
+ verify(toBubbleTaskController).setWindowBounds(any())
+ }
+
+ @Test
fun animateSwitch_bubbleToOverflow_oldHiddenNewShown() {
val fromBubble = createBubble(key = "from").initialize(container)
val overflow = createOverflow().initialize(container)
@@ -193,13 +221,43 @@
assertThat(toBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse()
}
- private fun createBubble(key: String): Bubble {
+ @Test
+ fun animateToRestPosition_updateTaskBounds() {
+ val taskController = mock<TaskViewTaskController>()
+ val bubble = createBubble("key", taskController).initialize(container)
+
+ getInstrumentation().runOnMainSync {
+ animationHelper.animateExpansion(bubble) {}
+ animatorTestRule.advanceTimeBy(1000)
+ }
+ getInstrumentation().waitForIdleSync()
+ getInstrumentation().runOnMainSync {
+ animationHelper.animateToRestPosition()
+ animatorTestRule.advanceTimeBy(100)
+ }
+ // Clear invocations to ensure that bounds update happens after animation ends
+ clearInvocations(taskController)
+ getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) }
+ getInstrumentation().waitForIdleSync()
+
+ verify(taskController).setWindowBounds(any())
+ }
+
+ private fun createBubble(
+ key: String,
+ taskViewTaskController: TaskViewTaskController = mock<TaskViewTaskController>(),
+ ): Bubble {
+ val taskView = TaskView(context, taskViewTaskController)
+ val taskInfo = mock<ActivityManager.RunningTaskInfo>()
+ whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo)
+ val bubbleTaskView = BubbleTaskView(taskView, mainExecutor)
+
val bubbleBarExpandedView =
FakeBubbleFactory.createExpandedView(
context,
bubblePositioner,
expandedViewManager,
- FakeBubbleTaskViewFactory(context, mainExecutor).create(),
+ bubbleTaskView,
mainExecutor,
bgExecutor,
bubbleLogger,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 3e8a9b6..3188e5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -463,6 +463,7 @@
super.onAnimationEnd(animation);
bbev.resetPivot();
bbev.setDragging(false);
+ updateExpandedView(bbev);
}
});
startNewAnimator(animatorSet);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index c74bf53..9ebb7f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -643,7 +643,9 @@
t.setPosition(animatingLeash, x, endY);
t.setAlpha(animatingLeash, 1.f);
}
- dispatchEndPositioning(mDisplayId, mCancelled, t);
+ if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+ dispatchEndPositioning(mDisplayId, mCancelled, t);
+ }
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_ANIMATION_RUNNING);
@@ -659,6 +661,14 @@
ImeTracker.forLogging().onCancelled(mStatsToken,
ImeTracker.PHASE_WM_ANIMATION_RUNNING);
}
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // In split screen, we also set {@link
+ // WindowContainer#mExcludeInsetsTypes} but this should only happen after
+ // the IME client visibility was set. Otherwise the insets will we
+ // dispatched too early, and we get a flicker. Thus, only dispatching it
+ // after reporting that the IME is hidden to system server.
+ dispatchEndPositioning(mDisplayId, mCancelled, t);
+ }
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_END,
mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index 03a2101..218983a 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -31,7 +31,6 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.widget.preference.selector.R;
-import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags;
/**
* Selector preference (checkbox or radio button) with an optional additional widget.
@@ -180,10 +179,8 @@
: getContext().getString(R.string.settings_label));
}
- if (Flags.allowSetTitleMaxLines()) {
- TextView title = (TextView) holder.findViewById(android.R.id.title);
- title.setMaxLines(mTitleMaxLines);
- }
+ TextView title = (TextView) holder.findViewById(android.R.id.title);
+ title.setMaxLines(mTitleMaxLines);
}
/**
@@ -244,16 +241,12 @@
setLayoutResource(R.layout.preference_selector_with_widget);
setIconSpaceReserved(false);
- if (Flags.allowSetTitleMaxLines()) {
- final TypedArray a =
- context.obtainStyledAttributes(
- attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr,
- defStyleRes);
- mTitleMaxLines =
- a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines,
- DEFAULT_MAX_LINES);
- a.recycle();
- }
+ final TypedArray a =
+ context.obtainStyledAttributes(
+ attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr, defStyleRes);
+ mTitleMaxLines =
+ a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines, DEFAULT_MAX_LINES);
+ a.recycle();
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
index 2b8b3b7..c939c77 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
@@ -21,9 +21,6 @@
import static org.junit.Assert.assertEquals;
import android.app.Application;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -33,10 +30,8 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.settingslib.widget.preference.selector.R;
-import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -45,7 +40,6 @@
@RunWith(RobolectricTestRunner.class)
public class SelectorWithWidgetPreferenceTest {
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private Application mContext;
private SelectorWithWidgetPreference mPreference;
@@ -128,26 +122,6 @@
}
@Test
- @DisableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
- public void onBindViewHolder_titleMaxLinesSet_flagOff_titleMaxLinesMatchesDefault() {
- final int titleMaxLines = 5;
- AttributeSet attributeSet = Robolectric.buildAttributeSet()
- .addAttribute(R.attr.titleMaxLines, String.valueOf(titleMaxLines))
- .build();
- mPreference = new SelectorWithWidgetPreference(mContext, attributeSet);
- View view = LayoutInflater.from(mContext)
- .inflate(mPreference.getLayoutResource(), null /* root */);
- PreferenceViewHolder preferenceViewHolder =
- PreferenceViewHolder.createInstanceForTests(view);
-
- mPreference.onBindViewHolder(preferenceViewHolder);
-
- TextView title = (TextView) preferenceViewHolder.findViewById(android.R.id.title);
- assertThat(title.getMaxLines()).isEqualTo(SelectorWithWidgetPreference.DEFAULT_MAX_LINES);
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
public void onBindViewHolder_noTitleMaxLinesSet_titleMaxLinesMatchesDefault() {
AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
mPreference = new SelectorWithWidgetPreference(mContext, attributeSet);
@@ -163,7 +137,6 @@
}
@Test
- @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
public void onBindViewHolder_titleMaxLinesSet_titleMaxLinesUpdated() {
final int titleMaxLines = 5;
AttributeSet attributeSet = Robolectric.buildAttributeSet()
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
index ca2b957..7d27a56 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
@@ -195,7 +195,10 @@
// Create the origin leash and add to the transition root leash.
mOriginLeash =
new SurfaceControl.Builder().setName("OriginTransition-origin-leash").build();
- mStartTransaction
+
+ // Create temporary transaction to build
+ final SurfaceControl.Transaction tmpTransaction = new SurfaceControl.Transaction();
+ tmpTransaction
.reparent(mOriginLeash, rootLeash)
.show(mOriginLeash)
.setCornerRadius(mOriginLeash, windowRadius)
@@ -208,14 +211,14 @@
int mode = change.getMode();
SurfaceControl leash = change.getLeash();
// Reparent leash to the transition root.
- mStartTransaction.reparent(leash, rootLeash);
+ tmpTransaction.reparent(leash, rootLeash);
if (TransitionUtil.isOpeningMode(mode)) {
openingSurfaces.add(change.getLeash());
// For opening surfaces, ending bounds are base bound. Apply corner radius if
// it's full screen.
Rect bounds = change.getEndAbsBounds();
if (displayBounds.equals(bounds)) {
- mStartTransaction
+ tmpTransaction
.setCornerRadius(leash, windowRadius)
.setWindowCrop(leash, bounds.width(), bounds.height());
}
@@ -226,28 +229,53 @@
// it's full screen.
Rect bounds = change.getStartAbsBounds();
if (displayBounds.equals(bounds)) {
- mStartTransaction
+ tmpTransaction
.setCornerRadius(leash, windowRadius)
.setWindowCrop(leash, bounds.width(), bounds.height());
}
}
}
+ if (openingSurfaces.isEmpty() && closingSurfaces.isEmpty()) {
+ logD("prepareUIs: no opening/closing surfaces available, nothing to prepare.");
+ return false;
+ }
+
// Set relative order:
// ---- App1 ----
// ---- origin ----
// ---- App2 ----
+
if (mIsEntry) {
- mStartTransaction
- .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1)
- .setRelativeLayer(
- openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1);
+ if (!closingSurfaces.isEmpty()) {
+ tmpTransaction
+ .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1);
+ } else {
+ logW("Missing closing surface is entry transition");
+ }
+ if (!openingSurfaces.isEmpty()) {
+ tmpTransaction
+ .setRelativeLayer(
+ openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1);
+ } else {
+ logW("Missing opening surface is entry transition");
+ }
+
} else {
- mStartTransaction
- .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1)
- .setRelativeLayer(
- closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1);
+ if (!openingSurfaces.isEmpty()) {
+ tmpTransaction
+ .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1);
+ } else {
+ logW("Missing opening surface is exit transition");
+ }
+ if (!closingSurfaces.isEmpty()) {
+ tmpTransaction.setRelativeLayer(
+ closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1);
+ } else {
+ logW("Missing closing surface is exit transition");
+ }
}
+ mStartTransaction.merge(tmpTransaction);
// Attach origin UIComponent to origin leash.
mOriginTransaction = mOrigin.newTransaction();
@@ -300,6 +328,7 @@
}
private void cancel() {
+ logD("cancel()");
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -311,6 +340,10 @@
}
}
+ private static void logW(String msg) {
+ Log.w(TAG, msg);
+ }
+
private static void logE(String msg) {
Log.e(TAG, msg);
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 5dbedc7..bf3360f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -931,7 +931,9 @@
Modifier.requiredSize(dpSize)
.thenIf(!isItemDragging) {
Modifier.animateItem(
- placementSpec = spring(stiffness = Spring.StiffnessMediumLow)
+ placementSpec = spring(stiffness = Spring.StiffnessMediumLow),
+ // See b/376495198 - not supported with AndroidView
+ fadeOutSpec = null,
)
}
.thenIf(isItemDragging) { Modifier.zIndex(1f) },
@@ -980,11 +982,14 @@
size = size,
selected = false,
modifier =
- Modifier.requiredSize(dpSize).animateItem().thenIf(
- communalResponsiveGrid()
- ) {
- Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f }
- },
+ Modifier.requiredSize(dpSize)
+ .animateItem(
+ // See b/376495198 - not supported with AndroidView
+ fadeOutSpec = null
+ )
+ .thenIf(communalResponsiveGrid()) {
+ Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f }
+ },
index = index,
contentListState = contentListState,
interactionHandler = interactionHandler,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
index 2af5ffa..5790c4a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
@@ -19,6 +19,7 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.layoutId
import com.android.compose.animation.scene.ContentScope
@@ -84,7 +85,11 @@
viewModel.notificationsPlaceholderViewModelFactory.create()
}
- OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) {
+ OverlayShade(
+ panelAlignment = Alignment.TopStart,
+ modifier = modifier,
+ onScrimClicked = viewModel::onScrimClicked,
+ ) {
Column {
if (viewModel.showHeader) {
val burnIn = rememberBurnIn(clockInteractor)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index b1a1945..f6c5f58 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -99,7 +99,11 @@
val viewModel =
rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() }
- OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) {
+ OverlayShade(
+ panelAlignment = Alignment.TopEnd,
+ modifier = modifier,
+ onScrimClicked = viewModel::onScrimClicked,
+ ) {
Column {
ExpandedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index f821e42..cfbe667 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -55,16 +55,17 @@
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.effect.rememberOffsetOverscrollEffect
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.res.R
/** Renders a lightweight shade UI container, as an overlay. */
@Composable
-fun SceneScope.OverlayShade(
+fun ContentScope.OverlayShade(
+ panelAlignment: Alignment,
onScrimClicked: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
@@ -87,7 +88,7 @@
) {
Scrim(onClicked = onScrimClicked)
- Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
+ Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = panelAlignment) {
Panel(
modifier =
Modifier.element(OverlayShade.Elements.Panel)
@@ -100,7 +101,7 @@
}
@Composable
-private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
+private fun ContentScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
Spacer(
modifier =
modifier
@@ -112,7 +113,7 @@
}
@Composable
-private fun SceneScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
+private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
Spacer(
modifier =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f48fd3c..6bdd86e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -241,7 +241,7 @@
shadeTestUtil.setSplitShade(true)
val horizontalPosition = checkNotNull(dimens).horizontalPosition
- assertIs<HorizontalPosition.FloatAtEnd>(horizontalPosition)
+ assertIs<HorizontalPosition.FloatAtStart>(horizontalPosition)
assertThat(horizontalPosition.width).isEqualTo(200)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
index b560c59..1ee8005 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
@@ -20,7 +20,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
@@ -31,7 +33,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.runner.RunWith
@@ -43,7 +44,7 @@
@RunWithLooper(setAsMainLooper = true)
class SystemUIBottomSheetDialogTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
private val configurationController = mock<ConfigurationController>()
private val config = mock<Configuration>()
private val delegate = mock<DialogDelegate<Dialog>>()
@@ -67,21 +68,17 @@
@Test
fun onStart_registersConfigCallback() {
- kosmos.testScope.runTest {
+ kosmos.runTest {
dialog.show()
- runCurrent()
-
verify(configurationController).addCallback(any())
}
}
@Test
fun onStop_unregisterConfigCallback() {
- kosmos.testScope.runTest {
+ kosmos.runTest {
dialog.show()
- runCurrent()
dialog.dismiss()
- runCurrent()
verify(configurationController).removeCallback(any())
}
@@ -89,14 +86,12 @@
@Test
fun onConfigurationChanged_calledInDelegate() {
- kosmos.testScope.runTest {
+ kosmos.runTest {
dialog.show()
- runCurrent()
val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
verify(configurationController).addCallback(capture(captor))
captor.value.onConfigChanged(config)
- runCurrent()
verify(delegate).onConfigurationChanged(any(), any())
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 9ae106c..014c0db 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -267,6 +267,7 @@
}
@Provides
+ @Nullable
@Singleton
static VirtualDeviceManager provideVirtualDeviceManager(Context context) {
return context.getSystemService(VirtualDeviceManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
index 42acd7bc..705845f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
@@ -75,7 +75,7 @@
constraintSet.apply {
if (SceneContainerFlag.isEnabled) {
when (horizontalPosition) {
- is HorizontalPosition.FloatAtEnd ->
+ is HorizontalPosition.FloatAtStart ->
constrainWidth(nsslId, horizontalPosition.width)
is HorizontalPosition.MiddleToEdge ->
setGuidelinePercent(R.id.nssl_guideline, horizontalPosition.ratio)
@@ -83,13 +83,13 @@
}
}
+ connect(nsslId, START, startConstraintId, START, marginStart)
if (
!SceneContainerFlag.isEnabled ||
- horizontalPosition !is HorizontalPosition.FloatAtEnd
+ horizontalPosition !is HorizontalPosition.FloatAtStart
) {
- connect(nsslId, START, startConstraintId, START, marginStart)
+ connect(nsslId, END, PARENT_ID, END, marginEnd)
}
- connect(nsslId, END, PARENT_ID, END, marginEnd)
connect(nsslId, BOTTOM, PARENT_ID, BOTTOM, marginBottom)
connect(nsslId, TOP, PARENT_ID, TOP, marginTop)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b81c71e..fc8c70f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -247,7 +247,7 @@
Split -> HorizontalPosition.MiddleToEdge(ratio = 0.5f)
Dual ->
if (isShadeLayoutWide) {
- HorizontalPosition.FloatAtEnd(
+ HorizontalPosition.FloatAtStart(
width = getDimensionPixelSize(R.dimen.shade_panel_width)
)
} else {
@@ -830,10 +830,10 @@
data class MiddleToEdge(val ratio: Float = 0.5f) : HorizontalPosition
/**
- * The container has a fixed [width] and is aligned to the end of the screen. In this
- * layout, the start edge of the container is floating, i.e. unconstrained.
+ * The container has a fixed [width] and is aligned to the start of the screen. In this
+ * layout, the end edge of the container is floating, i.e. unconstrained.
*/
- data class FloatAtEnd(val width: Int) : HorizontalPosition
+ data class FloatAtStart(val width: Int) : HorizontalPosition
}
/**
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
index a357275..f31697e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
@@ -70,6 +70,14 @@
}
}
+ fun getContentObservers(uri: Uri, userHandle: Int): List<ContentObserver> {
+ if (userHandle == UserHandle.USER_ALL) {
+ return contentObserversAllUsers[uri.toString()] ?: listOf()
+ } else {
+ return contentObservers[SettingsKey(userHandle, uri.toString())] ?: listOf()
+ }
+ }
+
override fun getContentResolver(): ContentResolver {
throw UnsupportedOperationException("FakeSettings.getContentResolver is not implemented")
}
diff --git a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
index 2818379..860d9f6 100644
--- a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
+++ b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
@@ -16,10 +16,17 @@
package com.android.test.input
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+
import android.view.KeyCharacterMap
import android.view.KeyEvent
+import com.android.hardware.input.Flags
+
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Rule
import org.junit.Test
/**
@@ -30,26 +37,38 @@
*
*/
class KeyCharacterMapTest {
+ @get:Rule
+ val setFlagsRule = SetFlagsRule()
+
@Test
+ @EnableFlags(Flags.FLAG_REMOVE_FALLBACK_MODIFIERS)
fun testGetFallback() {
// Based off of VIRTUAL kcm fallbacks.
val keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD)
// One modifier fallback.
- assertEquals(
- keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
- KeyEvent.META_CTRL_ON).keyCode,
- KeyEvent.KEYCODE_LANGUAGE_SWITCH)
+ val oneModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_CTRL_ON)
+ assertEquals(KeyEvent.KEYCODE_LANGUAGE_SWITCH, oneModifierFallback.keyCode)
+ assertEquals(0, oneModifierFallback.metaState)
// Multiple modifier fallback.
- assertEquals(
- keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
- KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON).keyCode,
- KeyEvent.KEYCODE_BACK)
+ val twoModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
+ KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
+ assertEquals(KeyEvent.KEYCODE_BACK, twoModifierFallback.keyCode)
+ assertEquals(0, twoModifierFallback.metaState)
// No default button, fallback only.
- assertEquals(
- keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0).keyCode,
- KeyEvent.KEYCODE_DPAD_CENTER)
+ val keyOnlyFallback =
+ keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0)
+ assertEquals(KeyEvent.KEYCODE_DPAD_CENTER, keyOnlyFallback.keyCode)
+ assertEquals(0, keyOnlyFallback.metaState)
+
+ // A key event that is not an exact match for a fallback. Expect a null return.
+ // E.g. Ctrl + Space -> LanguageSwitch
+ // Ctrl + Alt + Space -> Ctrl + Alt + Space (No fallback).
+ val noMatchFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
+ assertNull(noMatchFallback)
}
}