Merge changes from topics "shelf-refactor-anv", "shelf-refactor-click" into udc-dev am: 0948e76a59

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22575210

Change-Id: I11d6dd2eb8bbc0947722908fd4a00b596ad0f103
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Steve Elliott
2023-04-14 04:03:54 +00:00
committed by Automerger Merge Worker
47 changed files with 666 additions and 362 deletions

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -25,9 +25,6 @@ public interface FalsingCollector {
/** */
void onSuccessfulUnlock();
/** */
void onNotificationActive();
/** */
void setShowingAod(boolean showingAod);

View File

@@ -24,10 +24,6 @@ public class FalsingCollectorFake implements FalsingCollector {
public void onSuccessfulUnlock() {
}
@Override
public void onNotificationActive() {
}
@Override
public void setShowingAod(boolean showingAod) {
}

View File

@@ -173,10 +173,6 @@ class FalsingCollectorImpl implements FalsingCollector {
sessionEnd();
}
@Override
public void onNotificationActive() {
}
@Override
public void setShowingAod(boolean showingAod) {
mShowingAod = showingAod;

View File

@@ -29,6 +29,7 @@ import com.android.keyguard.dagger.KeyguardBouncerComponent;
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 @@ import javax.inject.Named;
*/
@Module(includes = {
AccessibilityModule.class,
AccessibilityRepositoryModule.class,
AppOpsModule.class,
AssistModule.class,
BiometricsModule.class,

View File

@@ -178,7 +178,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
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.Utils;
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 java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Provider;
import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -1709,8 +1707,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
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 final class NotificationPanelViewController implements ShadeSurface, Dump
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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
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);
}

View File

@@ -288,7 +288,6 @@ public class NotificationShadeWindowViewController {
mService.userActivity();
mService.wakeUpIfDozing(
mClock.uptimeMillis(),
mView,
"LOCK_ICON_TOUCH",
PowerManager.WAKE_REASON_GESTURE);
}

View File

@@ -90,7 +90,6 @@ class PulsingGestureListener @Inject constructor(
shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing")
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
notificationShadeWindowView,
"PULSING_SINGLE_TAP",
PowerManager.WAKE_REASON_TAP
)
@@ -116,7 +115,6 @@ class PulsingGestureListener @Inject constructor(
) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
notificationShadeWindowView,
"PULSING_DOUBLE_TAP",
PowerManager.WAKE_REASON_TAP
)

View File

@@ -18,7 +18,6 @@ package com.android.systemui.shade
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 @@ interface ShadeNotificationPresenter {
/** Returns whether the screen has temporarily woken up to display notifications. */
fun hasPulsingNotifications(): Boolean
/** The current activated notification. */
var activatedChild: ActivatableNotificationView?
}

View File

@@ -20,7 +20,6 @@ import android.view.View;
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;
@@ -106,11 +105,6 @@ public class LegacyNotificationShelfControllerImpl implements NotificationShelfC
return mView.getIntrinsicHeight();
}
@Override
public void setOnActivatedListener(ActivatableNotificationView.OnActivatedListener listener) {
mView.setOnActivatedListener(listener);
}
@Override
public void setOnClickListener(View.OnClickListener onClickListener) {
mView.setOnClickListener(onClickListener);

View File

@@ -276,7 +276,6 @@ class LockscreenShadeTransitionController @Inject constructor(
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
it,
"SHADE_CLICK",
PowerManager.WAKE_REASON_GESTURE,
)

View File

@@ -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 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
* 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.

View File

@@ -124,7 +124,7 @@ public class NotificationRemoteInputManager implements Dumpable {
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());

View File

@@ -21,8 +21,6 @@ import android.view.View
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 @@ interface NotificationShelfController {
/** 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,

View File

@@ -71,7 +71,7 @@ public final class NotificationClicker implements View.OnClickListener {
}
mCentralSurfacesOptional.ifPresent(centralSurfaces -> centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK",
SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE));
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;

View File

@@ -177,7 +177,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
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);

View File

@@ -28,7 +28,6 @@ import android.util.MathUtils;
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;
@@ -56,30 +55,6 @@ import java.util.Set;
*/
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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
* 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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
*/
private boolean mActivated;
private OnActivatedListener mOnActivatedListener;
private final Interpolator mSlowOutFastInInterpolator;
private final Interpolator mSlowOutLinearInInterpolator;
private Interpolator mCurrentAppearInterpolator;
NotificationBackgroundView mBackgroundNormal;
@@ -142,13 +110,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
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 abstract class ActivatableNotificationView extends ExpandableOutlineView
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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return false;
}
protected boolean handleSlideBack() {
return false;
}
/**
* @return whether this view is interactive and can be double tapped
*/
@@ -270,40 +232,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
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);
@@ -317,13 +251,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
protected void onBelowSpeedBumpChanged() {
}
/**
* @return whether we are below the speed bump
*/
public boolean isBelowSpeedBump() {
return mIsBelowSpeedBump;
}
/**
* Sets the tint color of the background
*/
@@ -728,10 +655,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
mOnActivatedListener = onActivatedListener;
}
@Override
public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
int outlineTranslation) {
@@ -782,14 +705,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
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 abstract class ActivatableNotificationView extends ExpandableOutlineView
});
}
}
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
}
}

View File

@@ -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 @@ public class ActivatableNotificationViewController
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 @@ public class ActivatableNotificationViewController
mExpandableOutlineViewController.init();
mView.setOnTouchListener(mTouchHandler);
mView.setTouchHandler(mTouchHandler);
mView.setAccessibilityManager(mAccessibilityManager);
}
@Override
@@ -99,15 +67,9 @@ public class ActivatableNotificationViewController
}
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());
}

