Merge changes from topics "shelf-refactor-anv", "shelf-refactor-click" into udc-dev
* changes:
Add ActivatableNotificationViewBinder hierarchy
Remove NotifShelfController#getInstrinsicHeight()
Decouple NotifIconAreaController and NotifShelf
Remove ActivatableNotificationView#isActivated
Move NotifShelf click handling to Interactor
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
new file mode 100644
index 0000000..ae9f57f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Exposes accessibility-related state. */
+interface AccessibilityRepository {
+ /** @see [AccessibilityManager.isTouchExplorationEnabled] */
+ val isTouchExplorationEnabled: Flow<Boolean>
+
+ companion object {
+ operator fun invoke(a11yManager: AccessibilityManager): AccessibilityRepository =
+ AccessibilityRepositoryImpl(a11yManager)
+ }
+}
+
+private class AccessibilityRepositoryImpl(
+ manager: AccessibilityManager,
+) : AccessibilityRepository {
+ override val isTouchExplorationEnabled: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val listener = TouchExplorationStateChangeListener(::trySend)
+ manager.addTouchExplorationStateChangeListener(listener)
+ trySend(manager.isTouchExplorationEnabled)
+ awaitClose { manager.removeTouchExplorationStateChangeListener(listener) }
+ }
+ .distinctUntilChanged()
+}
+
+@Module
+object AccessibilityRepositoryModule {
+ @Provides fun provideRepo(manager: AccessibilityManager) = AccessibilityRepository(manager)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt
new file mode 100644
index 0000000..968ce0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.accessibility.domain.interactor
+
+import com.android.systemui.accessibility.data.repository.AccessibilityRepository
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class AccessibilityInteractor
+@Inject
+constructor(
+ private val a11yRepo: AccessibilityRepository,
+) {
+ /** @see [android.view.accessibility.AccessibilityManager.isTouchExplorationEnabled] */
+ val isTouchExplorationEnabled: Flow<Boolean>
+ get() = a11yRepo.isTouchExplorationEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index 6670108..08e1e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -26,9 +26,6 @@
void onSuccessfulUnlock();
/** */
- void onNotificationActive();
-
- /** */
void setShowingAod(boolean showingAod);
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index cc25368..f335d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -25,10 +25,6 @@
}
@Override
- public void onNotificationActive() {
- }
-
- @Override
public void setShowingAod(boolean showingAod) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 8bdef13..6a021f6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -174,10 +174,6 @@
}
@Override
- public void onNotificationActive() {
- }
-
- @Override
public void setShowingAod(boolean showingAod) {
mShowingAod = showingAod;
updateSessionActive();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index ac91665..044dd6a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.accessibility.AccessibilityModule;
+import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
@@ -140,6 +141,7 @@
*/
@Module(includes = {
AccessibilityModule.class,
+ AccessibilityRepositoryModule.class,
AppOpsModule.class,
AssistModule.class,
BiometricsModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index a4a7d4c..f77be3a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -178,7 +178,6 @@
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -225,8 +224,6 @@
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -237,6 +234,7 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -1709,8 +1707,7 @@
final float extraSpaceForShelf = lockIconPadding - noShelfOverlapBottomPadding;
if (extraSpaceForShelf > 0f) {
- return Math.min(mNotificationShelfController.getIntrinsicHeight(),
- extraSpaceForShelf);
+ return Math.min(getShelfHeight(), extraSpaceForShelf);
}
return 0f;
}
@@ -1732,10 +1729,18 @@
mNotificationStackScrollLayoutController.getView(),
getVerticalSpaceForLockscreenNotifications(),
getVerticalSpaceForLockscreenShelf(),
- mNotificationShelfController.getIntrinsicHeight()
+ getShelfHeight()
);
}
+ private int getShelfHeight() {
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+ return mNotificationStackScrollLayoutController.getShelfHeight();
+ } else {
+ return mNotificationShelfController.getIntrinsicHeight();
+ }
+ }
+
private void updateClock() {
if (mIsOcclusionTransitionRunning) {
return;
@@ -3308,16 +3313,6 @@
public boolean hasPulsingNotifications() {
return mNotificationListContainer.hasPulsingNotifications();
}
-
- @Override
- public ActivatableNotificationView getActivatedChild() {
- return mNotificationStackScrollLayoutController.getActivatedChild();
- }
-
- @Override
- public void setActivatedChild(ActivatableNotificationView o) {
- mNotificationStackScrollLayoutController.setActivatedChild(o);
- }
}
@Override
@@ -3338,12 +3333,12 @@
mGestureRecorder = recorder;
mHideExpandedRunnable = hideExpandedRunnable;
+ mNotificationShelfController = notificationShelfController;
if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
mNotificationStackScrollLayoutController.setShelfController(
notificationShelfController);
+ mLockscreenShadeTransitionController.bindController(notificationShelfController);
}
- mNotificationShelfController = notificationShelfController;
- mLockscreenShadeTransitionController.bindController(notificationShelfController);
updateMaxDisplayedNotifications(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 2f4cc14..ebbf1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -288,7 +288,6 @@
mService.userActivity();
mService.wakeUpIfDozing(
mClock.uptimeMillis(),
- mView,
"LOCK_ICON_TOUCH",
PowerManager.WAKE_REASON_GESTURE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index b42bdaa..fd82e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -90,7 +90,6 @@
shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing")
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- notificationShadeWindowView,
"PULSING_SINGLE_TAP",
PowerManager.WAKE_REASON_TAP
)
@@ -116,7 +115,6 @@
) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- notificationShadeWindowView,
"PULSING_DOUBLE_TAP",
PowerManager.WAKE_REASON_TAP
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 34c9f6d..b6a2a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -18,7 +18,6 @@
import android.view.MotionEvent
import android.view.ViewGroup
import com.android.systemui.statusbar.RemoteInputController
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController
@@ -254,7 +253,4 @@
/** Returns whether the screen has temporarily woken up to display notifications. */
fun hasPulsingNotifications(): Boolean
-
- /** The current activated notification. */
- var activatedChild: ActivatableNotificationView?
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
index f7d37e6..4ef2063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
@@ -20,7 +20,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -107,11 +106,6 @@
}
@Override
- public void setOnActivatedListener(ActivatableNotificationView.OnActivatedListener listener) {
- mView.setOnActivatedListener(listener);
- }
-
- @Override
public void setOnClickListener(View.OnClickListener onClickListener) {
mView.setOnClickListener(onClickListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 63e29d1..792939b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -276,7 +276,6 @@
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- it,
"SHADE_CLICK",
PowerManager.WAKE_REASON_GESTURE,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index cb414ba..1c9bc60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -25,8 +24,7 @@
* for affecting the state of the system (e.g. starting an intent, given that the presenter may
* want to perform some action before doing so).
*/
-public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
- ActivatableNotificationView.OnActivatedListener {
+public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener {
/**
* Returns true if the presenter is not visible. For example, it may not be necessary to do
* animations if this returns true.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 9e2a07e..c519115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -124,7 +124,7 @@
View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
mCentralSurfacesOptionalLazy.get().ifPresent(
centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), view, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE));
final NotificationEntry entry = getNotificationForParent(view.getParent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
index 07cfd0d..1619dda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
@@ -21,8 +21,6 @@
import android.view.View.OnClickListener
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView.OnActivatedListener
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -43,9 +41,6 @@
/** Whether or not the shelf can modify the color of notifications in the shade. */
fun canModifyColorOfNotifications(): Boolean
- /** @see ActivatableNotificationView.setOnActivatedListener */
- fun setOnActivatedListener(listener: OnActivatedListener)
-
/** Binds the shelf to the host [NotificationStackScrollLayout], via its Controller. */
fun bind(
ambientState: AmbientState,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 705cf92..bab553e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -71,7 +71,7 @@
}
mCentralSurfacesOptional.ifPresent(centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE));
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 611edf8..bdb206b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -177,7 +177,6 @@
private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) {
mListContainer.bindRow(row);
mNotificationRemoteInputManager.bindRow(row);
- row.setOnActivatedListener(mPresenter);
entry.setRow(row);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 68ad49be..766ad88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -28,7 +28,6 @@
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
-import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -57,30 +56,6 @@
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
/**
- * The amount of width, which is kept in the end when performing a disappear animation (also
- * the amount from which the horizontal appearing begins)
- */
- private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f;
-
- /**
- * At which point from [0,1] does the horizontal collapse animation end (or start when
- * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
- */
- private static final float HORIZONTAL_ANIMATION_END = 0.2f;
-
- /**
- * At which point from [0,1] does the horizontal collapse animation start (or start when
- * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
- */
- private static final float HORIZONTAL_ANIMATION_START = 1.0f;
-
- /**
- * At which point from [0,1] does the vertical collapse animation start (or end when
- * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
- */
- private static final float VERTICAL_ANIMATION_START = 1.0f;
-
- /**
* A sentinel value when no color should be used. Can be used with {@link #setTintColor(int)}
* or {@link #setOverrideTintColor(int, float)}.
*/
@@ -95,10 +70,6 @@
* The start of the animation is at #ALPHA_APPEAR_START_FRACTION
*/
private static final float ALPHA_APPEAR_END_FRACTION = 1;
- private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
- = new PathInterpolator(0.6f, 0, 0.5f, 1);
- private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
- = new PathInterpolator(0, 0, 0.5f, 1);
private final Set<SourceType> mOnDetachResetRoundness = new HashSet<>();
private int mTintedRippleColor;
private int mNormalRippleColor;
@@ -112,10 +83,7 @@
*/
private boolean mActivated;
- private OnActivatedListener mOnActivatedListener;
-
private final Interpolator mSlowOutFastInInterpolator;
- private final Interpolator mSlowOutLinearInInterpolator;
private Interpolator mCurrentAppearInterpolator;
NotificationBackgroundView mBackgroundNormal;
@@ -142,13 +110,11 @@
protected Point mTargetPoint;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
- private AccessibilityManager mAccessibilityManager;
protected boolean mUseRoundnessSourceTypes;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
- mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
setClipChildren(false);
setClipToPadding(false);
updateColors();
@@ -230,7 +196,7 @@
public void onTap() {}
/** Sets the last action up time this view was touched. */
- void setLastActionUpTime(long eventTime) {
+ public void setLastActionUpTime(long eventTime) {
mLastActionUpTime = eventTime;
}
@@ -249,10 +215,6 @@
return false;
}
- protected boolean handleSlideBack() {
- return false;
- }
-
/**
* @return whether this view is interactive and can be double tapped
*/
@@ -270,40 +232,12 @@
mBackgroundNormal.setPressedAllowed(allowed);
}
- void makeActive() {
- mActivated = true;
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
- }
-
- public boolean isActive() {
- return mActivated;
- }
-
- /**
- * Cancels the hotspot and makes the notification inactive.
- */
- public void makeInactive(boolean animate) {
- if (mActivated) {
- mActivated = false;
- }
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivationReset(this);
- }
- }
-
private void updateOutlineAlpha() {
float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
setOutlineAlpha(alpha);
}
- private void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
- mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
- updateOutlineAlpha();
- }
-
@Override
public void setBelowSpeedBump(boolean below) {
super.setBelowSpeedBump(below);
@@ -318,13 +252,6 @@
}
/**
- * @return whether we are below the speed bump
- */
- public boolean isBelowSpeedBump() {
- return mIsBelowSpeedBump;
- }
-
- /**
* Sets the tint color of the background
*/
protected void setTintColor(int color) {
@@ -728,10 +655,6 @@
}
}
- public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
- mOnActivatedListener = onActivatedListener;
- }
-
@Override
public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
int outlineTranslation) {
@@ -782,14 +705,10 @@
return mRefocusOnDismiss || isAccessibilityFocused();
}
- void setTouchHandler(Gefingerpoken touchHandler) {
+ public void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
- public void setAccessibilityManager(AccessibilityManager accessibilityManager) {
- mAccessibilityManager = accessibilityManager;
- }
-
/**
* Enable the support for rounded corner based on the SourceType
* @param enabled true if is supported
@@ -832,9 +751,4 @@
});
}
}
-
- public interface OnActivatedListener {
- void onActivated(ActivatableNotificationView view);
- void onActivationReset(ActivatableNotificationView view);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index b084a76..028cd18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -16,15 +16,12 @@
package com.android.systemui.statusbar.notification.row;
-import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationTapHelper;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -37,44 +34,16 @@
private final ExpandableOutlineViewController mExpandableOutlineViewController;
private final AccessibilityManager mAccessibilityManager;
private final FalsingManager mFalsingManager;
- private final FalsingCollector mFalsingCollector;
- private final NotificationTapHelper mNotificationTapHelper;
private final TouchHandler mTouchHandler = new TouchHandler();
- private boolean mNeedsDimming;
-
@Inject
public ActivatableNotificationViewController(ActivatableNotificationView view,
- NotificationTapHelper.Factory notificationTapHelpFactory,
ExpandableOutlineViewController expandableOutlineViewController,
- AccessibilityManager accessibilityManager, FalsingManager falsingManager,
- FalsingCollector falsingCollector) {
+ AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
super(view);
mExpandableOutlineViewController = expandableOutlineViewController;
mAccessibilityManager = accessibilityManager;
mFalsingManager = falsingManager;
- mFalsingCollector = falsingCollector;
-
- mNotificationTapHelper = notificationTapHelpFactory.create(
- (active) -> {
- if (active) {
- mView.makeActive();
- mFalsingCollector.onNotificationActive();
- } else {
- mView.makeInactive(true /* animate */);
- }
- }, mView::performClick, mView::handleSlideBack);
-
- mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
- @Override
- public void onActivated(ActivatableNotificationView view) {
- mFalsingCollector.onNotificationActive();
- }
-
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- }
- });
}
/**
@@ -85,7 +54,6 @@
mExpandableOutlineViewController.init();
mView.setOnTouchListener(mTouchHandler);
mView.setTouchHandler(mTouchHandler);
- mView.setAccessibilityManager(mAccessibilityManager);
}
@Override
@@ -99,15 +67,9 @@
}
class TouchHandler implements Gefingerpoken, View.OnTouchListener {
- private boolean mBlockNextTouch;
-
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean result = false;
- if (mBlockNextTouch) {
- mBlockNextTouch = false;
- return true;
- }
if (ev.getAction() == MotionEvent.ACTION_UP) {
mView.setLastActionUpTime(ev.getEventTime());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 950ab5d..97dcbb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -969,15 +969,6 @@
}
@Override
- protected boolean handleSlideBack() {
- if (mMenuRow != null && mMenuRow.isMenuVisible()) {
- animateResetTranslation();
- return true;
- }
- return false;
- }
-
- @Override
public boolean isSummaryWithChildren() {
return mIsSummaryWithChildren;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
new file mode 100644
index 0000000..54af107
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.statusbar.notification.row.ui.viewbinder
+
+import android.view.MotionEvent
+import android.view.View
+import android.view.View.OnTouchListener
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.launch
+
+/** Binds an [ActivatableNotificationView] to its [view model][ActivatableNotificationViewModel]. */
+object ActivatableNotificationViewBinder {
+
+ fun bind(
+ viewModel: ActivatableNotificationViewModel,
+ view: ActivatableNotificationView,
+ falsingManager: FalsingManager,
+ ) {
+ ExpandableOutlineViewBinder.bind(viewModel, view)
+ val touchHandler = TouchHandler(view, falsingManager)
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.isTouchable.collect { isTouchable ->
+ touchHandler.isTouchEnabled = isTouchable
+ }
+ }
+ view.registerListenersWhileAttached(touchHandler)
+ }
+ }
+ }
+
+ private suspend fun ActivatableNotificationView.registerListenersWhileAttached(
+ touchHandler: TouchHandler,
+ ): Unit =
+ try {
+ setOnTouchListener(touchHandler)
+ setTouchHandler(touchHandler)
+ awaitCancellation()
+ } finally {
+ setTouchHandler(null)
+ setOnTouchListener(null)
+ }
+}
+
+private class TouchHandler(
+ private val view: ActivatableNotificationView,
+ private val falsingManager: FalsingManager,
+) : Gefingerpoken, OnTouchListener {
+
+ var isTouchEnabled = false
+
+ override fun onTouch(v: View, ev: MotionEvent): Boolean {
+ val result = false
+ if (ev.action == MotionEvent.ACTION_UP) {
+ view.setLastActionUpTime(ev.eventTime)
+ }
+ // With a11y, just do nothing.
+ if (!isTouchEnabled) {
+ return false
+ }
+ if (ev.action == MotionEvent.ACTION_UP) {
+ // If this is a false tap, capture the even so it doesn't result in a click.
+ val falseTap: Boolean = falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)
+ if (!falseTap && v is ActivatableNotificationView) {
+ v.onTap()
+ }
+ return falseTap
+ }
+ return result
+ }
+
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = false
+
+ /** Use [onTouch] instead. */
+ override fun onTouchEvent(ev: MotionEvent): Boolean = false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt
new file mode 100644
index 0000000..745ce77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt
@@ -0,0 +1,13 @@
+package com.android.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.ExpandableOutlineView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ExpandableOutlineViewModel as ViewModel
+
+object ExpandableOutlineViewBinder {
+ fun bind(
+ viewModel: ViewModel,
+ view: ExpandableOutlineView,
+ ) {
+ ExpandableViewBinder.bind(viewModel, view)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt
new file mode 100644
index 0000000..49cfb576
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ExpandableViewModel as ViewModel
+
+object ExpandableViewBinder {
+ fun bind(viewModel: ViewModel, view: ExpandableView) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt
new file mode 100644
index 0000000..f46d424
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.statusbar.notification.row.ui.viewmodel
+
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ActivatableNotificationView]. */
+interface ActivatableNotificationViewModel : ExpandableOutlineViewModel {
+ /** Does the view react to touches? */
+ val isTouchable: Flow<Boolean>
+
+ companion object {
+ operator fun invoke(
+ a11yInteractor: AccessibilityInteractor,
+ ): ActivatableNotificationViewModel = ActivatableNotificationViewModelImpl(a11yInteractor)
+ }
+}
+
+private class ActivatableNotificationViewModelImpl(
+ a11yInteractor: AccessibilityInteractor,
+) : ActivatableNotificationViewModel {
+ override val isTouchable: Flow<Boolean> =
+ // If a11y touch exploration is enabled, then the activatable view should ignore touches
+ a11yInteractor.isTouchExplorationEnabled.map { !it }
+}
+
+@Module
+object ActivatableNotificationViewModelModule {
+ @Provides
+ fun provideViewModel(interactor: AccessibilityInteractor) =
+ ActivatableNotificationViewModel(interactor)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt
new file mode 100644
index 0000000..5904c77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt
@@ -0,0 +1,4 @@
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ExpandableOutlineView]. */
+interface ExpandableOutlineViewModel : ExpandableViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt
new file mode 100644
index 0000000..5efaf04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt
@@ -0,0 +1,4 @@
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ExpandableView]. */
+interface ExpandableViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
index 8ba65f7..014406f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
+import android.os.PowerManager
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -31,6 +35,9 @@
constructor(
private val keyguardRepository: KeyguardRepository,
private val deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository,
+ private val centralSurfaces: CentralSurfaces,
+ private val systemClock: SystemClock,
+ private val keyguardTransitionController: LockscreenShadeTransitionController,
) {
/** Is the shelf showing on the keyguard? */
val isShowingOnKeyguard: Flow<Boolean>
@@ -45,4 +52,14 @@
) { isKeyguardShowing, isBypassEnabled ->
isKeyguardShowing && isBypassEnabled
}
+
+ /** Transition keyguard to the locked shade, triggered by the shelf. */
+ fun goToLockedShadeFromShelf() {
+ centralSurfaces.wakeUpIfDozing(
+ systemClock.uptimeMillis(),
+ "SHADE_CLICK",
+ PowerManager.WAKE_REASON_GESTURE,
+ )
+ keyguardTransitionController.goToLockedShade(null)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index b190cf6..c823189 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -17,10 +17,8 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewbinder
import android.view.View
-import android.view.accessibility.AccessibilityManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -28,19 +26,17 @@
import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.NotificationShelfController
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController
-import com.android.systemui.statusbar.notification.row.ExpandableOutlineViewController
-import com.android.systemui.statusbar.notification.row.ExpandableViewController
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.ActivatableNotificationViewBinder
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
-import com.android.systemui.statusbar.phone.NotificationTapHelper
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.util.kotlin.getValue
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -57,11 +53,9 @@
private val shelf: NotificationShelf,
private val viewModel: NotificationShelfViewModel,
featureFlags: FeatureFlags,
- private val notifTapHelperFactory: NotificationTapHelper.Factory,
- private val a11yManager: AccessibilityManager,
private val falsingManager: FalsingManager,
- private val falsingCollector: FalsingCollector,
hostControllerLazy: Lazy<NotificationStackScrollLayoutController>,
+ private val notificationIconAreaController: NotificationIconAreaController,
) : NotificationShelfController {
private val hostController: NotificationStackScrollLayoutController by hostControllerLazy
@@ -78,43 +72,28 @@
}
fun init() {
- NotificationShelfViewBinder.bind(viewModel, shelf)
-
- ActivatableNotificationViewController(
- shelf,
- notifTapHelperFactory,
- ExpandableOutlineViewController(shelf, ExpandableViewController(shelf)),
- a11yManager,
- falsingManager,
- falsingCollector,
- )
- .init()
+ NotificationShelfViewBinder.bind(viewModel, shelf, falsingManager)
hostController.setShelf(shelf)
hostController.setOnNotificationRemovedListener { child, _ ->
view.requestRoundnessResetFor(child)
}
+ notificationIconAreaController.setShelfIcons(shelf.shelfIcons)
}
override val intrinsicHeight: Int
- get() = shelf.intrinsicHeight
+ get() = unsupported
override val shelfIcons: NotificationIconContainer
- get() = shelf.shelfIcons
+ get() = unsupported
override fun canModifyColorOfNotifications(): Boolean = unsupported
- override fun setOnActivatedListener(listener: ActivatableNotificationView.OnActivatedListener) {
- shelf.setOnActivatedListener(listener)
- }
-
override fun bind(
ambientState: AmbientState,
notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
) = unsupported
- override fun setOnClickListener(listener: View.OnClickListener) {
- shelf.setOnClickListener(listener)
- }
+ override fun setOnClickListener(listener: View.OnClickListener) = unsupported
private val unsupported: Nothing
get() = NotificationShelfController.throwIllegalFlagStateError(expected = true)
@@ -122,14 +101,32 @@
/** Binds a [NotificationShelf] to its backend. */
object NotificationShelfViewBinder {
- fun bind(viewModel: NotificationShelfViewModel, shelf: NotificationShelf) {
+ fun bind(
+ viewModel: NotificationShelfViewModel,
+ shelf: NotificationShelf,
+ falsingManager: FalsingManager,
+ ) {
+ ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
shelf.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.canModifyColorOfNotifications
.onEach(shelf::setCanModifyColorOfNotifications)
.launchIn(this)
viewModel.isClickable.onEach(shelf::setCanInteract).launchIn(this)
+ registerViewListenersWhileAttached(shelf, viewModel)
}
}
}
+
+ private suspend fun registerViewListenersWhileAttached(
+ shelf: NotificationShelf,
+ viewModel: NotificationShelfViewModel,
+ ) {
+ try {
+ shelf.setOnClickListener { viewModel.onShelfClicked() }
+ awaitCancellation()
+ } finally {
+ shelf.setOnClickListener(null)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
index 5e297c8..fb19443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import javax.inject.Inject
@@ -29,7 +30,8 @@
@Inject
constructor(
private val interactor: NotificationShelfInteractor,
-) {
+ activatableViewModel: ActivatableNotificationViewModel,
+) : ActivatableNotificationViewModel by activatableViewModel {
/** Is the shelf allowed to be clickable when it has content? */
val isClickable: Flow<Boolean>
get() = interactor.isShowingOnKeyguard
@@ -37,4 +39,9 @@
/** Is the shelf allowed to modify the color of notifications in the host layout? */
val canModifyColorOfNotifications: Flow<Boolean>
get() = interactor.isShelfStatic.map { static -> !static }
+
+ /** Notifies that the user has clicked the shelf. */
+ fun onShelfClicked() {
+ interactor.goToLockedShadeFromShelf()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 77ede04..ae7c216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -34,7 +34,6 @@
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
@@ -65,7 +64,6 @@
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private int mScrollY;
private boolean mDimmed;
- private ActivatableNotificationView mActivatedChild;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
private boolean mDozing;
@@ -360,14 +358,6 @@
mHideSensitive = hideSensitive;
}
- /**
- * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
- * interaction. This child is then scaled normally and its background is fully opaque.
- */
- public void setActivatedChild(ActivatableNotificationView activatedChild) {
- mActivatedChild = activatedChild;
- }
-
public boolean isDimmed() {
// While we are expanding from pulse, we want the notifications not to be dimmed, otherwise
// you'd see the difference to the pulsing notification
@@ -382,10 +372,6 @@
return mHideSensitive;
}
- public ActivatableNotificationView getActivatedChild() {
- return mActivatedChild;
- }
-
public void setOverScrollAmount(float amount, boolean onTop) {
if (onTop) {
mOverScrollTopAmount = amount;
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 af608a7..555d502 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
@@ -4469,24 +4469,6 @@
}
}
- /**
- * See {@link AmbientState#setActivatedChild}.
- */
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void setActivatedChild(ActivatableNotificationView activatedChild) {
- mAmbientState.setActivatedChild(activatedChild);
- if (mAnimationsEnabled) {
- mActivateNeedsAnimation = true;
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public ActivatableNotificationView getActivatedChild() {
- return mAmbientState.getActivatedChild();
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void applyCurrentState() {
int numChildren = getChildCount();
@@ -5137,6 +5119,15 @@
requestChildrenUpdate();
}
+ @Nullable
+ public ExpandableView getShelf() {
+ if (NotificationShelfController.checkRefactorFlagEnabled(mAmbientState.getFeatureFlags())) {
+ return mShelf;
+ } else {
+ return null;
+ }
+ }
+
public void setShelf(NotificationShelf shelf) {
if (!NotificationShelfController.checkRefactorFlagEnabled(
mAmbientState.getFeatureFlags())) {
@@ -5236,7 +5227,6 @@
void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
- mAmbientState.setActivatedChild(null);
mAmbientState.setDimmed(onKeyguard);
if (mHeadsUpAppearanceController != null) {
@@ -5245,11 +5235,6 @@
setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
- ActivatableNotificationView activatedChild = getActivatedChild();
- setActivatedChild(null);
- if (activatedChild != null) {
- activatedChild.makeInactive(false /* animate */);
- }
updateFooter();
requestChildrenUpdate();
onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 1c8727f..b81fb7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1370,14 +1370,6 @@
mView.onUpdateRowStates();
}
- public ActivatableNotificationView getActivatedChild() {
- return mView.getActivatedChild();
- }
-
- public void setActivatedChild(ActivatableNotificationView view) {
- mView.setActivatedChild(view);
- }
-
public void runAfterAnimationFinished(Runnable r) {
mView.runAfterAnimationFinished(r);
}
@@ -1600,6 +1592,14 @@
mView.setShelf(shelf);
}
+ public int getShelfHeight() {
+ if (!NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) {
+ return 0;
+ }
+ ExpandableView shelf = mView.getShelf();
+ return shelf == null ? 0 : shelf.getIntrinsicHeight();
+ }
+
/**
* Enum for UiEvent logged from this class
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index b1fb13e0..3060473 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -126,7 +126,7 @@
updateHeadsUpStates(algorithmState, ambientState);
updatePulsingStates(algorithmState, ambientState);
- updateDimmedActivatedHideSensitive(ambientState, algorithmState);
+ updateDimmedAndHideSensitive(ambientState, algorithmState);
updateClipping(algorithmState, ambientState);
updateSpeedBumpState(algorithmState, speedBumpIndex);
updateShelfState(algorithmState, ambientState);
@@ -341,25 +341,17 @@
}
}
- /**
- * Updates the dimmed, activated and hiding sensitive states of the children.
- */
- private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
- StackScrollAlgorithmState algorithmState) {
+ /** Updates the dimmed and hiding sensitive states of the children. */
+ private void updateDimmedAndHideSensitive(AmbientState ambientState,
+ StackScrollAlgorithmState algorithmState) {
boolean dimmed = ambientState.isDimmed();
boolean hideSensitive = ambientState.isHideSensitive();
- View activatedChild = ambientState.getActivatedChild();
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState childViewState = child.getViewState();
childViewState.dimmed = dimmed;
childViewState.hideSensitive = hideSensitive;
- boolean isActivatedChild = activatedChild == child;
- if (dimmed && isActivatedChild) {
- childViewState.setZTranslation(childViewState.getZTranslation()
- + 2.0f * ambientState.getZDistanceBetweenElements());
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 3a1272f..a6c0435 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -212,7 +212,7 @@
/**
* Wakes up the device if the device was dozing.
*/
- void wakeUpIfDozing(long time, View where, String why, @PowerManager.WakeReason int wakeReason);
+ void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason);
NotificationShadeWindowView getNotificationShadeWindowView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 0960efb..6cb9582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1253,7 +1253,9 @@
// TODO: Deal with the ugliness that comes from having some of the status bar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
- mNotificationIconAreaController.setupShelf(mNotificationShelfController);
+ if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+ mNotificationIconAreaController.setupShelf(mNotificationShelfController);
+ }
mShadeExpansionStateManager.addExpansionListener(mWakeUpCoordinator);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -1563,7 +1565,6 @@
mNotifListContainer,
mHeadsUpManager,
mJankMonitor);
- mNotificationShelfController.setOnActivatedListener(mPresenter);
mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -1590,12 +1591,10 @@
* Ask the display to wake up if currently dozing, else do nothing
*
* @param time when to wake up
- * @param where the view requesting the wakeup
* @param why the reason for the wake up
*/
@Override
- public void wakeUpIfDozing(long time, View where, String why,
- @PowerManager.WakeReason int wakeReason) {
+ public void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason) {
if (mDozing && mScreenOffAnimationController.allowWakeUpIfDozing()) {
mPowerManager.wakeUp(
time, wakeReason, "com.android.systemui:" + why);
@@ -3481,7 +3480,7 @@
mStatusBarHideIconsForBouncerManager.setBouncerShowingAndTriggerUpdate(bouncerShowing);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
if (mBouncerShowing) {
- wakeUpIfDozing(SystemClock.uptimeMillis(), null, "BOUNCER_VISIBLE",
+ wakeUpIfDozing(SystemClock.uptimeMillis(), "BOUNCER_VISIBLE",
PowerManager.WAKE_REASON_GESTURE);
}
updateScrimController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 057fa42..55dc188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,6 +23,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -92,6 +93,8 @@
private final DemoModeController mDemoModeController;
+ private final FeatureFlags mFeatureFlags;
+
private int mAodIconAppearTranslation;
private boolean mAnimationsEnabled;
@@ -122,11 +125,12 @@
Optional<Bubbles> bubblesOptional,
DemoModeController demoModeController,
DarkIconDispatcher darkIconDispatcher,
- StatusBarWindowController statusBarWindowController,
+ FeatureFlags featureFlags, StatusBarWindowController statusBarWindowController,
ScreenOffAnimationController screenOffAnimationController) {
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mStatusBarStateController = statusBarStateController;
+ mFeatureFlags = featureFlags;
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
mDozeParameters = dozeParameters;
@@ -192,9 +196,16 @@
}
public void setupShelf(NotificationShelfController notificationShelfController) {
+ NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags);
mShelfIcons = notificationShelfController.getShelfIcons();
}
+ public void setShelfIcons(NotificationIconContainer icons) {
+ if (NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) {
+ mShelfIcons = icons;
+ }
+ }
+
public void onDensityOrFontScaleChanged(Context context) {
updateIconLayoutParams(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 39362cf..0398a095 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -31,7 +31,6 @@
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.InitController;
import com.android.systemui.R;
@@ -58,14 +57,12 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -84,7 +81,6 @@
private final NotifShadeEventSource mNotifShadeEventSource;
private final NotificationMediaManager mMediaManager;
private final NotificationGutsManager mGutsManager;
- private final LockscreenGestureLogger mLockscreenGestureLogger;
private final NotificationPanelViewController mNotificationPanel;
private final HeadsUpManagerPhone mHeadsUpManager;
@@ -151,7 +147,6 @@
mNotifShadeEventSource = notifShadeEventSource;
mMediaManager = notificationMediaManager;
mGutsManager = notificationGutsManager;
- mLockscreenGestureLogger = lockscreenGestureLogger;
mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
mNotificationShadeWindowController = notificationShadeWindowController;
mNotifPipelineFlags = notifPipelineFlags;
@@ -239,34 +234,6 @@
}
@Override
- public void onActivated(ActivatableNotificationView view) {
- onActivated();
- if (view != null) {
- mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(view);
- }
- }
-
- public void onActivated() {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_NOTE,
- 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
- mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
- ActivatableNotificationView previousView =
- mNotificationPanel.getShadeNotificationPresenter().getActivatedChild();
- if (previousView != null) {
- previousView.makeInactive(true /* animate */);
- }
- }
-
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- if (view == mNotificationPanel.getShadeNotificationPresenter().getActivatedChild()) {
- mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(null);
- mKeyguardIndicationController.hideTransientIndication();
- }
- }
-
- @Override
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
mMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation);
}
@@ -276,7 +243,7 @@
boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
mCentralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE);
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 5d4adda..b96001f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -21,9 +21,7 @@
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.ViewStub;
-
import androidx.constraintlayout.motion.widget.MotionLayout;
-
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.LockIconView;
import com.android.systemui.R;
@@ -52,6 +50,7 @@
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
@@ -75,18 +74,16 @@
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.settings.SecureSettings;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Named;
-import javax.inject.Provider;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
+import java.util.concurrent.Executor;
+import javax.inject.Named;
+import javax.inject.Provider;
-@Module(subcomponents = StatusBarFragmentComponent.class)
+@Module(subcomponents = StatusBarFragmentComponent.class,
+ includes = { ActivatableNotificationViewModelModule.class })
public abstract class StatusBarViewModule {
public static final String SHADE_HEADER = "large_screen_shade_header";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
new file mode 100644
index 0000000..aff52f5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.accessibility.data.repository
+
+import android.testing.AndroidTestingRunner
+import android.view.accessibility.AccessibilityManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AccessibilityRepositoryTest : SysuiTestCase() {
+
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ // mocks
+ @Mock private lateinit var a11yManager: AccessibilityManager
+
+ // real impls
+ private val underTest by lazy { AccessibilityRepository(a11yManager) }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_initFalse() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(false)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ assertThat(isTouchExplorationEnabled).isFalse()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_initTrue() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(true)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ assertThat(isTouchExplorationEnabled).isTrue()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_changeTrue() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(false)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ runCurrent()
+ withArgCaptor { verify(a11yManager).addTouchExplorationStateChangeListener(capture()) }
+ .onTouchExplorationStateChanged(/* enabled = */ true)
+ assertThat(isTouchExplorationEnabled).isTrue()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_changeFalse() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(true)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ runCurrent()
+ withArgCaptor { verify(a11yManager).addTouchExplorationStateChangeListener(capture()) }
+ .onTouchExplorationStateChanged(/* enabled = */ false)
+ assertThat(isTouchExplorationEnabled).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index 76aa08a..d7c06a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -17,11 +17,11 @@
package com.android.systemui.shade
import android.hardware.display.AmbientDisplayConfiguration
+import android.os.PowerManager
import android.provider.Settings.Secure.DOZE_DOUBLE_TAP_GESTURE
import android.provider.Settings.Secure.DOZE_TAP_SCREEN_GESTURE
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
-import android.os.PowerManager
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -38,15 +38,14 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -112,7 +111,7 @@
// THEN wake up device if dozing
verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), any(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
}
@Test
@@ -132,7 +131,7 @@
// THEN wake up device if dozing
verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), any(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
}
@Test
@@ -164,7 +163,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -212,7 +211,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -232,7 +231,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -252,7 +251,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
fun updateSettings() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
new file mode 100644
index 0000000..c960230
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import com.android.systemui.coroutines.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ActivatableNotificationViewModelTest : SysuiTestCase() {
+
+ // fakes
+ private val a11yRepo = FakeAccessibilityRepository()
+
+ // real impls
+ private val a11yInteractor = AccessibilityInteractor(a11yRepo)
+ private val underTest = ActivatableNotificationViewModel(a11yInteractor)
+
+ @Test
+ fun isTouchable_whenA11yTouchExplorationDisabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = false
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ assertThat(isTouchable).isTrue()
+ }
+
+ @Test
+ fun isNotTouchable_whenA11yTouchExplorationEnabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = true
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ assertThat(isTouchable).isFalse()
+ }
+
+ @Test
+ fun isTouchable_whenA11yTouchExplorationChangesToDisabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = true
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ runCurrent()
+ a11yRepo.isTouchExplorationEnabled.value = false
+ assertThat(isTouchable).isTrue()
+ }
+
+ @Test
+ fun isNotTouchable_whenA11yTouchExplorationChangesToEnabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = false
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ runCurrent()
+ a11yRepo.isTouchExplorationEnabled.value = true
+ assertThat(isTouchable).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index 2cc375b..944eb2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -18,17 +18,27 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.verify
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -36,8 +46,17 @@
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
+ private val centralSurfaces: CentralSurfaces = mock()
+ private val systemClock = FakeSystemClock()
+ private val keyguardTransitionController: LockscreenShadeTransitionController = mock()
private val underTest =
- NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository)
+ NotificationShelfInteractor(
+ keyguardRepository,
+ deviceEntryFaceAuthRepository,
+ centralSurfaces,
+ systemClock,
+ keyguardTransitionController,
+ )
@Test
fun shelfIsNotStatic_whenKeyguardNotShowing() = runTest {
@@ -85,4 +104,19 @@
assertThat(onKeyguard).isFalse()
}
+
+ @Test
+ fun goToLockedShadeFromShelf_wakesUpFromDoze() {
+ underTest.goToLockedShadeFromShelf()
+
+ verify(centralSurfaces)
+ .wakeUpIfDozing(anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ }
+
+ @Test
+ fun goToLockedShadeFromShelf_invokesKeyguardTransitionController() {
+ underTest.goToLockedShadeFromShelf()
+
+ verify(keyguardTransitionController).goToLockedShade(isNull(), eq(true))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 439edaf..e9a8f3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -18,28 +18,64 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
@RunWith(AndroidTestingRunner::class)
@SmallTest
class NotificationShelfViewModelTest : SysuiTestCase() {
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ // mocks
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
+
+ // fakes
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- private val interactor =
- NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository)
- private val underTest = NotificationShelfViewModel(interactor)
+ private val systemClock = FakeSystemClock()
+ private val a11yRepo = FakeAccessibilityRepository()
+
+ // real impls
+ private val a11yInteractor = AccessibilityInteractor(a11yRepo)
+ private val activatableViewModel = ActivatableNotificationViewModel(a11yInteractor)
+ private val interactor by lazy {
+ NotificationShelfInteractor(
+ keyguardRepository,
+ deviceEntryFaceAuthRepository,
+ centralSurfaces,
+ systemClock,
+ keyguardTransitionController,
+ )
+ }
+ private val underTest by lazy { NotificationShelfViewModel(interactor, activatableViewModel) }
@Test
fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest {
@@ -87,4 +123,13 @@
assertThat(isClickable).isFalse()
}
+
+ @Test
+ fun onClicked_goesToLockedShade() {
+ underTest.onShelfClicked()
+
+ verify(centralSurfaces)
+ .wakeUpIfDozing(ArgumentMatchers.anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6332069..fdd6140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -387,7 +387,6 @@
when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0));
when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
when(mPowerManagerService.isInteractive()).thenReturn(true);
- when(mStackScroller.getActivatedChild()).thenReturn(null);
doAnswer(invocation -> {
OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
@@ -1327,7 +1326,7 @@
// WHEN wakeup is requested
final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, null, "", wakeReason);
+ mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
// THEN power manager receives wakeup
verify(mPowerManagerService).wakeUp(eq(0L), eq(wakeReason), anyString(), anyString());
@@ -1341,7 +1340,7 @@
// WHEN wakeup is requested
final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, null, "", wakeReason);
+ mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
// THEN power manager receives wakeup
verify(mPowerManagerService, never()).wakeUp(anyLong(), anyInt(), anyString(), anyString());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 7d9c091..8e1dcf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -27,6 +27,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
@@ -75,6 +76,8 @@
@Mock private DemoModeController mDemoModeController;
@Mock
private NotificationIconContainer mAodIcons;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Before
public void setup() {
@@ -91,6 +94,7 @@
Optional.of(mBubbles),
mDemoModeController,
mDarkIconDispatcher,
+ mFeatureFlags,
mStatusBarWindowController,
mScreenOffAnimationController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index e83e50d..fea5363 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -25,15 +25,12 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.metrics.LogMaker;
-import android.support.test.metricshelper.MetricsAsserts;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
@@ -61,7 +58,6 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -283,15 +279,4 @@
assertTrue("CentralSurfaces alerts disabled shouldn't allow interruptions",
mInterruptSuppressor.suppressInterruptions(entry));
}
-
- @Test
- public void onActivatedMetrics() {
- ActivatableNotificationView view = mock(ActivatableNotificationView.class);
- mStatusBarNotificationPresenter.onActivated(view);
-
- MetricsAsserts.assertHasLog("missing lockscreen note tap log",
- mMetricsLogger.getLogs(),
- new LogMaker(MetricsEvent.ACTION_LS_NOTE)
- .setType(MetricsEvent.TYPE_ACTION));
- }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt
new file mode 100644
index 0000000..8444c7b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.accessibility.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeAccessibilityRepository(
+ override val isTouchExplorationEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
+) : AccessibilityRepository