Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 864d1d1d authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez
Browse files

Adding MSDL feedback to NPVC

Haptic feedback compliant with the Multi-sensory Design Language is
added to NPVC. The feedback is translated from a HapticFeedbackConstant
passed to performHapticFeedback

Test: atest NotificationPanelViewControllerTest
Flag: com.android.systemui.msdl_feedback
Bug: 352771261
Change-Id: Ic91a39dbbe904543c4e3f042ac229b7725d65714
parent c75a1774
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.Flags.msdlFeedback;
import static com.android.systemui.Flags.predictiveBackAnimateShade;
import static com.android.systemui.Flags.smartspaceRelocateToBottom;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
@@ -236,6 +237,9 @@ import com.android.wm.shell.animation.FlingAnimationUtils;

import dalvik.annotation.optimization.NeverCompile;

import com.google.android.msdl.data.model.MSDLToken;
import com.google.android.msdl.domain.MSDLPlayer;

import kotlin.Unit;

import kotlinx.coroutines.CoroutineDispatcher;
@@ -312,6 +316,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener();
    private final NotificationPanelView mView;
    private final VibratorHelper mVibratorHelper;
    private final MSDLPlayer mMSDLPlayer;
    private final MetricsLogger mMetricsLogger;
    private final ConfigurationController mConfigurationController;
    private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder;
@@ -777,7 +782,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
            SplitShadeStateController splitShadeStateController,
            PowerInteractor powerInteractor,
            KeyguardClockPositionAlgorithm keyguardClockPositionAlgorithm,
            NaturalScrollingSettingObserver naturalScrollingSettingObserver) {
            NaturalScrollingSettingObserver naturalScrollingSettingObserver,
            MSDLPlayer msdlPlayer) {
        SceneContainerFlag.assertInLegacyMode();
        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
            @Override
@@ -855,6 +861,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
        mNotificationsDragEnabled = mResources.getBoolean(
                R.bool.config_enableNotificationShadeDrag);
        mVibratorHelper = vibratorHelper;
        mMSDLPlayer = msdlPlayer;
        mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
        mSystemClock = systemClock;
@@ -2911,7 +2918,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
        }

        if (!mStatusBarStateController.isDozing()) {
            mVibratorHelper.performHapticFeedback(mView, HapticFeedbackConstants.REJECT);
            performHapticFeedback(HapticFeedbackConstants.REJECT);
        }
    }

@@ -3279,8 +3286,21 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    }

    public void performHapticFeedback(int constant) {
        if (msdlFeedback()) {
            MSDLToken token;
            switch (constant) {
                case HapticFeedbackConstants.GESTURE_START ->
                        token = MSDLToken.SWIPE_THRESHOLD_INDICATOR;
                case HapticFeedbackConstants.REJECT -> token = MSDLToken.FAILURE;
                default -> token = null;
            }
            if (token != null) {
                mMSDLPlayer.playToken(token, null);
            }
        } else {
            mVibratorHelper.performHapticFeedback(mView, constant);
        }
    }

    private class ShadeHeadsUpTrackerImpl implements ShadeHeadsUpTracker {
        @Override
@@ -3736,10 +3756,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private void maybeVibrateOnOpening(boolean openingWithTouch) {
        if (mVibrateOnOpening && mBarState != KEYGUARD && mBarState != SHADE_LOCKED) {
            if (!openingWithTouch || !mHasVibratedOnOpen) {
                mVibratorHelper.performHapticFeedback(
                        mView,
                        HapticFeedbackConstants.GESTURE_START
                );
                performHapticFeedback(HapticFeedbackConstants.GESTURE_START);
                mHasVibratedOnOpen = true;
                mShadeLog.v("Vibrating on opening, mHasVibratedOnOpen=true");
            }
+14 −12
Original line number Diff line number Diff line
@@ -22,10 +22,6 @@ import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;

import static com.google.common.truth.Truth.assertThat;

import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -40,6 +36,10 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;

import android.animation.Animator;
import android.annotation.IdRes;
import android.content.ContentResolver;
@@ -95,6 +95,7 @@ import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.flags.Flags;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.haptics.msdl.FakeMSDLPlayer;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository;
@@ -151,6 +152,7 @@ import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository;
@@ -167,7 +169,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -200,12 +201,6 @@ import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;

import dagger.Lazy;

import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.channels.BufferOverflow;
import kotlinx.coroutines.test.TestScope;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -220,6 +215,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;

import dagger.Lazy;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.channels.BufferOverflow;
import kotlinx.coroutines.test.TestScope;

public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {

    protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
@@ -374,6 +374,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
    protected View.OnLayoutChangeListener mLayoutChangeListener;
    protected KeyguardStatusViewController mKeyguardStatusViewController;
    protected ShadeRepository mShadeRepository;
    protected FakeMSDLPlayer mMSDLPlayer = mKosmos.getMsdlPlayer();

    protected final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
    protected final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
@@ -761,7 +762,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
                new ResourcesSplitShadeStateController(),
                mPowerInteractor,
                mKeyguardClockPositionAlgorithm,
                mNaturalScrollingSettingObserver);
                mNaturalScrollingSettingObserver,
                mMSDLPlayer);
        mNotificationPanelViewController.initDependencies(
                mCentralSurfaces,
                null,
+22 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.os.PowerManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -69,6 +70,8 @@ import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm;

import com.google.android.msdl.data.model.MSDLToken;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -1458,4 +1461,23 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo

        assertThat(mNotificationPanelViewController.getFalsingThreshold()).isGreaterThan(14);
    }

    @Test
    @EnableFlags(com.android.systemui.Flags.FLAG_MSDL_FEEDBACK)
    public void performHapticFeedback_withMSDL_forGestureStart_deliversDragThresholdToken() {
        mNotificationPanelViewController
                .performHapticFeedback(HapticFeedbackConstants.GESTURE_START);

        assertThat(mMSDLPlayer.getLatestTokenPlayed())
                .isEqualTo(MSDLToken.SWIPE_THRESHOLD_INDICATOR);
    }

    @Test
    @EnableFlags(com.android.systemui.Flags.FLAG_MSDL_FEEDBACK)
    public void performHapticFeedback_withMSDL_forReject_deliversFailureToken() {
        mNotificationPanelViewController
                .performHapticFeedback(HapticFeedbackConstants.REJECT);

        assertThat(mMSDLPlayer.getLatestTokenPlayed()).isEqualTo(MSDLToken.FAILURE);
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.statusbar.StatusBarState.SHADE
import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -157,6 +156,7 @@ class NotificationPanelViewControllerWithCoroutinesTest :
    }

    @Test
    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
    fun doubleTapRequired_onKeyguard_usesPerformHapticFeedback() = runTest {
        launch(Dispatchers.Main.immediate) {
            val listener = getFalsingTapListener()
@@ -184,6 +184,7 @@ class NotificationPanelViewControllerWithCoroutinesTest :
    }

    @Test
    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
    fun doubleTapRequired_shadeLocked_usesPerformHapticFeedback() = runTest {
        launch(Dispatchers.Main.immediate) {
            val listener = getFalsingTapListener()
@@ -209,7 +210,7 @@ class NotificationPanelViewControllerWithCoroutinesTest :
                    KEYGUARD /*statusBarState*/,
                    false /*keyguardFadingAway*/,
                    false /*goingToFullShade*/,
                    SHADE /*oldStatusBarState*/
                    SHADE, /*oldStatusBarState*/
                )
        }
        advanceUntilIdle()