Merge "Fix default logo is wrong for some apps." into main
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0caea7f..9c80659 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7155,13 +7155,7 @@
// Adds any new extras provided by the user.
if (mUserExtras != null) {
final Bundle saveExtras = (Bundle) mUserExtras.clone();
- if (SystemProperties.getBoolean(
- "persist.sysui.notification.builder_extras_override", false)) {
- mN.extras.putAll(saveExtras);
- } else {
- saveExtras.putAll(mN.extras);
- mN.extras = saveExtras;
- }
+ mN.extras.putAll(saveExtras);
}
if (!Flags.sortSectionByTime()) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cefc648..1ef5c3f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4444,8 +4444,8 @@
<!-- True if camera app should be pinned via Pinner Service -->
<bool name="config_pinnerCameraApp">false</bool>
- <!-- True if home app should be pinned via Pinner Service -->
- <bool name="config_pinnerHomeApp">false</bool>
+ <!-- Bytes that the PinnerService will pin for Home app -->
+ <integer name="config_pinnerHomePinBytes">0</integer>
<!-- True if assistant app should be pinned via Pinner Service -->
<bool name="config_pinnerAssistantApp">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d058fb1..ec63ea3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3437,7 +3437,7 @@
<!-- Pinner Service -->
<java-symbol type="array" name="config_defaultPinnerServiceFiles" />
<java-symbol type="bool" name="config_pinnerCameraApp" />
- <java-symbol type="bool" name="config_pinnerHomeApp" />
+ <java-symbol type="integer" name="config_pinnerHomePinBytes" />
<java-symbol type="bool" name="config_pinnerAssistantApp" />
<java-symbol type="integer" name="config_pinnerWebviewPinBytes" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 7fb894a..30ec940 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -84,7 +84,6 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemProperties;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.text.Spannable;
@@ -132,9 +131,6 @@
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
- // TODO(b/169435530): remove this flag set once resolved.
- SystemProperties.set("persist.sysui.notification.builder_extras_override",
- Boolean.toString(false));
}
@Test
@@ -1703,10 +1699,6 @@
// Ensures that extras in a Notification Builder can be updated.
@Test
public void testExtras_cachedExtrasOverwrittenByUserProvided() {
- // Sets the flag to new state.
- // TODO(b/169435530): remove this set value once resolved.
- SystemProperties.set("persist.sysui.notification.builder_extras_override",
- Boolean.toString(true));
Bundle extras = new Bundle();
extras.putCharSequence(EXTRA_TITLE, "test title");
extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text");
@@ -1732,10 +1724,6 @@
// Ensures that extras in a Notification Builder can be updated by an extender.
@Test
public void testExtras_cachedExtrasOverwrittenByExtender() {
- // Sets the flag to new state.
- // TODO(b/169435530): remove this set value once resolved.
- SystemProperties.set("persist.sysui.notification.builder_extras_override",
- Boolean.toString(true));
Notification.CarExtender extender = new Notification.CarExtender().setColor(1234);
Notification notification = new Notification.Builder(mContext, "test id")
@@ -1749,58 +1737,6 @@
assertThat(recoveredExtender.getColor()).isEqualTo(5678);
}
- // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated.
- // TODO(b/169435530): remove this test once resolved.
- @Test
- public void testExtras_cachedExtrasOverwrittenByUserProvidedOld() {
- // Sets the flag to old state.
- SystemProperties.set("persist.sysui.notification.builder_extras_override",
- Boolean.toString(false));
-
- Bundle extras = new Bundle();
- extras.putCharSequence(EXTRA_TITLE, "test title");
- extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text");
-
- Notification.Builder builder = new Notification.Builder(mContext, "test id")
- .addExtras(extras);
-
- Notification notification = builder.build();
- assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
- "test title");
- assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
- "summary text");
-
- extras.putCharSequence(EXTRA_TITLE, "new title");
- builder.addExtras(extras);
- notification = builder.build();
- assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
- "test title");
- assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
- "summary text");
- }
-
- // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated
- // by an extender.
- // TODO(b/169435530): remove this test once resolved.
- @Test
- public void testExtras_cachedExtrasOverwrittenByExtenderOld() {
- // Sets the flag to old state.
- SystemProperties.set("persist.sysui.notification.builder_extras_override",
- Boolean.toString(false));
-
- Notification.CarExtender extender = new Notification.CarExtender().setColor(1234);
-
- Notification notification = new Notification.Builder(mContext, "test id")
- .extend(extender).build();
-
- extender.setColor(5678);
-
- Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build();
-
- Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification);
- assertThat(recoveredExtender.getColor()).isEqualTo(1234);
- }
-
@Test
@CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() {
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index cc5b3b9..635e78e 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -40,7 +40,7 @@
/** @hide */
private static int getPanelFrameSize() {
- final int DefaultSize = 150 * 1024 * 1024; // 150 MB;
+ final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
DefaultSize);
}
@@ -262,7 +262,7 @@
protected void throwIfCannotDraw(Bitmap bitmap) {
super.throwIfCannotDraw(bitmap);
int bitmapSize = bitmap.getByteCount();
- if (bitmap.getConfig() != Bitmap.Config.HARDWARE && bitmapSize > MAX_BITMAP_SIZE) {
+ if (bitmapSize > MAX_BITMAP_SIZE) {
throw new RuntimeException(
"Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 6e61f22..414a9d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -132,6 +132,7 @@
PhonePipMenuController menuPhoneController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
+ @NonNull PipTransitionState pipTransitionState,
@NonNull SizeSpecSource sizeSpecSource,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -139,8 +140,9 @@
@ShellMainThread ShellExecutor mainExecutor,
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
- pipBoundsState, sizeSpecSource, pipMotionHelper, floatingContentCoordinator,
- pipUiEventLogger, mainExecutor, pipPerfHintControllerOptional);
+ pipBoundsState, pipTransitionState, sizeSpecSource, pipMotionHelper,
+ floatingContentCoordinator, pipUiEventLogger, mainExecutor,
+ pipPerfHintControllerOptional);
}
@WMSingleton
@@ -149,9 +151,13 @@
PipBoundsState pipBoundsState, PhonePipMenuController menuController,
PipSnapAlgorithm pipSnapAlgorithm,
FloatingContentCoordinator floatingContentCoordinator,
- Optional<PipPerfHintController> pipPerfHintControllerOptional) {
+ PipScheduler pipScheduler,
+ Optional<PipPerfHintController> pipPerfHintControllerOptional,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipTransitionState pipTransitionState) {
return new PipMotionHelper(context, pipBoundsState, menuController, pipSnapAlgorithm,
- floatingContentCoordinator, pipPerfHintControllerOptional);
+ floatingContentCoordinator, pipScheduler, pipPerfHintControllerOptional,
+ pipBoundsAlgorithm, pipTransitionState);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
index 03547a5..b757b00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
@@ -53,7 +53,7 @@
* Listener interface for callers to learn when this class is registered or unregistered with
* window manager
*/
- private interface RegistrationListener {
+ interface RegistrationListener {
void onRegistrationChanged(boolean isRegistered);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 619bed4..a097a0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -31,7 +31,9 @@
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Debug;
+import android.view.SurfaceControl;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
@@ -39,6 +41,7 @@
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipPerfHintController;
import com.android.wm.shell.common.pip.PipSnapAlgorithm;
@@ -57,6 +60,7 @@
public class PipMotionHelper implements PipAppOpsListener.Callback,
FloatingContentCoordinator.FloatingContent {
private static final String TAG = "PipMotionHelper";
+ private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change";
private static final boolean DEBUG = false;
private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
@@ -72,7 +76,9 @@
private final Context mContext;
private @NonNull PipBoundsState mPipBoundsState;
-
+ private @NonNull PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private @NonNull PipScheduler mPipScheduler;
+ private @NonNull PipTransitionState mPipTransitionState;
private PhonePipMenuController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
@@ -145,6 +151,11 @@
private boolean mDismissalPending = false;
/**
+ * Set to true if bounds change transition has been scheduled from PipMotionHelper.
+ */
+ private boolean mWaitingForBoundsChangeTransition = false;
+
+ /**
* Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is
* used to show menu activity when the expand animation is completed.
*/
@@ -152,22 +163,25 @@
public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
PhonePipMenuController menuController, PipSnapAlgorithm snapAlgorithm,
- FloatingContentCoordinator floatingContentCoordinator,
- Optional<PipPerfHintController> pipPerfHintControllerOptional) {
+ FloatingContentCoordinator floatingContentCoordinator, PipScheduler pipScheduler,
+ Optional<PipPerfHintController> pipPerfHintControllerOptional,
+ PipBoundsAlgorithm pipBoundsAlgorithm, PipTransitionState pipTransitionState) {
mContext = context;
mPipBoundsState = pipBoundsState;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipScheduler = pipScheduler;
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
mPipPerfHintController = pipPerfHintControllerOptional.orElse(null);
mResizePipUpdateListener = (target, values) -> {
if (mPipBoundsState.getMotionBoundsState().isInMotion()) {
- /*
- mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
- mPipBoundsState.getMotionBoundsState().getBoundsInMotion(), null);
- */
+ mPipScheduler.scheduleUserResizePip(
+ mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
}
};
+ mPipTransitionState = pipTransitionState;
+ mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged);
}
void init() {
@@ -236,12 +250,7 @@
mPipBoundsState.setBounds(toBounds);
} else {
mPipBoundsState.getMotionBoundsState().setBoundsInMotion(toBounds);
- /*
- mPipTaskOrganizer.scheduleUserResizePip(getBounds(), toBounds,
- (Rect newBounds) -> {
- mMenuController.updateMenuLayout(newBounds);
- });
- */
+ mPipScheduler.scheduleUserResizePip(toBounds);
}
} else {
// If PIP is 'catching up' after being stuck in the dismiss target, update the animation
@@ -552,11 +561,11 @@
/** Set new fling configs whose min/max values respect the given movement bounds. */
private void rebuildFlingConfigs() {
mFlingConfigX = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION,
- mPipBoundsState.getMovementBounds().left,
- mPipBoundsState.getMovementBounds().right);
+ mPipBoundsAlgorithm.getMovementBounds(getBounds()).left,
+ mPipBoundsAlgorithm.getMovementBounds(getBounds()).right);
mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION,
- mPipBoundsState.getMovementBounds().top,
- mPipBoundsState.getMovementBounds().bottom);
+ mPipBoundsAlgorithm.getMovementBounds(getBounds()).top,
+ mPipBoundsAlgorithm.getMovementBounds(getBounds()).bottom);
final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets();
mStashConfigX = new PhysicsAnimator.FlingConfig(
DEFAULT_FRICTION,
@@ -623,22 +632,15 @@
private void onBoundsPhysicsAnimationEnd() {
// The physics animation ended, though we may not necessarily be done animating, such as
// when we're still dragging after moving out of the magnetic target.
- if (!mDismissalPending
- && !mSpringingToTouch
- && !mMagnetizedPip.getObjectStuckToTarget()) {
- // All motion operations have actually finished.
- mPipBoundsState.setBounds(
- mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
- mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded();
- if (!mDismissalPending) {
- // do not schedule resize if PiP is dismissing, which may cause app re-open to
- // mBounds instead of its normal bounds.
- // mPipTaskOrganizer.scheduleFinishResizePip(getBounds());
- }
+ if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) {
+ // do not schedule resize if PiP is dismissing, which may cause app re-open to
+ // mBounds instead of its normal bounds.
+ Bundle extra = new Bundle();
+ extra.putBoolean(FLING_BOUNDS_CHANGE, true);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
+ return;
}
- mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded();
- mSpringingToTouch = false;
- mDismissalPending = false;
+ settlePipBoundsAfterPhysicsAnimation(true /* animatingAfter */);
cleanUpHighPerfSessionMaybe();
}
@@ -662,7 +664,7 @@
+ " callers=\n%s", TAG, toBounds, Debug.getCallers(5, " "));
}
if (!toBounds.equals(getBounds())) {
- // mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
+ mPipScheduler.scheduleAnimateResizePip(toBounds);
}
}
@@ -685,6 +687,60 @@
// setAnimatingToBounds(toBounds);
}
+ private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @PipTransitionState.TransitionState int newState,
+ @Nullable Bundle extra) {
+ switch (newState) {
+ case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
+ if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break;
+
+ // If touch is turned off and we are in a fling animation, schedule a transition.
+ mWaitingForBoundsChangeTransition = true;
+ mPipScheduler.scheduleAnimateResizePip(
+ mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+ break;
+ case PipTransitionState.CHANGING_PIP_BOUNDS:
+ if (!mWaitingForBoundsChangeTransition) break;
+
+ // If bounds change transition was scheduled from this class, handle leash updates.
+ mWaitingForBoundsChangeTransition = false;
+ SurfaceControl.Transaction startTx = extra.getParcelable(
+ PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
+ Rect destinationBounds = extra.getParcelable(
+ PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
+ startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
+ destinationBounds.left, destinationBounds.top);
+ startTx.apply();
+
+ // All motion operations have actually finished, so make bounds cache updates.
+ settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
+ cleanUpHighPerfSessionMaybe();
+
+ // Setting state to CHANGED_PIP_BOUNDS applies finishTx and notifies Core.
+ mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS);
+ break;
+ case PipTransitionState.EXITING_PIP:
+ // We need to force finish any local animators if about to leave PiP, to avoid
+ // breaking the state (e.g. leashes are cleaned up upon exit).
+ if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break;
+ cancelPhysicsAnimation();
+ settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
+ }
+ }
+
+ private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) {
+ if (!animatingAfter) {
+ // The physics animation ended, though we may not necessarily be done animating, such as
+ // when we're still dragging after moving out of the magnetic target. Only set the final
+ // bounds state and clear motion bounds completely if the whole animation is over.
+ mPipBoundsState.setBounds(mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+ mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded();
+ }
+ mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded();
+ mSpringingToTouch = false;
+ mDismissalPending = false;
+ }
+
/**
* Returns a MagnetizedObject wrapper for PIP's animated bounds. This is provided to the
* magnetic dismiss target so it can calculate PIP's size and position.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 72fa3ba..c5b0de3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -25,16 +25,19 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -156,4 +159,20 @@
wct.setBounds(mPipTransitionState.mPipTaskToken, toBounds);
mPipTransitionController.startResizeTransition(wct);
}
+
+ /**
+ * Directly perform a scaled matrix transformation on the leash. This will not perform any
+ * {@link WindowContainerTransaction}.
+ */
+ public void scheduleUserResizePip(Rect toBounds) {
+ if (toBounds.isEmpty()) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG);
+ return;
+ }
+ SurfaceControl leash = mPipTransitionState.mPinnedTaskLeash;
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setPosition(leash, toBounds.left, toBounds.top);
+ tx.apply();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 472003c..9c6e3ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.pip2.phone;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASH_MINIMUM_VELOCITY_THRESHOLD;
import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_LEFT;
@@ -30,18 +32,19 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Bundle;
import android.provider.DeviceConfig;
import android.util.Size;
import android.view.DisplayCutout;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -80,6 +83,7 @@
private final Context mContext;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@NonNull private final PipBoundsState mPipBoundsState;
+ @NonNull private final PipTransitionState mPipTransitionState;
@NonNull private final SizeSpecSource mSizeSpecSource;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
@@ -125,6 +129,7 @@
private final FloatingContentCoordinator mFloatingContentCoordinator;
private PipMotionHelper mMotionHelper;
private PipTouchGesture mGesture;
+ private PipInputConsumer mPipInputConsumer;
// Temp vars
private final Rect mTmpBounds = new Rect();
@@ -167,6 +172,7 @@
PhonePipMenuController menuController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
+ @NonNull PipTransitionState pipTransitionState,
@NonNull SizeSpecSource sizeSpecSource,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -179,6 +185,9 @@
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
+
+ mPipTransitionState = pipTransitionState;
+ mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged);
mSizeSpecSource = sizeSpecSource;
mMenuController = menuController;
mPipUiEventLogger = pipUiEventLogger;
@@ -227,6 +236,11 @@
mPipResizeGestureHandler.init();
mPipDismissTargetHandler.init();
+ mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
+ INPUT_CONSUMER_PIP, mMainExecutor);
+ mPipInputConsumer.setInputListener(this::handleTouchEvent);
+ mPipInputConsumer.setRegistrationListener(this::onRegistrationChanged);
+
mEnableStash = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
PIP_STASHING,
@@ -294,19 +308,17 @@
void onActivityPinned() {
mPipDismissTargetHandler.createOrUpdateDismissTarget();
-
mPipResizeGestureHandler.onActivityPinned();
mFloatingContentCoordinator.onContentAdded(mMotionHelper);
+ mPipInputConsumer.registerInputConsumer();
}
- void onActivityUnpinned(ComponentName topPipActivity) {
- if (topPipActivity == null) {
- // Clean up state after the last PiP activity is removed
- mPipDismissTargetHandler.cleanUpDismissTarget();
-
- mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
- }
+ void onActivityUnpinned() {
+ // Clean up state after the last PiP activity is removed
+ mPipDismissTargetHandler.cleanUpDismissTarget();
+ mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
mPipResizeGestureHandler.onActivityUnpinned();
+ mPipInputConsumer.unregisterInputConsumer();
}
void onPinnedStackAnimationEnded(
@@ -512,6 +524,7 @@
return true;
}
+ /*
if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting())
&& mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) {
// If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
@@ -528,11 +541,13 @@
return true;
}
- if (!mTouchState.isUserInteracting()) {
+ // Ignore the motion event When the entry animation is waiting to be started
+ if (!mTouchState.isUserInteracting() && mPipTaskOrganizer.isEntryScheduled()) {
ProtoLog.wtf(WM_SHELL_PICTURE_IN_PICTURE,
"%s: Waiting to start the entry animation, skip the motion event.", TAG);
return true;
}
+ */
// Update the touch state
mTouchState.onTouchEvent(ev);
@@ -808,7 +823,7 @@
mMovementWithinDismiss = touchState.getDownTouchPosition().y
>= mPipBoundsState.getMovementBounds().bottom;
mMotionHelper.setSpringingToTouch(false);
- // mPipDismissTargetHandler.setTaskLeash(mPipTaskOrganizer.getSurfaceControl());
+ mPipDismissTargetHandler.setTaskLeash(mPipTransitionState.mPinnedTaskLeash);
// If the menu is still visible then just poke the menu
// so that it will timeout after the user stops touching it
@@ -880,7 +895,8 @@
// Reset the touch state on up before the fling settles
mTouchState.reset();
if (mEnableStash && shouldStash(vel, getPossiblyMotionBounds())) {
- mMotionHelper.stashToEdge(vel.x, vel.y, this::stashEndAction /* endAction */);
+ // mMotionHelper.stashToEdge(vel.x, vel.y,
+ // this::stashEndAction /* endAction */);
} else {
if (mPipBoundsState.isStashed()) {
// Reset stashed state if previously stashed
@@ -1059,6 +1075,27 @@
mPipResizeGestureHandler.setOhmOffset(offset);
}
+ private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
+ @PipTransitionState.TransitionState int newState,
+ @Nullable Bundle extra) {
+ switch (newState) {
+ case PipTransitionState.ENTERED_PIP:
+ onActivityPinned();
+ mTouchState.setAllowInputEvents(true);
+ break;
+ case PipTransitionState.EXITED_PIP:
+ mTouchState.setAllowInputEvents(false);
+ onActivityUnpinned();
+ break;
+ case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
+ mTouchState.setAllowInputEvents(false);
+ break;
+ case PipTransitionState.CHANGED_PIP_BOUNDS:
+ mTouchState.setAllowInputEvents(true);
+ break;
+ }
+ }
+
/**
* Dumps the {@link PipTouchHandler} state.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 8b2d0dd..7dddd27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -61,11 +61,15 @@
public class PipTransition extends PipTransitionController implements
PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = PipTransition.class.getSimpleName();
+
+ // Used when for ENTERING_PIP state update.
private static final String PIP_TASK_TOKEN = "pip_task_token";
private static final String PIP_TASK_LEASH = "pip_task_leash";
- private static final String PIP_START_TX = "pip_start_tx";
- private static final String PIP_FINISH_TX = "pip_finish_tx";
- private static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds";
+
+ // Used for PiP CHANGING_BOUNDS state update.
+ static final String PIP_START_TX = "pip_start_tx";
+ static final String PIP_FINISH_TX = "pip_finish_tx";
+ static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds";
/**
* The fixed start delay in ms when fading out the content overlay from bounds animation.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 9a9c59e2..8204d41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -71,17 +71,21 @@
// State for app finishing drawing in PiP mode as a final step in enter PiP flow.
public static final int ENTERED_PIP = 3;
- // State for scheduling a transition to change PiP bounds.
- public static final int CHANGING_PIP_BOUNDS = 4;
+ // State to indicate we have scheduled a PiP bounds change transition.
+ public static final int SCHEDULED_BOUNDS_CHANGE = 4;
- // State for app potentially finishing drawing in new PiP bounds after resize is complete.
- public static final int CHANGED_PIP_BOUNDS = 5;
+ // State for the start of playing a transition to change PiP bounds. At this point, WM Core
+ // is aware of the new PiP bounds, but Shell might still be continuing animating.
+ public static final int CHANGING_PIP_BOUNDS = 5;
+
+ // State for finishing animating into new PiP bounds after resize is complete.
+ public static final int CHANGED_PIP_BOUNDS = 6;
// State for starting exiting PiP.
- public static final int EXITING_PIP = 6;
+ public static final int EXITING_PIP = 7;
// State for finishing exit PiP flow.
- public static final int EXITED_PIP = 7;
+ public static final int EXITED_PIP = 8;
private static final int FIRST_CUSTOM_STATE = 1000;
@@ -92,6 +96,7 @@
SWIPING_TO_PIP,
ENTERING_PIP,
ENTERED_PIP,
+ SCHEDULED_BOUNDS_CHANGE,
CHANGING_PIP_BOUNDS,
CHANGED_PIP_BOUNDS,
EXITING_PIP,
@@ -165,10 +170,11 @@
* @param extra a bundle passed to the subscribed listeners to resolve/cache extra info.
*/
public void setState(@TransitionState int state, @Nullable Bundle extra) {
- if (state == ENTERING_PIP || state == SWIPING_TO_PIP) {
- // Whenever we are entering PiP caller must provide extra state to set as well.
+ if (state == ENTERING_PIP || state == SWIPING_TO_PIP
+ || state == SCHEDULED_BOUNDS_CHANGE || state == CHANGING_PIP_BOUNDS) {
+ // States listed above require extra bundles to be provided.
Preconditions.checkArgument(extra != null && !extra.isEmpty(),
- "No extra bundle for either ENTERING_PIP or SWIPING_TO_PIP state.");
+ "No extra bundle for " + stateToString(state) + " state.");
}
if (mState != state) {
dispatchPipTransitionStateChanged(mState, state, extra);
@@ -254,23 +260,24 @@
return ++mPrevCustomState;
}
- private String stateToString() {
- switch (mState) {
+ private static String stateToString(int state) {
+ switch (state) {
case UNDEFINED: return "undefined";
case SWIPING_TO_PIP: return "swiping_to_pip";
case ENTERING_PIP: return "entering-pip";
case ENTERED_PIP: return "entered-pip";
+ case SCHEDULED_BOUNDS_CHANGE: return "scheduled_bounds_change";
case CHANGING_PIP_BOUNDS: return "changing-bounds";
case CHANGED_PIP_BOUNDS: return "changed-bounds";
case EXITING_PIP: return "exiting-pip";
case EXITED_PIP: return "exited-pip";
}
- throw new IllegalStateException("Unknown state: " + mState);
+ throw new IllegalStateException("Unknown state: " + state);
}
@Override
public String toString() {
return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)",
- stateToString(), mInSwipePipToHomeTransition);
+ stateToString(mState), mInSwipePipToHomeTransition);
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index adbfc72..4ea7460 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1712,7 +1712,7 @@
<string name="keyboard_layout_default_label">Default</string>
<!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
- <string name="turn_screen_on_title">Turn screen on</string>
+ <string name="turn_screen_on_title">Screen turn-on control</string>
<!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
<string name="allow_turn_screen_on">Allow turning the screen on</string>
<!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index c109e51..abbf0ea 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -58,15 +58,11 @@
.collectAsState(initial = BurnInScaleViewModel())
return this.graphicsLayer {
- val scale =
- when {
- scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale
- else -> 1f
- }
-
this.translationX = if (isClock) 0F else translationX
this.translationY = translationY
this.alpha = alpha
+
+ val scale = if (scaleViewModel.scaleClockOnly) scaleViewModel.scale else 1f
this.scaleX = scale
this.scaleY = scale
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 7c8cc194..01d62a3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -68,12 +68,14 @@
import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.height
+import com.android.compose.modifiers.thenIf
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
import com.android.systemui.res.R
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.session.ui.composable.rememberSession
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.composable.ShadeHeader
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
@@ -165,6 +167,7 @@
viewModel: NotificationsPlaceholderViewModel,
maxScrimTop: () -> Float,
shouldPunchHoleBehindScrim: Boolean,
+ shadeMode: ShadeMode,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
@@ -242,6 +245,27 @@
}
}
+ val scrimNestedScrollConnection =
+ shadeSession.rememberSession(
+ scrimOffset,
+ maxScrimTop,
+ minScrimTop,
+ isCurrentGestureOverscroll,
+ ) {
+ NotificationScrimNestedScrollConnection(
+ scrimOffset = { scrimOffset.value },
+ snapScrimOffset = { value -> coroutineScope.launch { scrimOffset.snapTo(value) } },
+ animateScrimOffset = { value ->
+ coroutineScope.launch { scrimOffset.animateTo(value) }
+ },
+ minScrimOffset = minScrimOffset,
+ maxScrimOffset = 0f,
+ contentHeight = { stackHeight.intValue.toFloat() },
+ minVisibleScrimHeight = minVisibleScrimHeight,
+ isCurrentGestureOverscroll = { isCurrentGestureOverscroll.value },
+ )
+ }
+
Box(
modifier =
modifier
@@ -316,31 +340,9 @@
topBehavior = NestedScrollBehavior.EdgeWithPreview,
isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }
)
- .nestedScroll(
- shadeSession.rememberSession(
- scrimOffset,
- maxScrimTop,
- minScrimTop,
- isCurrentGestureOverscroll,
- ) {
- NotificationScrimNestedScrollConnection(
- scrimOffset = { scrimOffset.value },
- snapScrimOffset = { value ->
- coroutineScope.launch { scrimOffset.snapTo(value) }
- },
- animateScrimOffset = { value ->
- coroutineScope.launch { scrimOffset.animateTo(value) }
- },
- minScrimOffset = minScrimOffset,
- maxScrimOffset = 0f,
- contentHeight = { stackHeight.intValue.toFloat() },
- minVisibleScrimHeight = minVisibleScrimHeight,
- isCurrentGestureOverscroll = {
- isCurrentGestureOverscroll.value
- },
- )
- }
- )
+ .thenIf(shadeMode == ShadeMode.Single) {
+ Modifier.nestedScroll(scrimNestedScrollConnection)
+ }
.verticalScroll(scrollState)
.fillMaxWidth()
.notificationStackHeight(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 61ce83a..6ae0efa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -86,6 +86,7 @@
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
import com.android.systemui.shade.ui.composable.Shade
@@ -370,6 +371,7 @@
shadeSession = shadeSession,
maxScrimTop = { screenHeight },
shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
+ shadeMode = ShadeMode.Single,
modifier =
Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index ff9c5a5..cbaa894 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -5,9 +5,8 @@
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
-import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.goneToShadeTransition
@@ -17,6 +16,7 @@
import com.android.systemui.scene.ui.composable.transitions.lockscreenToGoneTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.lockscreenToSplitShadeTransition
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
import com.android.systemui.shade.ui.composable.Shade
@@ -41,7 +41,7 @@
from(
Scenes.Gone,
to = Scenes.Shade,
- key = GoneToSplitShade,
+ key = ToSplitShade,
) {
goneToSplitShadeTransition()
}
@@ -59,6 +59,13 @@
from(
Scenes.Lockscreen,
to = Scenes.Shade,
+ key = ToSplitShade,
+ ) {
+ lockscreenToSplitShadeTransition()
+ }
+ from(
+ Scenes.Lockscreen,
+ to = Scenes.Shade,
key = SlightlyFasterShadeCollapse,
) {
lockscreenToShadeTransition(durationScale = 0.9)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index 4dc36d6..f14ff76 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -16,50 +16,10 @@
package com.android.systemui.scene.ui.composable.transitions
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.TransitionBuilder
-import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
-import com.android.systemui.notifications.ui.composable.Notifications
-import com.android.systemui.qs.ui.composable.QuickSettings
-import com.android.systemui.shade.ui.composable.Shade
-import com.android.systemui.shade.ui.composable.ShadeHeader
-import kotlin.time.Duration.Companion.milliseconds
fun TransitionBuilder.goneToSplitShadeTransition(
durationScale: Double = 1.0,
) {
- spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
- swipeSpec =
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
- )
- distance =
- object : UserActionDistance {
- override fun UserActionDistanceScope.absoluteDistance(
- fromSceneSize: IntSize,
- orientation: Orientation,
- ): Float {
- return fromSceneSize.height.toFloat() * 2 / 3f
- }
- }
-
- fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
-
- fractionRange(start = .33f) {
- fade(ShadeHeader.Elements.Clock)
- fade(ShadeHeader.Elements.CollapsedContentStart)
- fade(ShadeHeader.Elements.CollapsedContentEnd)
- fade(ShadeHeader.Elements.PrivacyChip)
- fade(QuickSettings.Elements.SplitShadeQuickSettings)
- fade(QuickSettings.Elements.FooterActions)
- fade(Notifications.Elements.NotificationScrim)
- }
+ toSplitShadeTransition(durationScale)
}
-
-private val DefaultDuration = 500.milliseconds
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
new file mode 100644
index 0000000..70c343c
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.composable.transitions
+
+import com.android.compose.animation.scene.TransitionBuilder
+
+fun TransitionBuilder.lockscreenToSplitShadeTransition(
+ durationScale: Double = 1.0,
+) {
+ toSplitShadeTransition(durationScale = durationScale)
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt
new file mode 100644
index 0000000..a8315c0
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.composable.transitions
+
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.unit.IntSize
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.UserActionDistance
+import com.android.compose.animation.scene.UserActionDistanceScope
+import com.android.systemui.notifications.ui.composable.Notifications
+import com.android.systemui.qs.ui.composable.QuickSettings
+import com.android.systemui.shade.ui.composable.Shade
+import com.android.systemui.shade.ui.composable.ShadeHeader
+import kotlin.time.Duration.Companion.milliseconds
+
+fun TransitionBuilder.toSplitShadeTransition(
+ durationScale: Double = 1.0,
+) {
+ spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
+ swipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
+ )
+ distance =
+ object : UserActionDistance {
+ override fun UserActionDistanceScope.absoluteDistance(
+ fromSceneSize: IntSize,
+ orientation: Orientation,
+ ): Float {
+ return fromSceneSize.height.toFloat() * 2 / 3f
+ }
+ }
+
+ fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
+
+ fractionRange(start = .33f) {
+ fade(ShadeHeader.Elements.Clock)
+ fade(ShadeHeader.Elements.CollapsedContentStart)
+ fade(ShadeHeader.Elements.CollapsedContentEnd)
+ fade(ShadeHeader.Elements.PrivacyChip)
+ fade(QuickSettings.Elements.SplitShadeQuickSettings)
+ fade(QuickSettings.Elements.FooterActions)
+ fade(Notifications.Elements.NotificationScrim)
+ }
+}
+
+private val DefaultDuration = 500.milliseconds
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 869f741..42e6fcc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -298,6 +298,7 @@
stackScrollView = notificationStackScrollView,
viewModel = viewModel.notifications,
maxScrimTop = { maxNotifScrimTop.value },
+ shadeMode = ShadeMode.Single,
shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
)
},
@@ -492,6 +493,7 @@
viewModel = viewModel.notifications,
maxScrimTop = { 0f },
shouldPunchHoleBehindScrim = false,
+ shadeMode = ShadeMode.Split,
modifier =
Modifier.weight(1f)
.fillMaxHeight()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index a3467f2..1def7fe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -20,6 +20,8 @@
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.expandVertically
@@ -28,10 +30,8 @@
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.shrinkVertically
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -39,6 +39,7 @@
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
@@ -49,15 +50,21 @@
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.PlatformSliderColors
+import com.android.compose.modifiers.padding
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
private const val EXPAND_DURATION_MILLIS = 500
+private const val COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS = 350
private const val COLLAPSE_DURATION_MILLIS = 300
+private const val EXPAND_BUTTON_ANIMATION_DURATION_MILLIS = 350
+private const val TOP_SLIDER_ANIMATION_DURATION_MILLIS = 400
private const val SHRINK_FRACTION = 0.55f
private const val SCALE_FRACTION = 0.9f
+private const val EXPAND_BUTTON_SCALE = 0.8f
/** Volume sliders laid out in a collapsable column */
@OptIn(ExperimentalAnimationApi::class)
@@ -73,14 +80,15 @@
require(viewModels.isNotEmpty())
val transition = updateTransition(isExpanded, label = "CollapsableSliders")
Column(modifier = modifier) {
- Row(
+ Box(
modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
val sliderViewModel: SliderViewModel = viewModels.first()
val sliderState by viewModels.first().slider.collectAsState()
+ val sliderPadding by topSliderPadding(isExpandable)
+
VolumeSlider(
- modifier = Modifier.weight(1f),
+ modifier = Modifier.padding(end = { sliderPadding.roundToPx() }).fillMaxWidth(),
state = sliderState,
onValueChange = { newValue: Float ->
sliderViewModel.onValueChanged(sliderState, newValue)
@@ -90,21 +98,13 @@
sliderColors = sliderColors,
)
- val expandButtonStateDescription =
- if (isExpanded) stringResource(R.string.volume_panel_expanded_sliders)
- else stringResource(R.string.volume_panel_collapsed_sliders)
- if (isExpandable) {
- ExpandButton(
- modifier =
- Modifier.semantics {
- role = Role.Switch
- stateDescription = expandButtonStateDescription
- },
- isExpanded = isExpanded,
- onExpandedChanged = onExpandedChanged,
- sliderColors = sliderColors,
- )
- }
+ ExpandButton(
+ modifier = Modifier.align(Alignment.CenterEnd),
+ isExpanded = isExpanded,
+ isExpandable = isExpandable,
+ onExpandedChanged = onExpandedChanged,
+ sliderColors = sliderColors,
+ )
}
transition.AnimatedVisibility(
visible = { it || !isExpandable },
@@ -147,30 +147,48 @@
@Composable
private fun ExpandButton(
isExpanded: Boolean,
+ isExpandable: Boolean,
onExpandedChanged: (Boolean) -> Unit,
sliderColors: PlatformSliderColors,
modifier: Modifier = Modifier,
) {
- IconButton(
- modifier = modifier.size(64.dp),
- onClick = { onExpandedChanged(!isExpanded) },
- colors =
- IconButtonDefaults.filledIconButtonColors(
- containerColor = sliderColors.indicatorColor,
- contentColor = sliderColors.iconColor
- ),
+ val expandButtonStateDescription =
+ if (isExpanded) {
+ stringResource(R.string.volume_panel_expanded_sliders)
+ } else {
+ stringResource(R.string.volume_panel_collapsed_sliders)
+ }
+ AnimatedVisibility(
+ modifier = modifier,
+ visible = isExpandable,
+ enter = expandButtonEnterTransition(),
+ exit = expandButtonExitTransition(),
) {
- Icon(
- painter =
- painterResource(
- if (isExpanded) {
- R.drawable.ic_filled_arrow_down
- } else {
- R.drawable.ic_filled_arrow_up
- }
+ IconButton(
+ modifier =
+ Modifier.size(64.dp).semantics {
+ role = Role.Switch
+ stateDescription = expandButtonStateDescription
+ },
+ onClick = { onExpandedChanged(!isExpanded) },
+ colors =
+ IconButtonDefaults.filledIconButtonColors(
+ containerColor = sliderColors.indicatorColor,
+ contentColor = sliderColors.iconColor
),
- contentDescription = null,
- )
+ ) {
+ Icon(
+ painter =
+ painterResource(
+ if (isExpanded) {
+ R.drawable.ic_filled_arrow_down
+ } else {
+ R.drawable.ic_filled_arrow_up
+ }
+ ),
+ contentDescription = null,
+ )
+ }
}
}
@@ -204,3 +222,63 @@
) +
fadeOut(animationSpec = tween(durationMillis = exitDuration))
}
+
+private fun expandButtonEnterTransition(): EnterTransition {
+ return fadeIn(
+ tween(
+ delayMillis = COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS,
+ durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS,
+ )
+ ) +
+ scaleIn(
+ animationSpec =
+ tween(
+ delayMillis = COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS,
+ durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS,
+ ),
+ initialScale = EXPAND_BUTTON_SCALE,
+ )
+}
+
+private fun expandButtonExitTransition(): ExitTransition {
+ return fadeOut(
+ tween(
+ delayMillis = EXPAND_DURATION_MILLIS,
+ durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS,
+ )
+ ) +
+ scaleOut(
+ animationSpec =
+ tween(
+ delayMillis = EXPAND_DURATION_MILLIS,
+ durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS,
+ ),
+ targetScale = EXPAND_BUTTON_SCALE,
+ )
+}
+
+@Composable
+private fun topSliderPadding(isExpandable: Boolean): State<Dp> {
+ val animationSpec: AnimationSpec<Dp> =
+ if (isExpandable) {
+ tween(
+ delayMillis = COLLAPSE_DURATION_MILLIS,
+ durationMillis = TOP_SLIDER_ANIMATION_DURATION_MILLIS,
+ )
+ } else {
+ tween(
+ delayMillis = EXPAND_DURATION_MILLIS,
+ durationMillis = TOP_SLIDER_ANIMATION_DURATION_MILLIS,
+ )
+ }
+ return animateDpAsState(
+ targetValue =
+ if (isExpandable) {
+ 72.dp
+ } else {
+ 0.dp
+ },
+ animationSpec = animationSpec,
+ label = "TopVolumeSliderPadding"
+ )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
index fdf8ee8..79056b2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
@@ -24,6 +24,7 @@
import com.android.compose.PlatformSliderDefaults
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel
+import com.android.systemui.volume.panel.component.volume.ui.viewmodel.SlidersExpandableViewModel
import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
import com.android.systemui.volume.panel.ui.composable.isPortrait
@@ -48,13 +49,21 @@
modifier = modifier.fillMaxWidth(),
)
} else {
- val isExpanded by viewModel.isExpanded.collectAsState()
+ val expandableViewModel: SlidersExpandableViewModel by
+ viewModel
+ .isExpandable(isPortrait)
+ .collectAsState(SlidersExpandableViewModel.Unavailable)
+ if (expandableViewModel is SlidersExpandableViewModel.Unavailable) {
+ return
+ }
+ val isExpanded =
+ (expandableViewModel as? SlidersExpandableViewModel.Expandable)?.isExpanded ?: true
ColumnVolumeSliders(
viewModels = sliderViewModels,
isExpanded = isExpanded,
onExpandedChanged = viewModel::onExpandedChanged,
sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(),
- isExpandable = isPortrait,
+ isExpandable = expandableViewModel is SlidersExpandableViewModel.Expandable,
modifier = modifier.fillMaxWidth(),
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index d924d88..92d5c26 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -74,6 +74,16 @@
*/
val isUserInputOngoing: Flow<Boolean>,
) : ObservableTransitionState
+
+ fun isIdle(scene: SceneKey?): Boolean {
+ return this is Idle && (scene == null || this.currentScene == scene)
+ }
+
+ fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
+ return this is Transition &&
+ (from == null || this.fromScene == from) &&
+ (to == null || this.toScene == to)
+ }
}
/**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index e270d9e..519bb6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -62,8 +62,8 @@
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val keyguardClockRepository = kosmos.fakeKeyguardClockRepository
private lateinit var underTest: AodBurnInViewModel
-
- private var burnInParameters = BurnInParameters()
+ // assign a smaller value to minViewY to avoid overflow
+ private var burnInParameters = BurnInParameters(minViewY = Int.MAX_VALUE / 2)
private val burnInFlow = MutableStateFlow(BurnInModel())
@Before
@@ -296,52 +296,111 @@
scale = 0.5f,
)
- assertThat(movement?.translationX).isEqualTo(0)
- assertThat(movement?.translationY).isEqualTo(0)
+ assertThat(movement?.translationX).isEqualTo(20)
+ assertThat(movement?.translationY).isEqualTo(30)
assertThat(movement?.scale).isEqualTo(0.5f)
assertThat(movement?.scaleClockOnly).isEqualTo(false)
}
@Test
- fun translationAndScale_composeFlagOn_weatherLargeClock() =
- testBurnInViewModelWhenComposeFlagOn(
+ fun translationAndScale_composeFlagOff_weatherLargeClock() =
+ testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = true,
- expectedScaleOnly = false
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = false
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOff_weatherSmallClock() =
+ testBurnInViewModelForClocks(
+ isSmallClock = true,
+ isWeatherClock = true,
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = false
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOff_nonWeatherLargeClock() =
+ testBurnInViewModelForClocks(
+ isSmallClock = false,
+ isWeatherClock = false,
+ expectedScaleOnly = true,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = false
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOff_nonWeatherSmallClock() =
+ testBurnInViewModelForClocks(
+ isSmallClock = true,
+ isWeatherClock = false,
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = false
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOn_weatherLargeClock() =
+ testBurnInViewModelForClocks(
+ isSmallClock = false,
+ isWeatherClock = true,
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = true
)
@Test
fun translationAndScale_composeFlagOn_weatherSmallClock() =
- testBurnInViewModelWhenComposeFlagOn(
+ testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = true,
- expectedScaleOnly = true
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = true
)
@Test
fun translationAndScale_composeFlagOn_nonWeatherLargeClock() =
- testBurnInViewModelWhenComposeFlagOn(
+ testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = false,
- expectedScaleOnly = true
+ expectedScaleOnly = true,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = true
)
@Test
fun translationAndScale_composeFlagOn_nonWeatherSmallClock() =
- testBurnInViewModelWhenComposeFlagOn(
+ testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = false,
- expectedScaleOnly = true
+ expectedScaleOnly = false,
+ enableMigrateClocksToBlueprintFlag = true,
+ enableComposeLockscreenFlag = true
)
- private fun testBurnInViewModelWhenComposeFlagOn(
+ private fun testBurnInViewModelForClocks(
isSmallClock: Boolean,
isWeatherClock: Boolean,
- expectedScaleOnly: Boolean
+ expectedScaleOnly: Boolean,
+ enableMigrateClocksToBlueprintFlag: Boolean,
+ enableComposeLockscreenFlag: Boolean
) =
testScope.runTest {
- mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ if (enableMigrateClocksToBlueprintFlag) {
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ } else {
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ }
+
+ if (enableComposeLockscreenFlag) {
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ } else {
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ }
if (isSmallClock) {
keyguardClockRepository.setClockSize(ClockSize.SMALL)
// we need the following step to update stateFlow value
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index bc9d257..f46ca00 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -24,6 +24,7 @@
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
@@ -39,6 +40,7 @@
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -117,6 +119,17 @@
}
}
+ private fun expectedDownTransitionKey(
+ isSingleShade: Boolean,
+ isShadeTouchable: Boolean,
+ ): TransitionKey? {
+ return when {
+ !isShadeTouchable -> null
+ !isSingleShade -> TransitionKeys.ToSplitShade
+ else -> null
+ }
+ }
+
private fun expectedUpDestination(
canSwipeToEnter: Boolean,
isShadeTouchable: Boolean,
@@ -184,18 +197,16 @@
)
val destinationScenes by collectLastValue(underTest.destinationScenes)
-
- assertThat(
- destinationScenes
- ?.get(
- Swipe(
- SwipeDirection.Down,
- fromSource = Edge.Top.takeIf { downFromEdge },
- pointerCount = if (downWithTwoPointers) 2 else 1,
- )
- )
- ?.toScene
+ val downDestination =
+ destinationScenes?.get(
+ Swipe(
+ SwipeDirection.Down,
+ fromSource = Edge.Top.takeIf { downFromEdge },
+ pointerCount = if (downWithTwoPointers) 2 else 1,
+ )
)
+
+ assertThat(downDestination?.toScene)
.isEqualTo(
expectedDownDestination(
downFromEdge = downFromEdge,
@@ -204,6 +215,14 @@
)
)
+ assertThat(downDestination?.transitionKey)
+ .isEqualTo(
+ expectedDownTransitionKey(
+ isSingleShade = isSingleShade,
+ isShadeTouchable = isShadeTouchable,
+ )
+ )
+
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene)
.isEqualTo(
expectedUpDestination(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
index a2ffe70..545a0c7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -67,7 +67,7 @@
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Down))?.transitionKey)
- .isEqualTo(GoneToSplitShade)
+ .isEqualTo(ToSplitShade)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 4622f0c..482dc5d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -42,7 +42,7 @@
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -169,11 +169,11 @@
runCurrent()
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.transitionKey)
- .isEqualTo(GoneToSplitShade)
+ .isEqualTo(ToSplitShade)
}
@Test
- fun upTransitionKey_splitShadeDisabled_isNull() =
+ fun upTransitionKey_splitShadeDisable_isNull() =
testScope.runTest {
val destinationScenes by collectLastValue(underTest.destinationScenes)
shadeRepository.setShadeMode(ShadeMode.Single)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 79bf5f1..629c96c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -109,6 +109,12 @@
val largeClockMessageBuffer: MessageBuffer,
)
+data class AodClockBurnInModel(
+ val scale: Float,
+ val translationX: Float,
+ val translationY: Float,
+)
+
/** Specifies layout information for the */
interface ClockFaceLayout {
/** All clock views to add to the root constraint layout before applying constraints. */
@@ -118,6 +124,8 @@
fun applyConstraints(constraints: ConstraintSet): ConstraintSet
fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet
+
+ fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
}
/** A ClockFaceLayout that applies the default lockscreen layout to a single view */
@@ -137,6 +145,10 @@
override fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet {
return constraints
}
+
+ override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) {
+ // Default clock doesn't need detailed control of view
+ }
}
/** Events that should call when various rendering parameters change */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 5a28f711..9b07675f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -26,6 +26,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
@@ -140,6 +141,8 @@
}
private fun listenForAlternateBouncerToGone() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// Handled via #dismissAlternateBouncer.
return
@@ -162,6 +165,8 @@
}
private fun listenForAlternateBouncerToPrimaryBouncer() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
.filterRelevantKeyguardStateAnd { isPrimaryBouncerShowing ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 4d73774..a306954 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -185,6 +186,7 @@
* PRIMARY_BOUNCER.
*/
private fun listenForAodToPrimaryBouncer() {
+ if (SceneContainerFlag.isEnabled) return
scope.launch("$TAG#listenForAodToPrimaryBouncer") {
keyguardInteractor.primaryBouncerShowing
.filterRelevantKeyguardStateAnd { primaryBouncerShowing -> primaryBouncerShowing }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
index e738ea4..63294f7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
@@ -26,6 +26,7 @@
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -93,6 +94,8 @@
}
private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
.filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing }
@@ -101,6 +104,8 @@
}
private fun listenForDreamingLockscreenHostedToGone() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.biometricUnlockState
.filterRelevantKeyguardStateAnd { biometricUnlockState ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index c952e08..7961b45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -88,6 +89,8 @@
private fun listenForDreamingToGlanceableHub() {
if (!communalHub()) return
+ if (SceneContainerFlag.isEnabled)
+ return // TODO(b/336576536): Check if adaptation for scene framework is needed
scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
glanceableHubTransitions.listenForGlanceableHubTransition(
transitionOwnerName = TAG,
@@ -175,6 +178,8 @@
}
private fun listenForDreamingToGoneWhenDismissable() {
+ if (SceneContainerFlag.isEnabled)
+ return // TODO(b/336576536): Check if adaptation for scene framework is needed
scope.launch {
keyguardInteractor.isAbleToDream
.sampleCombine(
@@ -190,6 +195,8 @@
}
private fun listenForDreamingToGoneFromBiometricUnlock() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.biometricUnlockState
.filterRelevantKeyguardStateAnd { biometricUnlockState ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index ad9b6e7..ca6ab3e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import javax.inject.Inject
@@ -63,6 +64,8 @@
) {
override fun start() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
if (!Flags.communalHub()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index c2c095b..2b3732f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -62,6 +63,8 @@
) {
override fun start() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
listenForGoneToAodOrDozing()
listenForGoneToDreaming()
listenForGoneToLockscreenOrHub()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 56261e0..dad2d96 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -20,6 +20,7 @@
import android.util.MathUtils
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launch
+import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -32,6 +33,7 @@
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import java.util.UUID
@@ -150,6 +152,7 @@
}
private fun listenForLockscreenToPrimaryBouncer() {
+ if (SceneContainerFlag.isEnabled) return
scope.launch("$TAG#listenForLockscreenToPrimaryBouncer") {
keyguardInteractor.primaryBouncerShowing
.filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing }
@@ -174,6 +177,7 @@
/* Starts transitions when manually dragging up the bouncer from the lockscreen. */
private fun listenForLockscreenToPrimaryBouncerDragging() {
+ if (SceneContainerFlag.isEnabled) return
var transitionId: UUID? = null
scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") {
shadeRepository.legacyShadeExpansion
@@ -280,6 +284,7 @@
}
private fun listenForLockscreenToGoneDragging() {
+ if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// When the refactor is enabled, we no longer use isKeyguardGoingAway.
scope.launch("$TAG#listenForLockscreenToGoneDragging") {
@@ -337,7 +342,9 @@
* keyguard transition.
*/
private fun listenForLockscreenToGlanceableHub() {
- if (!com.android.systemui.Flags.communalHub()) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
+ if (!Flags.communalHub()) {
return
}
scope.launch(mainDispatcher) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 2a7178f..2603aab2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -27,6 +27,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -91,20 +92,14 @@
.sample(
communalInteractor.isIdleOnCommunal,
communalInteractor.showCommunalFromOccluded,
- communalInteractor.dreamFromOccluded
+ communalInteractor.dreamFromOccluded,
)
.collect { (_, isIdleOnCommunal, showCommunalFromOccluded, dreamFromOccluded) ->
- // Occlusion signals come from the framework, and should interrupt any
- // existing transition
- val to =
- if (restartDreamOnUnocclude() && dreamFromOccluded) {
- KeyguardState.DREAMING
- } else if (isIdleOnCommunal || showCommunalFromOccluded) {
- KeyguardState.GLANCEABLE_HUB
- } else {
- KeyguardState.LOCKSCREEN
- }
- startTransitionTo(to)
+ startTransitionToLockscreenOrHub(
+ isIdleOnCommunal,
+ showCommunalFromOccluded,
+ dreamFromOccluded
+ )
}
}
} else {
@@ -121,23 +116,35 @@
}
.collect { (_, _, isIdleOnCommunal, showCommunalFromOccluded, dreamFromOccluded)
->
- // Occlusion signals come from the framework, and should interrupt any
- // existing transition
- val to =
- if (restartDreamOnUnocclude() && dreamFromOccluded) {
- KeyguardState.DREAMING
- } else if (isIdleOnCommunal || showCommunalFromOccluded) {
- KeyguardState.GLANCEABLE_HUB
- } else {
- KeyguardState.LOCKSCREEN
- }
- startTransitionTo(to)
+ startTransitionToLockscreenOrHub(
+ isIdleOnCommunal,
+ showCommunalFromOccluded,
+ dreamFromOccluded
+ )
}
}
}
}
+ private suspend fun FromOccludedTransitionInteractor.startTransitionToLockscreenOrHub(
+ isIdleOnCommunal: Boolean,
+ showCommunalFromOccluded: Boolean,
+ dreamFromOccluded: Boolean,
+ ) {
+ if (restartDreamOnUnocclude() && dreamFromOccluded) {
+ startTransitionTo(KeyguardState.DREAMING)
+ } else if (isIdleOnCommunal || showCommunalFromOccluded) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
+ startTransitionTo(KeyguardState.GLANCEABLE_HUB)
+ } else {
+ startTransitionTo(KeyguardState.LOCKSCREEN)
+ }
+ }
+
private fun listenForOccludedToGone() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// We don't think OCCLUDED to GONE is possible. You should always have to go via a
// *_BOUNCER state to end up GONE. Launching an activity over a dismissable keyguard
@@ -158,10 +165,6 @@
}
}
- fun dismissToGone() {
- scope.launch { startTransitionTo(KeyguardState.GONE) }
- }
-
private fun listenForOccludedToAsleep() {
scope.launch { listenForSleepTransition() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 181a551..53a0c32 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
@@ -98,6 +99,8 @@
}
private fun listenForPrimaryBouncerToLockscreenHubOrOccluded() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
scope.launch {
keyguardInteractor.primaryBouncerShowing
@@ -158,10 +161,14 @@
}
private fun listenForPrimaryBouncerToAsleep() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch { listenForSleepTransition() }
}
private fun listenForPrimaryBouncerToDreamingLockscreenHosted() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
scope.launch {
keyguardInteractor.primaryBouncerShowing
.sample(keyguardInteractor.isActiveDreamLockscreenHosted, ::Pair)
@@ -174,6 +181,8 @@
}
private fun listenForPrimaryBouncerToGone() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
// This is handled in KeyguardSecurityContainerController and
// StatusBarKeyguardViewManager, which calls the transition interactor to kick off a
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
index 197221a..fcf67d5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
@@ -25,6 +25,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
@@ -49,6 +50,8 @@
fromState: KeyguardState,
toState: KeyguardState,
) {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
val toScene =
if (fromState == KeyguardState.GLANCEABLE_HUB) {
CommunalScenes.Blank
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index a18579d..2c05d49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -28,11 +28,11 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
-import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -356,6 +356,8 @@
* state.
*/
fun startDismissKeyguardTransition() {
+ // TODO(b/336576536): Check if adaptation for scene framework is needed
+ if (SceneContainerFlag.isEnabled) return
when (val startedState = startedKeyguardState.replayCache.last()) {
LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard()
PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index bb2eeb7..dc35e43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -16,11 +16,16 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,6 +47,7 @@
fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
+ sceneInteractor: SceneInteractor,
) {
private val defaultSurfaceBehindVisibility =
transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -103,21 +109,42 @@
* animation. This is used to keep the RemoteAnimationTarget alive until we're done using it.
*/
val usingKeyguardGoingAwayAnimation: Flow<Boolean> =
- combine(
- transitionInteractor.isInTransitionToState(KeyguardState.GONE),
- transitionInteractor.finishedKeyguardState,
- surfaceBehindInteractor.isAnimatingSurface,
- notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
- ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning ->
- // Using the animation if we're animating it directly, or if the
- // ActivityLaunchAnimator is in the process of animating it.
- val animationsRunning = isAnimatingSurface || notifLaunchRunning
- // We may still be animating the surface after the keyguard is fully GONE, since
- // some animations (like the translation spring) are not tied directly to the
- // transition step amount.
- isInTransitionToGone || (finishedState == KeyguardState.GONE && animationsRunning)
- }
- .distinctUntilChanged()
+ if (SceneContainerFlag.isEnabled) {
+ combine(
+ sceneInteractor.transitionState,
+ surfaceBehindInteractor.isAnimatingSurface,
+ notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
+ ) { transition, isAnimatingSurface, isLaunchAnimationRunning ->
+ // Using the animation if we're animating it directly, or if the
+ // ActivityLaunchAnimator is in the process of animating it.
+ val isAnyAnimationRunning = isAnimatingSurface || isLaunchAnimationRunning
+ // We may still be animating the surface after the keyguard is fully GONE, since
+ // some animations (like the translation spring) are not tied directly to the
+ // transition step amount.
+ transition.isTransitioning(to = Scenes.Gone) ||
+ (isAnyAnimationRunning &&
+ (transition.isIdle(Scenes.Gone) ||
+ transition.isTransitioning(from = Scenes.Gone)))
+ }
+ .distinctUntilChanged()
+ } else {
+ combine(
+ transitionInteractor.isInTransitionToState(KeyguardState.GONE),
+ transitionInteractor.finishedKeyguardState,
+ surfaceBehindInteractor.isAnimatingSurface,
+ notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
+ ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning ->
+ // Using the animation if we're animating it directly, or if the
+ // ActivityLaunchAnimator is in the process of animating it.
+ val animationsRunning = isAnimatingSurface || notifLaunchRunning
+ // We may still be animating the surface after the keyguard is fully GONE, since
+ // some animations (like the translation spring) are not tied directly to the
+ // transition step amount.
+ isInTransitionToGone ||
+ (finishedState == KeyguardState.GONE && animationsRunning)
+ }
+ .distinctUntilChanged()
+ }
/**
* Whether the lockscreen is visible, from the Window Manager (WM) perspective.
@@ -127,28 +154,44 @@
* want to know if the AOD/clock/notifs/etc. are visible.
*/
val lockscreenVisibility: Flow<Boolean> =
- transitionInteractor.currentKeyguardState
- .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
- .map { (currentState, startedWithPrev) ->
- val startedFromStep = startedWithPrev?.previousValue
- val startedStep = startedWithPrev?.newValue
- val returningToGoneAfterCancellation =
- startedStep?.to == KeyguardState.GONE &&
- startedFromStep?.transitionState == TransitionState.CANCELED &&
- startedFromStep.from == KeyguardState.GONE
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.transitionState
+ .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ .map { (prevTransitionState, transitionState) ->
+ val isReturningToGoneAfterCancellation =
+ prevTransitionState.isTransitioning(from = Scenes.Gone) &&
+ transitionState.isTransitioning(to = Scenes.Gone)
+ val isNotOnGone =
+ !transitionState.isTransitioning(from = Scenes.Gone) &&
+ !transitionState.isIdle(Scenes.Gone)
- if (!returningToGoneAfterCancellation) {
- // By default, apply the lockscreen visibility of the current state.
- KeyguardState.lockscreenVisibleInState(currentState)
- } else {
- // If we're transitioning to GONE after a prior canceled transition from GONE,
- // then this is the camera launch transition from an asleep state back to GONE.
- // We don't want to show the lockscreen since we're aborting the lock and going
- // back to GONE.
- KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+ isNotOnGone && !isReturningToGoneAfterCancellation
}
- }
- .distinctUntilChanged()
+ .distinctUntilChanged()
+ } else {
+ transitionInteractor.currentKeyguardState
+ .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
+ .map { (currentState, startedWithPrev) ->
+ val startedFromStep = startedWithPrev?.previousValue
+ val startedStep = startedWithPrev?.newValue
+ val returningToGoneAfterCancellation =
+ startedStep?.to == KeyguardState.GONE &&
+ startedFromStep?.transitionState == TransitionState.CANCELED &&
+ startedFromStep.from == KeyguardState.GONE
+
+ if (!returningToGoneAfterCancellation) {
+ // By default, apply the lockscreen visibility of the current state.
+ KeyguardState.lockscreenVisibleInState(currentState)
+ } else {
+ // If we're transitioning to GONE after a prior canceled transition from
+ // GONE, then this is the camera launch transition from an asleep state back
+ // to GONE. We don't want to show the lockscreen since we're aborting the
+ // lock and going back to GONE.
+ KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+ }
+ }
+ .distinctUntilChanged()
+ }
/**
* Whether always-on-display (AOD) is visible when the lockscreen is visible, from window
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index ed5d53c..c846cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -33,14 +33,18 @@
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.clocks.AodClockBurnInModel
import com.android.systemui.plugins.clocks.ClockController
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
object KeyguardClockViewBinder {
private val TAG = KeyguardClockViewBinder::class.simpleName!!
// When changing to new clock, we need to remove old clock views from burnInLayer
private var lastClock: ClockController? = null
+
@JvmStatic
fun bind(
clockSection: ClockSection,
@@ -48,6 +52,7 @@
viewModel: KeyguardClockViewModel,
keyguardClockInteractor: KeyguardClockInteractor,
blueprintInteractor: KeyguardBlueprintInteractor,
+ rootViewModel: KeyguardRootViewModel,
) {
keyguardRootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
@@ -105,6 +110,28 @@
}
}
}
+
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ combine(
+ rootViewModel.translationX,
+ rootViewModel.translationY,
+ rootViewModel.scale,
+ ::Triple
+ )
+ .collect { (translationX, translationY, scale) ->
+ viewModel.currentClock.value
+ ?.largeClock
+ ?.layout
+ ?.applyAodBurnIn(
+ AodClockBurnInModel(
+ translationX = translationX.value!!,
+ translationY = translationY,
+ scale = scale.scale
+ )
+ )
+ }
+ }
}
}
}
@@ -117,17 +144,16 @@
) {
val burnInLayer = viewModel.burnInLayer
val clockController = viewModel.currentClock.value
+ // Large clocks won't be added to or removed from burn in layer
+ // Weather large clock has customized burn in preventing mechanism
+ // Non-weather large clock will only scale and translate vertically
clockController?.let { clock ->
when (clockSize) {
ClockSize.LARGE -> {
clock.smallClock.layout.views.forEach { burnInLayer?.removeView(it) }
- if (clock.config.useAlternateSmartspaceAODTransition) {
- clock.largeClock.layout.views.forEach { burnInLayer?.addView(it) }
- }
}
ClockSize.SMALL -> {
clock.smallClock.layout.views.forEach { burnInLayer?.addView(it) }
- clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) }
}
}
}
@@ -148,13 +174,6 @@
burnInLayer?.removeView(it)
rootView.removeView(it)
}
-
- // add large clock to burn in layer only when it will have same transition with other
- // components in AOD otherwise, it will have a separate scale transition while other
- // components only have translate transition
- if (clock.config.useAlternateSmartspaceAODTransition) {
- clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) }
- }
clock.largeClock.layout.views.forEach { rootView.removeView(it) }
}
lastClock = currentClock
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 4451bca..39db22d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -257,23 +257,6 @@
it.scaleX = scaleViewModel.scale
it.scaleY = scaleViewModel.scale
}
- // Make sure to reset these views, or they will be invisible
- if (childViews[burnInLayerId]?.scaleX != 1f) {
- childViews[burnInLayerId]?.scaleX = 1f
- childViews[burnInLayerId]?.scaleY = 1f
- childViews[aodNotificationIconContainerId]?.scaleX = 1f
- childViews[aodNotificationIconContainerId]?.scaleY = 1f
- view.requestLayout()
- }
- } else {
- // For weather clock, large clock should have only scale
- // transition with other parts in burnInLayer
- childViews[burnInLayerId]?.scaleX = scaleViewModel.scale
- childViews[burnInLayerId]?.scaleY = scaleViewModel.scale
- childViews[aodNotificationIconContainerId]?.scaleX =
- scaleViewModel.scale
- childViews[aodNotificationIconContainerId]?.scaleY =
- scaleViewModel.scale
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index ef29270..b367715 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -38,6 +38,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceLayout
@@ -64,6 +65,7 @@
private val context: Context,
val smartspaceViewModel: KeyguardSmartspaceViewModel,
val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
+ private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
override fun addViews(constraintLayout: ConstraintLayout) {}
override fun bindData(constraintLayout: ConstraintLayout) {
@@ -75,7 +77,8 @@
constraintLayout,
keyguardClockViewModel,
clockInteractor,
- blueprintInteractor.get()
+ blueprintInteractor.get(),
+ rootViewModel,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 5b83a10..c05a1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -27,7 +27,6 @@
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.ui.StateToValue
@@ -121,11 +120,13 @@
),
) { interpolated, burnIn ->
val useAltAod =
- keyguardClockViewModel.currentClock.value?.let { clock ->
- clock.config.useAlternateSmartspaceAODTransition
- } == true
+ keyguardClockViewModel.currentClock.value
+ ?.config
+ ?.useAlternateSmartspaceAODTransition == true
+ // Only scale large non-weather clocks
+ // elements in large weather clock will translate the same as smartspace
val useScaleOnly =
- useAltAod && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
+ (!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
val translationY =
@@ -134,35 +135,12 @@
} else {
max(params.topInset, params.minViewY + burnInY) - params.minViewY
}
- if (ComposeLockscreen.isEnabled) {
- BurnInModel(
- translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
- translationY = translationY,
- scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
- scaleClockOnly = !useScaleOnly,
- )
- } else {
- if (useScaleOnly) {
- BurnInModel(
- translationX = 0,
- translationY = 0,
- scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
- )
- } else {
- // Ensure the desired translation doesn't encroach on the top inset
- BurnInModel(
- translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
- translationY = translationY,
- scale =
- MathUtils.lerp(
- /* start= */ burnIn.scale,
- /* stop= */ 1f,
- /* amount= */ 1f - interpolated,
- ),
- scaleClockOnly = true,
- )
- }
- }
+ BurnInModel(
+ translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
+ translationY = translationY,
+ scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
+ scaleClockOnly = useScaleOnly
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index d8b5013..02e48fc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -28,6 +28,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
@@ -89,10 +90,15 @@
shadeMode: ShadeMode,
): Map<UserAction, UserActionResult> {
val shadeSceneKey =
- if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade
+ UserActionResult(
+ toScene =
+ if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade,
+ transitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split },
+ )
val quickSettingsIfSingleShade =
- if (shadeMode is ShadeMode.Single) Scenes.QuickSettings else shadeSceneKey
+ if (shadeMode is ShadeMode.Single) UserActionResult(Scenes.QuickSettings)
+ else shadeSceneKey
return mapOf(
Swipe.Left to UserActionResult(Scenes.Communal).takeIf { isCommunalAvailable },
@@ -103,7 +109,7 @@
swipeDownFromTop(pointerCount = 2) to
// TODO(b/338577208): Remove 'Dual' once we add Dual Shade invocation zones.
if (shadeMode is ShadeMode.Dual) {
- Scenes.QuickSettingsShade
+ UserActionResult(Scenes.QuickSettingsShade)
} else {
quickSettingsIfSingleShade
},
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
index 0603d21..ef393e4 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
@@ -24,8 +24,8 @@
* These are the subset of transitions that can be referenced by key when asking for a scene change.
*/
object TransitionKeys {
- /** Reference to the gone to shade transition with split shade enabled. */
- val GoneToSplitShade = TransitionKey("GoneToSplitShade")
+ /** Reference to the gone/lockscreen to shade transition with split shade enabled. */
+ val ToSplitShade = TransitionKey("GoneToSplitShade")
/** Reference to a scene transition that can collapse the shade scene instantly. */
val CollapseShadeInstantly = TransitionKey("CollapseShadeInstantly")
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index 016fe57..99118bc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -24,7 +24,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
@@ -73,7 +73,7 @@
val downSceneKey =
if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade
- val downTransitionKey = GoneToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ val downTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
this[Swipe(direction = SwipeDirection.Down)] =
UserActionResult(downSceneKey, downTransitionKey)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index f509ef5..e4a2424 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -33,7 +33,7 @@
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -150,7 +150,7 @@
else -> Scenes.Lockscreen
}
- val upTransitionKey = GoneToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ val upTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
val down = Scenes.QuickSettings.takeIf { shadeMode is ShadeMode.Single }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1ef9c6c..abbe7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -3433,15 +3433,19 @@
int action = ev.getActionMasked();
boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL;
if (mSendingTouchesToSceneFramework) {
- mController.sendTouchToSceneFramework(ev);
+ MotionEvent adjustedEvent = MotionEvent.obtain(ev);
+ adjustedEvent.setLocation(ev.getRawX(), ev.getRawY());
+ mController.sendTouchToSceneFramework(adjustedEvent);
mScrollViewFields.sendCurrentGestureOverscroll(
getExpandedInThisMotion() && !isUpOrCancel);
+ adjustedEvent.recycle();
} else if (!isUpOrCancel) {
// if this is the first touch being sent to the scene framework,
// convert it into a synthetic DOWN event.
mSendingTouchesToSceneFramework = true;
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
+ downEvent.setLocation(ev.getRawX(), ev.getRawY());
mController.sendTouchToSceneFramework(downEvent);
mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion());
downEvent.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b436eb9..e56893a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -282,7 +282,7 @@
@GuardedBy("mSafetyWarningLock")
private CsdWarningDialog mCsdDialog;
private boolean mHovering = false;
- private final boolean mShowActiveStreamOnly;
+ private final boolean mIsTv;
private boolean mConfigChanged = false;
private boolean mIsAnimatingDismiss = false;
private boolean mHasSeenODICaptionsTooltip;
@@ -343,7 +343,7 @@
mConfigurationController = configurationController;
mMediaOutputDialogManager = mediaOutputDialogManager;
mCsdWarningDialogFactory = csdWarningDialogFactory;
- mShowActiveStreamOnly = showActiveStreamOnly();
+ mIsTv = isTv();
mHasSeenODICaptionsTooltip =
Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
mShowLowMediaVolumeIcon =
@@ -1632,7 +1632,7 @@
Trace.endSection();
}
- private boolean showActiveStreamOnly() {
+ private boolean isTv() {
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
|| mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION);
}
@@ -1644,7 +1644,7 @@
return true;
}
- if (!mShowActiveStreamOnly) {
+ if (!mIsTv) {
if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
return mShowA11yStream;
}
@@ -2089,6 +2089,11 @@
}
final int newProgress = getProgressFromVolume(row.ss, row.slider, vlevel);
if (progress != newProgress) {
+ if (mIsTv) {
+ // don't animate slider on TVs
+ row.slider.setProgress(newProgress, false);
+ return;
+ }
if (mShowing && rowVisible) {
// animate!
if (row.anim != null && row.anim.isRunning()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
index 26d6a9a..4b4d69a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -31,13 +31,15 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
@@ -53,12 +55,39 @@
constructor(
@VolumePanelScope private val scope: CoroutineScope,
mediaOutputInteractor: MediaOutputInteractor,
- private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
+ mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory,
private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory,
streamsInteractor: AudioSlidersInteractor,
) {
+ private val mutableIsExpanded = MutableStateFlow<Boolean?>(null)
+ private val isPlaybackActive: Flow<Boolean?> =
+ mediaOutputInteractor.defaultActiveMediaSession
+ .filterData()
+ .flatMapLatest { session ->
+ if (session == null) {
+ flowOf(false)
+ } else {
+ mediaDeviceSessionInteractor.playbackState(session).map { it?.isActive == true }
+ }
+ }
+ .onEach { isPlaybackActive -> mutableIsExpanded.value = !isPlaybackActive }
+ .stateIn(scope, SharingStarted.Eagerly, null)
+ private val portraitExpandable: Flow<SlidersExpandableViewModel> =
+ isPlaybackActive
+ .filterNotNull()
+ .flatMapLatest { isActive ->
+ if (isActive) {
+ mutableIsExpanded.filterNotNull().map { isExpanded ->
+ SlidersExpandableViewModel.Expandable(isExpanded)
+ }
+ } else {
+ flowOf(SlidersExpandableViewModel.Fixed)
+ }
+ }
+ .stateIn(scope, SharingStarted.Eagerly, SlidersExpandableViewModel.Unavailable)
+
val sliderViewModels: StateFlow<List<SliderViewModel>> =
streamsInteractor.volumePanelSliders
.transformLatest { sliderTypes ->
@@ -76,24 +105,16 @@
}
.stateIn(scope, SharingStarted.Eagerly, emptyList())
- private val mutableIsExpanded = MutableSharedFlow<Boolean>()
-
- val isExpanded: StateFlow<Boolean> =
- merge(
- mutableIsExpanded,
- mediaOutputInteractor.defaultActiveMediaSession.filterData().flatMapLatest { session
- ->
- if (session == null) flowOf(true)
- else
- mediaDeviceSessionInteractor.playbackState(session).map {
- it?.isActive != true
- }
- },
- )
- .stateIn(scope, SharingStarted.Eagerly, false)
+ fun isExpandable(isPortrait: Boolean): Flow<SlidersExpandableViewModel> {
+ return if (isPortrait) {
+ portraitExpandable
+ } else {
+ flowOf(SlidersExpandableViewModel.Fixed)
+ }
+ }
fun onExpandedChanged(isExpanded: Boolean) {
- scope.launch { mutableIsExpanded.emit(isExpanded) }
+ scope.launch { mutableIsExpanded.value = isExpanded }
}
private fun CoroutineScope.createSessionViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt
new file mode 100644
index 0000000..19b9ead
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.volume.ui.viewmodel
+
+/**
+ * Models expandability state of the
+ * [com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent].
+ */
+sealed interface SlidersExpandableViewModel {
+
+ /** [SlidersExpandableViewModel] is not loaded. */
+ data object Unavailable : SlidersExpandableViewModel
+
+ data class Expandable(val isExpanded: Boolean) : SlidersExpandableViewModel
+
+ data object Fixed : SlidersExpandableViewModel
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index c3a806b..ef15d21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.BrokenWithSceneContainer
+import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -157,6 +158,7 @@
}
@Test
+ @DisableSceneContainer
fun lockscreenToPrimaryBouncerViaBouncerShowingCall() =
testScope.runTest {
// GIVEN a prior transition has run to LOCKSCREEN
@@ -370,6 +372,7 @@
}
@Test
+ @DisableSceneContainer
fun dreamingLockscreenHostedToGone() =
testScope.runTest {
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
@@ -396,6 +399,7 @@
}
@Test
+ @DisableSceneContainer
fun dreamingLockscreenHostedToPrimaryBouncer() =
testScope.runTest {
// GIVEN a device dreaming with lockscreen hosted dream and not dozing
@@ -623,6 +627,7 @@
/** This handles security method NONE and screen off with lock timeout */
@Test
+ @DisableSceneContainer
fun dreamingToGoneWithKeyguardNotShowing() =
testScope.runTest {
// GIVEN a prior transition has run to DREAMING
@@ -679,6 +684,7 @@
}
@Test
+ @DisableSceneContainer
fun goneToDozing() =
testScope.runTest {
// GIVEN a device with AOD not available
@@ -704,6 +710,7 @@
}
@Test
+ @DisableSceneContainer
fun goneToAod() =
testScope.runTest {
// GIVEN a device with AOD available
@@ -751,6 +758,7 @@
}
@Test
+ @DisableSceneContainer
fun goneToDreaming() =
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
@@ -809,6 +817,7 @@
}
@Test
+ @DisableSceneContainer
fun alternateBouncerToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
@@ -985,6 +994,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToAod() =
testScope.runTest {
// GIVEN aod available
@@ -1015,6 +1025,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToDozing() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
@@ -1043,6 +1054,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToLockscreen() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
@@ -1066,6 +1078,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToGlanceableHub() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
@@ -1097,6 +1110,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToGlanceableHubWhileDreaming() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
@@ -1132,6 +1146,7 @@
}
@Test
+ @DisableSceneContainer
fun primaryBouncerToDreamingLockscreenHosted() =
testScope.runTest {
// GIVEN device dreaming with the lockscreen hosted dream and not dozing
@@ -1445,7 +1460,7 @@
keyguardRepository.setKeyguardOccluded(false)
runCurrent()
- // THEN a transition to GLANCEABLE_HUB should occur
+ // THEN a transition to DREAMING should occur
assertThat(transitionRepository)
.startedTransition(
ownerName = FromOccludedTransitionInteractor::class.simpleName,
@@ -1511,6 +1526,7 @@
}
@Test
+ @DisableSceneContainer
fun dreamingToGlanceableHub() =
testScope.runTest {
// GIVEN a prior transition has run to DREAMING
@@ -1598,6 +1614,7 @@
}
@Test
+ @DisableSceneContainer
fun aodToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to AOD
@@ -1699,6 +1716,7 @@
}
@Test
+ @DisableSceneContainer
fun lockscreenToGlanceableHub() =
testScope.runTest {
// GIVEN a prior transition has run to LOCKSCREEN
@@ -1756,6 +1774,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToLockscreen() =
testScope.runTest {
// GIVEN a prior transition has run to GLANCEABLE_HUB
@@ -1810,6 +1829,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToDozing() =
testScope.runTest {
// GIVEN a prior transition has run to GLANCEABLE_HUB
@@ -1831,6 +1851,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToPrimaryBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
@@ -1852,6 +1873,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToAlternateBouncer() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
@@ -1904,6 +1926,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToGone() =
testScope.runTest {
// GIVEN a prior transition has run to GLANCEABLE_HUB
@@ -1925,6 +1948,7 @@
}
@Test
+ @DisableSceneContainer
fun glanceableHubToDreaming() =
testScope.runTest {
// GIVEN that we are dreaming and not dozing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index b1a8dd1..a77169e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -18,20 +18,29 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,14 +66,22 @@
.thenReturn(surfaceBehindIsAnimatingFlow)
}
- private val underTest = kosmos.windowManagerLockscreenVisibilityInteractor
+ private val underTest = lazy { kosmos.windowManagerLockscreenVisibilityInteractor }
private val testScope = kosmos.testScope
private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
+ @Before
+ fun setUp() {
+ // lazy value needs to be called here otherwise flow collection misbehaves
+ underTest.value
+ kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
+ }
+
@Test
+ @DisableSceneContainer
fun surfaceBehindVisibility_switchesToCorrectFlow() =
testScope.runTest {
- val values by collectValues(underTest.surfaceBehindVisibility)
+ val values by collectValues(underTest.value.surfaceBehindVisibility)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -170,9 +187,10 @@
}
@Test
+ @DisableSceneContainer
fun testUsingGoingAwayAnimation_duringTransitionToGone() =
testScope.runTest {
- val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
+ val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -230,9 +248,10 @@
}
@Test
+ @DisableSceneContainer
fun testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGone() =
testScope.runTest {
- val values by collectValues(underTest.usingKeyguardGoingAwayAnimation)
+ val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -319,9 +338,10 @@
}
@Test
+ @DisableSceneContainer
fun lockscreenVisibility_visibleWhenGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
// Start on LOCKSCREEN.
transitionRepository.sendTransitionStep(
@@ -385,9 +405,10 @@
}
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_usesFromState_ifCanceled() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -486,9 +507,10 @@
* state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true).
*/
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -587,11 +609,11 @@
)
}
- /** */
@Test
+ @DisableSceneContainer
fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() =
testScope.runTest {
- val values by collectValues(underTest.lockscreenVisibility)
+ val values by collectValues(underTest.value.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -702,4 +724,109 @@
values
)
}
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() =
+ testScope.runTest {
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+
+ sceneTransitions.value = lsToGone
+ assertThat(lockscreenVisibility).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(lockscreenVisibility).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() =
+ testScope.runTest {
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = lsToGone
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = goneToLs
+ assertThat(lockscreenVisibility).isFalse()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ assertThat(lockscreenVisibility).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() =
+ testScope.runTest {
+ val usingKeyguardGoingAwayAnimation by
+ collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
+
+ sceneTransitions.value = lsToGone
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(usingKeyguardGoingAwayAnimation).isFalse()
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun sceneContainer_usingGoingAwayAnimation_surfaceBehindIsAnimating() =
+ testScope.runTest {
+ val usingKeyguardGoingAwayAnimation by
+ collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation)
+
+ sceneTransitions.value = lsToGone
+ surfaceBehindIsAnimatingFlow.emit(true)
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ sceneTransitions.value = goneToLs
+ assertThat(usingKeyguardGoingAwayAnimation).isTrue()
+
+ surfaceBehindIsAnimatingFlow.emit(false)
+ assertThat(usingKeyguardGoingAwayAnimation).isFalse()
+ }
+
+ companion object {
+ private val progress = MutableStateFlow(0f)
+
+ private val sceneTransitions =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(Scenes.Lockscreen)
+ )
+
+ private val lsToGone =
+ ObservableTransitionState.Transition(
+ Scenes.Lockscreen,
+ Scenes.Gone,
+ flowOf(Scenes.Lockscreen),
+ progress,
+ false,
+ flowOf(false)
+ )
+
+ private val goneToLs =
+ ObservableTransitionState.Transition(
+ Scenes.Gone,
+ Scenes.Lockscreen,
+ flowOf(Scenes.Lockscreen),
+ progress,
+ false,
+ flowOf(false)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
index 2f650c4..040d3b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
@@ -85,7 +85,6 @@
setupWeatherClock()
KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.LARGE)
verify(burnInLayer).removeView(smallClockView)
- verify(burnInLayer).addView(largeClockView)
}
@Test
@@ -101,7 +100,6 @@
setupNonWeatherClock()
KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.SMALL)
verify(burnInLayer).addView(smallClockView)
- verify(burnInLayer).removeView(largeClockView)
}
private fun setupWeatherClock() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index ba2efe6..b3cc5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
@@ -117,6 +118,7 @@
context,
keyguardSmartspaceViewModel,
{ keyguardBlueprintInteractor },
+ keyguardRootViewModel,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 56e5e29..aac3640 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -138,7 +138,6 @@
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 90a93f4..a6b40df 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -24,6 +24,7 @@
import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.util.mockito.mock
@@ -37,6 +38,7 @@
context = applicationContext,
smartspaceViewModel = keyguardSmartspaceViewModel,
blueprintInteractor = { keyguardBlueprintInteractor },
+ rootViewModel = keyguardRootViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
index 29167d6..b38acc8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
val Kosmos.windowManagerLockscreenVisibilityInteractor by
@@ -29,5 +30,6 @@
fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
+ sceneInteractor = sceneInteractor,
)
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index c7a8369..d04dbc2 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -121,7 +121,6 @@
SystemProperties.getBoolean("pinner.use_pinlist", true);
private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app.
- private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app.
private static final int MAX_ASSISTANT_PIN_SIZE = 60 * (1 << 20); // 60MB max for assistant app.
public static final String ANON_REGION_STAT_NAME = "[anon]";
@@ -176,7 +175,7 @@
// Resource-configured pinner flags;
private final boolean mConfiguredToPinCamera;
- private final boolean mConfiguredToPinHome;
+ private final int mConfiguredHomePinBytes;
private final boolean mConfiguredToPinAssistant;
private final int mConfiguredWebviewPinBytes;
@@ -238,8 +237,8 @@
mDeviceConfigInterface = mInjector.getDeviceConfigInterface();
mConfiguredToPinCamera = context.getResources().getBoolean(
com.android.internal.R.bool.config_pinnerCameraApp);
- mConfiguredToPinHome = context.getResources().getBoolean(
- com.android.internal.R.bool.config_pinnerHomeApp);
+ mConfiguredHomePinBytes = context.getResources().getInteger(
+ com.android.internal.R.integer.config_pinnerHomePinBytes);
mConfiguredToPinAssistant = context.getResources().getBoolean(
com.android.internal.R.bool.config_pinnerAssistantApp);
mConfiguredWebviewPinBytes = context.getResources().getInteger(
@@ -390,7 +389,7 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
if (userSetupCompleteUri.equals(uri)) {
- if (mConfiguredToPinHome) {
+ if (mConfiguredHomePinBytes > 0) {
sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(),
true /* force */);
}
@@ -594,7 +593,7 @@
Slog.i(TAG, "Pinner - skip pinning camera app");
}
- if (mConfiguredToPinHome) {
+ if (mConfiguredHomePinBytes > 0) {
pinKeys.add(KEY_HOME);
}
if (mConfiguredToPinAssistant) {
@@ -815,7 +814,7 @@
case KEY_CAMERA:
return MAX_CAMERA_PIN_SIZE;
case KEY_HOME:
- return MAX_HOME_PIN_SIZE;
+ return mConfiguredHomePinBytes;
case KEY_ASSISTANT:
return MAX_ASSISTANT_PIN_SIZE;
default:
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 3a0f7fb..02bd3cc 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -376,11 +376,14 @@
@NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = deletedPs.getPackageName();
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
+ final boolean shouldDeletePackageSetting =
+ shouldDeletePackageSetting(deletedPs, targetUserId, allUserHandles, flags);
// Retrieve object to delete permissions for shared user later on
final AndroidPackage deletedPkg = deletedPs.getPkg();
// Delete all the data and states related to this package.
- clearPackageStateForUserLIF(deletedPs, targetUserId, flags);
+ clearPackageStateForUserLIF(deletedPs,
+ shouldDeletePackageSetting ? UserHandle.USER_ALL : targetUserId, flags);
// Delete from mPackages
removePackageLI(packageName, (flags & PackageManager.DELETE_CHATTY) != 0);
@@ -392,7 +395,7 @@
deletedPs.setPkg(null);
}
- if (shouldDeletePackageSetting(deletedPs, targetUserId, allUserHandles, flags)) {
+ if (shouldDeletePackageSetting) {
// Delete from mSettings
final SparseBooleanArray changedUsers = new SparseBooleanArray();
synchronized (mPm.mLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index c74284e..f06d3af 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1704,6 +1704,15 @@
final Transition transit = task.mTransitionController.requestCloseTransitionIfNeeded(task);
if (transit != null) {
transit.collectClose(task);
+ if (!task.mTransitionController.useFullReadyTracking()) {
+ // If a transition was created here, it means this is an isolated removeTask. It's
+ // possible for there to be no consequent operations (eg. this is a multiwindow task
+ // closing so nothing becomes visible in response) so we must "touch" the old ready
+ // tracker so that it doesn't get stuck. However, since the old ready tracker
+ // doesn't support multiple conditions, we have to touch it here at the beginning
+ // before anything that may need it to wait (setReady(false)).
+ transit.setReady(task, true);
+ }
} else if (task.mTransitionController.isCollecting()) {
task.mTransitionController.getCollectingTransition().collectClose(task);
}
diff --git a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java
index 88ca029..ec78bce 100644
--- a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java
@@ -112,7 +112,7 @@
resources.addOverride(
com.android.internal.R.array.config_defaultPinnerServiceFiles, new String[0]);
resources.addOverride(com.android.internal.R.bool.config_pinnerCameraApp, false);
- resources.addOverride(com.android.internal.R.bool.config_pinnerHomeApp, false);
+ resources.addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 0);
resources.addOverride(com.android.internal.R.bool.config_pinnerAssistantApp, false);
mFakeDeviceConfigInterface = new FakeDeviceConfigInterface();
@@ -242,7 +242,7 @@
public void testPinHomeApp() throws Exception {
// Enable HOME app pinning
mContext.getOrCreateTestableResources()
- .addOverride(com.android.internal.R.bool.config_pinnerHomeApp, true);
+ .addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 1024);
PinnerService pinnerService = new PinnerService(mContext, mInjector);
pinnerService.onStart();
@@ -266,7 +266,7 @@
public void testPinHomeAppOnBootCompleted() throws Exception {
// Enable HOME app pinning
mContext.getOrCreateTestableResources()
- .addOverride(com.android.internal.R.bool.config_pinnerHomeApp, true);
+ .addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 1024);
PinnerService pinnerService = new PinnerService(mContext, mInjector);
pinnerService.onStart();