View File

@@ -968,15 +968,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
@Override
protected boolean handleSlideBack() {
if (mMenuRow != null && mMenuRow.isMenuVisible()) {
animateResetTranslation();
return true;
}
return false;
}
@Override
public boolean isSummaryWithChildren() {
return mIsSummaryWithChildren;

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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) {}
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -0,0 +1,4 @@
package com.android.systemui.statusbar.notification.row.ui.viewmodel
/** ViewModel for [com.android.systemui.statusbar.notification.row.ExpandableView]. */
interface ExpandableViewModel

View File

@@ -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 @@ class NotificationShelfInteractor
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 @@ constructor(
) { 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)
}
}

View File

@@ -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.plugins.FalsingManager
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 @@ constructor(
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 @@ constructor(
}
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 @@ constructor(
/** 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)
}
}
}

View File

@@ -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 @@ class NotificationShelfViewModel
@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 @@ constructor(
/** 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()
}
}

View File

@@ -34,7 +34,6 @@ import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
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 @@ public class AmbientState implements Dumpable {
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 @@ public class AmbientState implements Dumpable {
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 @@ public class AmbientState implements Dumpable {
return mHideSensitive;
}
public ActivatableNotificationView getActivatedChild() {
return mActivatedChild;
}
public void setOverScrollAmount(float amount, boolean onTop) {
if (onTop) {
mOverScrollTopAmount = amount;

View File

@@ -4469,24 +4469,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
/**
* 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
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 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
mAmbientState.setActivatedChild(null);
mAmbientState.setDimmed(onKeyguard);
if (mHeadsUpAppearanceController != null) {
@@ -5245,11 +5235,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = getActivatedChild();
setActivatedChild(null);
if (activatedChild != null) {
activatedChild.makeInactive(false /* animate */);
}
updateFooter();
requestChildrenUpdate();
onUpdateRowStates();

View File

@@ -1370,14 +1370,6 @@ public class NotificationStackScrollLayoutController {
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 @@ public class NotificationStackScrollLayoutController {
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
*/

View File

@@ -126,7 +126,7 @@ public class StackScrollAlgorithm {
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 @@ public class StackScrollAlgorithm {
}
}
/**
* 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());
}
}
}

View File

@@ -212,7 +212,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
/**
* 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();

View File

@@ -1253,7 +1253,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mNotifListContainer,
mHeadsUpManager,
mJankMonitor);
mNotificationShelfController.setOnActivatedListener(mPresenter);
mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -1590,12 +1591,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
* 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
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();

View File

@@ -23,6 +23,7 @@ import com.android.systemui.animation.Interpolators;
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 @@ public class NotificationIconAreaController implements
private final DemoModeController mDemoModeController;
private final FeatureFlags mFeatureFlags;
private int mAodIconAppearTranslation;
private boolean mAnimationsEnabled;
@@ -122,11 +125,12 @@ public class NotificationIconAreaController implements
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 class NotificationIconAreaController implements
}
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);
}

View File

@@ -31,7 +31,6 @@ import android.util.Slog;
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.inflation.Notifica
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 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
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 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
mNotifShadeEventSource = notifShadeEventSource;
mMediaManager = notificationMediaManager;
mGutsManager = notificationGutsManager;
mLockscreenGestureLogger = lockscreenGestureLogger;
mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
mNotificationShadeWindowController = notificationShadeWindowController;
mNotifPipelineFlags = notifPipelineFlags;
@@ -238,34 +233,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
return mNotificationPanel.isFullyCollapsed();
}
@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 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
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) {

View File

@@ -21,9 +21,7 @@ import android.content.ContentResolver;
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.OperatorNameViewController;
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.statusbar.window.StatusBarWindowStateController;
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";

View File

@@ -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()
}
}

View File

@@ -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.Before
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 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// 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 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// 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 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
anyLong(), any(), anyString(), anyInt())
anyLong(), anyString(), anyInt())
}
@Test
@@ -212,7 +211,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
anyLong(), any(), anyString(), anyInt())
anyLong(), anyString(), anyInt())
}
@Test
@@ -232,7 +231,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
anyLong(), any(), anyString(), anyInt())
anyLong(), anyString(), anyInt())
}
@Test
@@ -252,7 +251,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
anyLong(), any(), anyString(), anyInt())
anyLong(), anyString(), anyInt())
}
fun updateSettings() {

View File

@@ -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()
}
}

View File

@@ -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 @@ class NotificationShelfInteractorTest : SysuiTestCase() {
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 @@ class NotificationShelfInteractorTest : SysuiTestCase() {
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))
}
}

View File

@@ -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 @@ class NotificationShelfViewModelTest : SysuiTestCase() {
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))
}
}

View File

@@ -387,7 +387,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
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 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
// 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 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
// 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());

View File

@@ -27,6 +27,7 @@ import androidx.test.filters.SmallTest;
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 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
@Mock private DemoModeController mDemoModeController;
@Mock
private NotificationIconContainer mAodIcons;
@Mock
private FeatureFlags mFeatureFlags;
@Before
public void setup() {
@@ -91,6 +94,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
Optional.of(mBubbles),
mDemoModeController,
mDarkIconDispatcher,
mFeatureFlags,
mStatusBarWindowController,
mScreenOffAnimationController);
}

View File

@@ -25,15 +25,12 @@ import static org.mockito.Mockito.when;
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.NotificationEntryB
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 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
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));
}
}

View File

@@ -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