summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java112
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java78
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java94
13 files changed, 609 insertions, 22 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 4de96e342b2f..50cfb6a905c9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -37,8 +37,10 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -82,6 +84,22 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
private long mJitterStartTimeMillis;
private boolean mBouncerAnimating;
+ private boolean mWakingUpFromSwipe;
+
+ private final BouncerlessScrimController mBouncerlessScrimController;
+
+ private final BouncerlessScrimController.Callback mBouncerlessExpansionCallback =
+ new BouncerlessScrimController.Callback() {
+ @Override
+ public void onExpansion(ShadeExpansionChangeEvent event) {
+ updateTransitionState(event.getFraction());
+ }
+
+ @Override
+ public void onWakeup() {
+ mWakingUpFromSwipe = true;
+ }
+ };
private final PrimaryBouncerExpansionCallback
mBouncerExpansionCallback =
@@ -156,7 +174,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
@Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter,
PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
DreamOverlayAnimationsController animationsController,
- DreamOverlayStateController stateController) {
+ DreamOverlayStateController stateController,
+ BouncerlessScrimController bouncerlessScrimController) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
@@ -164,6 +183,9 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
+ mBouncerlessScrimController = bouncerlessScrimController;
+ mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback);
+
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
R.dimen.dream_overlay_y_offset);
@@ -190,6 +212,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
@Override
protected void onViewAttached() {
+ mWakingUpFromSwipe = false;
mJitterStartTimeMillis = System.currentTimeMillis();
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback);
@@ -278,6 +301,13 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
*/
public void wakeUp(@NonNull Runnable onAnimationEnd,
@NonNull DelayableExecutor callbackExecutor) {
+ // When swiping causes wakeup, do not run any animations as the dream should exit as soon
+ // as possible.
+ if (mWakingUpFromSwipe) {
+ onAnimationEnd.run();
+ return;
+ }
+
mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index e7b29bb84b3d..0ab8c8e42b03 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -28,6 +28,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
+import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule;
import java.util.Optional;
@@ -42,6 +43,7 @@ import dagger.Provides;
@Module(includes = {
RegisteredComplicationsModule.class,
LowLightDreamModule.class,
+ ScrimModule.class
},
subcomponents = {
DreamOverlayComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 44207f4aecf5..73c2289ad6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -36,11 +36,12 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimManager;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.util.Optional;
@@ -78,7 +79,8 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final float mBouncerZoneScreenPercentage;
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final ScrimManager mScrimManager;
+ private ScrimController mCurrentScrimController;
private float mCurrentExpansion;
private final Optional<CentralSurfaces> mCentralSurfaces;
@@ -90,6 +92,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
private final DisplayMetrics mDisplayMetrics;
private Boolean mCapture;
+ private Boolean mExpanded;
private boolean mBouncerInitiallyShowing;
@@ -101,6 +104,17 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
private final UiEventLogger mUiEventLogger;
+ private final ScrimManager.Callback mScrimManagerCallback = new ScrimManager.Callback() {
+ @Override
+ public void onScrimControllerChanged(ScrimController controller) {
+ if (mCurrentScrimController != null) {
+ mCurrentScrimController.reset();
+ }
+
+ mCurrentScrimController = controller;
+ }
+ };
+
private final GestureDetector.OnGestureListener mOnGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -115,8 +129,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
.orElse(false);
if (mCapture) {
+ // reset expanding
+ mExpanded = false;
// Since the user is dragging the bouncer up, set scrimmed to false.
- mStatusBarKeyguardViewManager.showPrimaryBouncer(false);
+ mCurrentScrimController.show();
}
}
@@ -157,10 +173,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
/* fraction= */ mCurrentExpansion,
- /* expanded= */ false,
+ /* expanded= */ mExpanded,
/* tracking= */ true,
/* dragDownPxAmount= */ dragDownAmount);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(event);
+ mCurrentScrimController.expand(event);
}
@@ -187,7 +203,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
@Inject
public BouncerSwipeTouchHandler(
DisplayMetrics displayMetrics,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ ScrimManager scrimManager,
Optional<CentralSurfaces> centralSurfaces,
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
@@ -200,7 +216,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
UiEventLogger uiEventLogger) {
mDisplayMetrics = displayMetrics;
mCentralSurfaces = centralSurfaces;
- mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mScrimManager = scrimManager;
mNotificationShadeWindowController = notificationShadeWindowController;
mBouncerZoneScreenPercentage = swipeRegionPercentage;
mFlingAnimationUtils = flingAnimationUtils;
@@ -234,9 +250,12 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
mTouchSession = session;
mVelocityTracker.clear();
mNotificationShadeWindowController.setForcePluginOpen(true, this);
+ mScrimManager.addCallback(mScrimManagerCallback);
+ mCurrentScrimController = mScrimManager.getCurrentController();
session.registerCallback(() -> {
mVelocityTracker.recycle();
+ mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
mNotificationShadeWindowController.setForcePluginOpen(false, this);
});
@@ -273,9 +292,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
final float velocityVector =
(float) Math.hypot(horizontalVelocity, verticalVelocity);
- final float expansion = flingRevealsOverlay(verticalVelocity, velocityVector)
- ? KeyguardBouncerConstants.EXPANSION_HIDDEN
- : KeyguardBouncerConstants.EXPANSION_VISIBLE;
+ mExpanded = !flingRevealsOverlay(verticalVelocity, velocityVector);
+ final float expansion = mExpanded
+ ? KeyguardBouncerConstants.EXPANSION_VISIBLE
+ : KeyguardBouncerConstants.EXPANSION_HIDDEN;
// Log the swiping up to show Bouncer event.
if (!mBouncerInitiallyShowing
@@ -286,7 +306,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
flingToExpansion(verticalVelocity, expansion);
if (expansion == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
- mStatusBarKeyguardViewManager.reset(false);
+ mCurrentScrimController.reset();
}
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
new file mode 100644
index 000000000000..f5bbba780b27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+
+import javax.inject.Inject;
+
+/**
+ * Implementation for handling swipe movements on the overlay when the keyguard is present.
+ */
+public class BouncerScrimController implements ScrimController {
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+ @Inject
+ BouncerScrimController(StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ }
+
+ @Override
+ public void show() {
+ mStatusBarKeyguardViewManager.showBouncer(false);
+ }
+
+ @Override
+ public void expand(ShadeExpansionChangeEvent event) {
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(event);
+ }
+
+ @Override
+ public void reset() {
+ mStatusBarKeyguardViewManager.reset(false);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java
new file mode 100644
index 000000000000..01e4d04dcc2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import android.os.PowerManager;
+import android.os.SystemClock;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.unfold.util.CallbackController;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * {@link BouncerlessScrimController} handles scrim progression when no keyguard is set. When
+ * fully expanded, the controller dismisses the dream.
+ */
+@SysUISingleton
+public class BouncerlessScrimController implements ScrimController,
+ CallbackController<BouncerlessScrimController.Callback> {
+ private static final String TAG = "BLScrimController";
+
+ /**
+ * {@link Callback} allows {@link BouncerlessScrimController} clients to be informed of
+ * expansion progression and wakeup
+ */
+ public interface Callback {
+ /**
+ * Invoked when there is a change to the scrim expansion.
+ */
+ void onExpansion(ShadeExpansionChangeEvent event);
+
+ /**
+ * Invoked after {@link BouncerlessScrimController} has started waking up the device.
+ */
+ void onWakeup();
+ }
+
+ private final Executor mExecutor;
+ private final PowerManager mPowerManager;
+
+ @Override
+ public void addCallback(Callback listener) {
+ mExecutor.execute(() -> mCallbacks.add(listener));
+ }
+
+ @Override
+ public void removeCallback(Callback listener) {
+ mExecutor.execute(() -> mCallbacks.remove(listener));
+ }
+
+ private final HashSet<Callback> mCallbacks;
+
+
+ @Inject
+ public BouncerlessScrimController(@Main Executor executor,
+ PowerManager powerManager) {
+ mExecutor = executor;
+ mPowerManager = powerManager;
+ mCallbacks = new HashSet<>();
+ }
+
+ @Override
+ public void expand(ShadeExpansionChangeEvent event) {
+ if (event.getExpanded()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:SwipeUp");
+ mExecutor.execute(() -> mCallbacks.forEach(callback -> callback.onWakeup()));
+ } else {
+ mExecutor.execute(() -> mCallbacks.forEach(callback -> callback.onExpansion(event)));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java
new file mode 100644
index 000000000000..61629ef79637
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+
+/**
+ * {@link ScrimController} provides an interface for the different consumers of scrolling/expansion
+ * events over the dream.
+ */
+public interface ScrimController {
+ /**
+ * Called at the start of expansion before any expansion amount updates.
+ */
+ default void show() {
+ }
+
+ /**
+ * Called for every expansion update.
+ * @param event {@link ShadeExpansionChangeEvent} detailing the change.
+ */
+ default void expand(ShadeExpansionChangeEvent event) {
+ }
+
+ /**
+ * Called at the end of the movement.
+ */
+ default void reset() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java
new file mode 100644
index 000000000000..0d0dff6c8fb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import static com.android.systemui.dreams.touch.scrim.dagger.ScrimModule.BOUNCERLESS_SCRIM_CONTROLLER;
+import static com.android.systemui.dreams.touch.scrim.dagger.ScrimModule.BOUNCER_SCRIM_CONTROLLER;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * {@link ScrimManager} helps manage multiple {@link ScrimController} instances, specifying the
+ * appropriate one to use at the current moment and managing the handoff between controllers.
+ */
+public class ScrimManager {
+ private final ScrimController mBouncerScrimController;
+ private final ScrimController mBouncerlessScrimController;
+ private final KeyguardStateController mKeyguardStateController;
+ private final Executor mExecutor;
+
+ private ScrimController mCurrentController;
+ private final HashSet<Callback> mCallbacks;
+
+ /**
+ * Interface implemented for receiving updates to the active {@link ScrimController}.
+ */
+ public interface Callback {
+ /**
+ * Invoked when the controller changes.
+ * @param controller The currently active {@link ScrimController}.
+ */
+ void onScrimControllerChanged(ScrimController controller);
+ }
+
+ private final KeyguardStateController.Callback mKeyguardStateCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ mExecutor.execute(() -> updateController());
+ }
+ };
+
+ @Inject
+ ScrimManager(@Main Executor executor,
+ @Named(BOUNCER_SCRIM_CONTROLLER) ScrimController bouncerScrimController,
+ @Named(BOUNCERLESS_SCRIM_CONTROLLER)ScrimController bouncerlessScrimController,
+ KeyguardStateController keyguardStateController) {
+ mExecutor = executor;
+ mCallbacks = new HashSet<>();
+ mBouncerlessScrimController = bouncerlessScrimController;
+ mBouncerScrimController = bouncerScrimController;
+ mKeyguardStateController = keyguardStateController;
+
+ mKeyguardStateController.addCallback(mKeyguardStateCallback);
+ updateController();
+ }
+
+ private void updateController() {
+ final ScrimController existingController = mCurrentController;
+ mCurrentController = mKeyguardStateController.canDismissLockScreen()
+ ? mBouncerlessScrimController
+ : mBouncerScrimController;
+
+ if (existingController == mCurrentController) {
+ return;
+ }
+
+ mCallbacks.forEach(callback -> callback.onScrimControllerChanged(mCurrentController));
+ }
+
+ /**
+ * Adds a {@link Callback} to receive future changes to the active {@link ScrimController}.
+ */
+ public void addCallback(Callback callback) {
+ mExecutor.execute(() -> mCallbacks.add(callback));
+ }
+
+ /**
+ * Removes the {@link Callback} from receiving further updates.
+ */
+ public void removeCallback(Callback callback) {
+ mExecutor.execute(() -> mCallbacks.remove(callback));
+ }
+
+ /**
+ * Returns the currently get {@link ScrimController}.
+ * @return
+ */
+ public ScrimController getCurrentController() {
+ return mCurrentController;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java
new file mode 100644
index 000000000000..40bc0ea6e95e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim.dagger;
+
+import com.android.systemui.dreams.touch.scrim.BouncerScrimController;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for scrim related dependencies.
+ */
+@Module
+public interface ScrimModule {
+ String BOUNCERLESS_SCRIM_CONTROLLER = "bouncerless_scrim_controller";
+ String BOUNCER_SCRIM_CONTROLLER = "bouncer_scrim_controller";
+
+ /** */
+ @Provides
+ @Named(BOUNCERLESS_SCRIM_CONTROLLER)
+ static ScrimController providesBouncerlessScrimController(
+ BouncerlessScrimController controller) {
+ return controller;
+ }
+
+ /** */
+ @Provides
+ @Named(BOUNCER_SCRIM_CONTROLLER)
+ static ScrimController providesBouncerScrimController(
+ BouncerScrimController controller) {
+ return controller;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 63179dac7b8c..5adb58bca886 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -77,6 +77,12 @@ public class CrossFadeHelper {
*/
public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
view.animate().cancel();
+
+ // Don't fade out if already not visible.
+ if (view.getAlpha() == 0.0f) {
+ return;
+ }
+
if (fadeOutAmount == 1.0f && view.getVisibility() != View.GONE) {
view.setVisibility(View.INVISIBLE);
} else if (view.getVisibility() == View.INVISIBLE) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 84c97862710f..6b095ffd3977 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -36,6 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
@@ -88,6 +89,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
DreamOverlayAnimationsController mAnimationsController;
@Mock
+ BouncerlessScrimController mBouncerlessScrimController;
+
+ @Mock
DreamOverlayStateController mStateController;
DreamOverlayContainerViewController mController;
@@ -113,7 +117,8 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
MILLIS_UNTIL_FULL_JITTER,
mPrimaryBouncerCallbackInteractor,
mAnimationsController,
- mStateController);
+ mStateController,
+ mBouncerlessScrimController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index f64179deec35..3a168d4e234b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -41,12 +41,13 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimManager;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -63,10 +64,13 @@ import java.util.Optional;
@RunWith(AndroidTestingRunner.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@Mock
- StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ CentralSurfaces mCentralSurfaces;
@Mock
- CentralSurfaces mCentralSurfaces;
+ ScrimManager mScrimManager;
+
+ @Mock
+ ScrimController mScrimController;
@Mock
NotificationShadeWindowController mNotificationShadeWindowController;
@@ -111,7 +115,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mTouchHandler = new BouncerSwipeTouchHandler(
mDisplayMetrics,
- mStatusBarKeyguardViewManager,
+ mScrimManager,
Optional.of(mCentralSurfaces),
mNotificationShadeWindowController,
mValueAnimatorCreator,
@@ -121,6 +125,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
TOUCH_REGION,
mUiEventLogger);
+ when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
@@ -193,7 +198,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
- verify(mStatusBarKeyguardViewManager, never()).onPanelExpansionChanged(any());
+ verify(mScrimController, never()).expand(any());
}
/**
@@ -220,7 +225,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
- verify(mStatusBarKeyguardViewManager, never()).onPanelExpansionChanged(any());
+ verify(mScrimController, never()).expand(any());
}
/**
@@ -274,12 +279,12 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
0, direction == Direction.UP ? SCREEN_HEIGHT_PX - distanceY : distanceY, 0);
- reset(mStatusBarKeyguardViewManager);
+ reset(mScrimController);
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
// Ensure only called once
- verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(any());
+ verify(mScrimController).expand(any());
final float expansion = isBouncerInitiallyShowing ? percent : 1 - percent;
final float dragDownAmount = event2.getY() - event1.getY();
@@ -288,7 +293,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
expansion, /* expanded= */ false, /* tracking= */ true, dragDownAmount);
- verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(event);
+ verify(mScrimController).expand(event);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
new file mode 100644
index 000000000000..79c535aea2d0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class BouncerlessScrimControllerTest extends SysuiTestCase {
+ @Mock
+ BouncerlessScrimController.Callback mCallback;
+
+ @Mock
+ PowerManager mPowerManager;
+
+ private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testWakeupOnSwipeOpen() {
+ final BouncerlessScrimController scrimController =
+ new BouncerlessScrimController(mExecutor, mPowerManager);
+ scrimController.addCallback(mCallback);
+ scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false, 0.0f));
+ mExecutor.runAllReady();
+ verify(mPowerManager).wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_GESTURE), any());
+ verify(mCallback).onWakeup();
+ }
+
+ @Test
+ public void testExpansionPropagation() {
+ final BouncerlessScrimController scrimController =
+ new BouncerlessScrimController(mExecutor, mPowerManager);
+ scrimController.addCallback(mCallback);
+ final ShadeExpansionChangeEvent expansionEvent =
+ new ShadeExpansionChangeEvent(0.5f, false, false, 0.0f);
+ scrimController.expand(expansionEvent);
+ mExecutor.runAllReady();
+ verify(mCallback).onExpansion(eq(expansionEvent));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
new file mode 100644
index 000000000000..ac9822db85d6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.dreams.touch.scrim;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ScrimManagerTest extends SysuiTestCase {
+ @Mock
+ ScrimController mBouncerlessScrimController;
+
+ @Mock
+ ScrimController mBouncerScrimController;
+
+ @Mock
+ KeyguardStateController mKeyguardStateController;
+
+ @Mock
+ ScrimManager.Callback mCallback;
+
+ private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testControllerSelection() {
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ final ScrimManager manager = new ScrimManager(mExecutor, mBouncerScrimController,
+ mBouncerlessScrimController, mKeyguardStateController);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+
+ assertThat(manager.getCurrentController()).isEqualTo(mBouncerScrimController);
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ callbackCaptor.getValue().onKeyguardShowingChanged();
+ mExecutor.runAllReady();
+ assertThat(manager.getCurrentController()).isEqualTo(mBouncerlessScrimController);
+ }
+
+ @Test
+ public void testCallback() {
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ final ScrimManager manager = new ScrimManager(mExecutor, mBouncerScrimController,
+ mBouncerlessScrimController, mKeyguardStateController);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+
+ manager.addCallback(mCallback);
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ callbackCaptor.getValue().onKeyguardShowingChanged();
+ mExecutor.runAllReady();
+ verify(mCallback).onScrimControllerChanged(eq(mBouncerlessScrimController));
+ }
+}