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
This commit is contained in:
Juan Sebastian Martinez
2023-07-19 15:33:32 +00:00
parent 83b7fafe23
commit f966e40a2e
2 changed files with 105 additions and 7 deletions

View File

@@ -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,12 +2634,16 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
if (!mStatusBarStateController.isDozing()) {
mVibratorHelper.vibrate(
Process.myUid(),
mView.getContext().getPackageName(),
ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT,
"falsing-additional-tap-required",
TOUCH_VIBRATION_ATTRIBUTES);
if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
mVibratorHelper.performHapticFeedback(mView, HapticFeedbackConstants.REJECT);
} else {
mVibratorHelper.vibrate(
Process.myUid(),
mView.getContext().getPackageName(),
ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT,
"falsing-additional-tap-required",
TOUCH_VIBRATION_ATTRIBUTES);
}
}
}
@@ -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) {
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
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");
}

View File

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