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

Commit f966e40a authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez
Browse files

Using performHapticFeedback on NotificationPanelViewController

Migration towards the new one-way API that can trigger haptic feedback from the UI thread. Calls to the vibrate method of the VibratorHelper are replaced by performHapticFeedback with haptic constants that represent interfactions. A GESTURE_START vibration is delivered upon swipe down events and a REJECT vibration when a second tap is required due to falsing. The migration is controlled by a feature flag at the moment.

Test: Vibration calls were tested in the NotificationPanelViewControllerWithCoroutinesTest class. Manual verification of vibration was performed in the event of swiping down the notification panel. The vibrations were verified when the feature flag was on and off.
Bug: 245528624
Change-Id: I55c3e7a0627358cf5ac0c6e221a6e8bb9a8f8404
parent 83b7fafe
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.UNLOCK;
import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
@@ -70,6 +71,7 @@ import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.MathUtils;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -2632,6 +2634,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
        }

        if (!mStatusBarStateController.isDozing()) {
            if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
                mVibratorHelper.performHapticFeedback(mView, HapticFeedbackConstants.REJECT);
            } else {
                mVibratorHelper.vibrate(
                        Process.myUid(),
                        mView.getContext().getPackageName(),
@@ -2640,6 +2645,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
                        TOUCH_VIBRATION_ATTRIBUTES);
            }
        }
    }

    private void onTrackingStarted() {
        mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
@@ -3504,7 +3510,14 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private void maybeVibrateOnOpening(boolean openingWithTouch) {
        if (mVibrateOnOpening && mBarState != KEYGUARD && mBarState != SHADE_LOCKED) {
            if (!openingWithTouch || !mHasVibratedOnOpen) {
                if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
                    mVibratorHelper.performHapticFeedback(
                            mView,
                            HapticFeedbackConstants.GESTURE_START
                    );
                } else {
                    mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
                }
                mHasVibratedOnOpen = true;
                mShadeLog.v("Vibrating on opening, mHasVibratedOnOpen=true");
            }
+85 −0
Original line number Diff line number Diff line
@@ -16,17 +16,23 @@

package com.android.systemui.shade

import android.os.VibrationEffect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.ViewStub
import androidx.test.filters.SmallTest
import com.android.internal.util.CollectionUtils
import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.systemui.R
import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
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.VibratorHelper
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
@@ -55,6 +61,9 @@ class NotificationPanelViewControllerWithCoroutinesTest :

    override fun getMainDispatcher() = Dispatchers.Main.immediate

    private val ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT =
        VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false)

    @Test
    fun testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() = runTest {
        launch(Dispatchers.Main.immediate) { givenViewAttached() }
@@ -147,6 +156,43 @@ class NotificationPanelViewControllerWithCoroutinesTest :
        advanceUntilIdle()
    }

    @Test
    fun doubleTapRequired_onKeyguard_oneWayHapticsDisabled_usesOldVibrate() = runTest {
        launch(Dispatchers.Main.immediate) {
            whenever(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(false)
            val listener = getFalsingTapListener()
            mStatusBarStateController.setState(KEYGUARD)

            listener.onAdditionalTapRequired()
            val packageName = mView.context.packageName
            verify(mKeyguardIndicationController).showTransientIndication(anyInt())
            verify(mVibratorHelper)
                .vibrate(
                    any(),
                    eq(packageName),
                    eq(ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT),
                    eq("falsing-additional-tap-required"),
                    eq(VibratorHelper.TOUCH_VIBRATION_ATTRIBUTES)
                )
        }
        advanceUntilIdle()
    }

    @Test
    fun doubleTapRequired_onKeyguard_oneWayHapticsEnabled_usesPerformHapticFeedback() = runTest {
        launch(Dispatchers.Main.immediate) {
            whenever(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true)
            val listener = getFalsingTapListener()
            mStatusBarStateController.setState(KEYGUARD)

            listener.onAdditionalTapRequired()
            verify(mKeyguardIndicationController).showTransientIndication(anyInt())
            verify(mVibratorHelper)
                .performHapticFeedback(eq(mView), eq(HapticFeedbackConstants.REJECT))
        }
        advanceUntilIdle()
    }

    @Test
    fun testDoubleTapRequired_ShadeLocked() = runTest {
        launch(Dispatchers.Main.immediate) {
@@ -160,6 +206,45 @@ class NotificationPanelViewControllerWithCoroutinesTest :
        advanceUntilIdle()
    }

    @Test
    fun doubleTapRequired_shadeLocked_oneWayHapticsDisabled_usesOldVibrate() = runTest {
        launch(Dispatchers.Main.immediate) {
            whenever(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(false)
            val listener = getFalsingTapListener()
            val packageName = mView.context.packageName
            mStatusBarStateController.setState(SHADE_LOCKED)

            listener.onAdditionalTapRequired()
            verify(mVibratorHelper)
                .vibrate(
                    any(),
                    eq(packageName),
                    eq(ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT),
                    eq("falsing-additional-tap-required"),
                    eq(VibratorHelper.TOUCH_VIBRATION_ATTRIBUTES)
                )

            verify(mTapAgainViewController).show()
        }
        advanceUntilIdle()
    }

    @Test
    fun doubleTapRequired_shadeLocked_oneWayHapticsEnabled_usesPerformHapticFeedback() = runTest {
        launch(Dispatchers.Main.immediate) {
            whenever(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true)
            val listener = getFalsingTapListener()
            mStatusBarStateController.setState(SHADE_LOCKED)

            listener.onAdditionalTapRequired()
            verify(mVibratorHelper)
                .performHapticFeedback(eq(mView), eq(HapticFeedbackConstants.REJECT))

            verify(mTapAgainViewController).show()
        }
        advanceUntilIdle()
    }

    @Test
    fun testOnAttachRefreshStatusBarState() = runTest {
        launch(Dispatchers.Main.immediate) {