[Test Week] Add VibratorWrapperTest
Number of new tested methods: 9
Bug: 353303621
Test: This is the unit test
Flag: NONE - unit test
Change-Id: Id6dde920d6365823cf859e97c7c0cfbb25e7270d
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 51749a7..6bae1ba 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -31,6 +31,7 @@
import android.provider.Settings;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -49,14 +50,14 @@
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
- private static final Uri HAPTIC_FEEDBACK_URI =
- Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
+ @VisibleForTesting
+ static final Uri HAPTIC_FEEDBACK_URI = Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED);
- private static final float LOW_TICK_SCALE = 0.9f;
- private static final float DRAG_TEXTURE_SCALE = 0.03f;
- private static final float DRAG_COMMIT_SCALE = 0.5f;
- private static final float DRAG_BUMP_SCALE = 0.4f;
- private static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
+ @VisibleForTesting static final float LOW_TICK_SCALE = 0.9f;
+ @VisibleForTesting static final float DRAG_TEXTURE_SCALE = 0.03f;
+ @VisibleForTesting static final float DRAG_COMMIT_SCALE = 0.5f;
+ @VisibleForTesting static final float DRAG_BUMP_SCALE = 0.4f;
+ @VisibleForTesting static final int DRAG_TEXTURE_EFFECT_SIZE = 200;
@Nullable
private final VibrationEffect mDragEffect;
@@ -73,22 +74,29 @@
*/
public static final VibrationEffect OVERVIEW_HAPTIC = EFFECT_CLICK;
- private final Context mContext;
private final Vibrator mVibrator;
private final boolean mHasVibrator;
- private final SettingsCache.OnChangeListener mHapticChangeListener =
+
+ private final SettingsCache mSettingsCache;
+
+ @VisibleForTesting
+ final SettingsCache.OnChangeListener mHapticChangeListener =
isEnabled -> mIsHapticFeedbackEnabled = isEnabled;
private boolean mIsHapticFeedbackEnabled;
private VibratorWrapper(Context context) {
- mContext = context;
- mVibrator = context.getSystemService(Vibrator.class);
+ this(context.getSystemService(Vibrator.class), SettingsCache.INSTANCE.get(context));
+ }
+
+ @VisibleForTesting
+ VibratorWrapper(Vibrator vibrator, SettingsCache settingsCache) {
+ mVibrator = vibrator;
mHasVibrator = mVibrator.hasVibrator();
+ mSettingsCache = settingsCache;
if (mHasVibrator) {
- SettingsCache cache = SettingsCache.INSTANCE.get(mContext);
- cache.register(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
- mIsHapticFeedbackEnabled = cache.getValue(HAPTIC_FEEDBACK_URI, 0);
+ mSettingsCache.register(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+ mIsHapticFeedbackEnabled = mSettingsCache.getValue(HAPTIC_FEEDBACK_URI, 0);
} else {
mIsHapticFeedbackEnabled = false;
}
@@ -98,12 +106,7 @@
// Drag texture, Commit, and Bump should only be used for premium phones.
// Before using these haptics make sure check if the device can use it
- VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
- for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
- dragEffect.addPrimitive(
- PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
- }
- mDragEffect = dragEffect.compose();
+ mDragEffect = getDragEffect();
mCommitEffect = VibrationEffect.startComposition().addPrimitive(
VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose();
mBumpEffect = VibrationEffect.startComposition().addPrimitive(
@@ -124,8 +127,7 @@
@Override
public void close() {
if (mHasVibrator) {
- SettingsCache.INSTANCE.get(mContext)
- .unregister(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
+ mSettingsCache.unregister(HAPTIC_FEEDBACK_URI, mHapticChangeListener);
}
}
@@ -215,4 +217,13 @@
vibrate(primitiveLowTickEffect);
}
}
+
+ static VibrationEffect getDragEffect() {
+ VibrationEffect.Composition dragEffect = VibrationEffect.startComposition();
+ for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) {
+ dragEffect.addPrimitive(
+ PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE);
+ }
+ return dragEffect.compose();
+ }
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
new file mode 100644
index 0000000..330c394
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2024 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.launcher3.util
+
+import android.media.AudioAttributes
+import android.os.SystemClock
+import android.os.VibrationEffect
+import android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK
+import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
+import android.os.Vibrator
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.VibratorWrapper.HAPTIC_FEEDBACK_URI
+import com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC
+import com.android.launcher3.util.VibratorWrapper.VIBRATION_ATTRS
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.never
+import org.mockito.kotlin.same
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class VibratorWrapperTest {
+
+ @Mock private lateinit var settingsCache: SettingsCache
+ @Mock private lateinit var vibrator: Vibrator
+ @Captor private lateinit var vibrationEffectCaptor: ArgumentCaptor<VibrationEffect>
+
+ private lateinit var underTest: VibratorWrapper
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(settingsCache.getValue(HAPTIC_FEEDBACK_URI, 0)).thenReturn(true)
+ `when`(vibrator.hasVibrator()).thenReturn(true)
+ `when`(vibrator.areAllPrimitivesSupported(PRIMITIVE_TICK)).thenReturn(true)
+ `when`(vibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)).thenReturn(true)
+ `when`(vibrator.getPrimitiveDurations(PRIMITIVE_LOW_TICK)).thenReturn(intArrayOf(10))
+
+ underTest = VibratorWrapper(vibrator, settingsCache)
+ }
+
+ @Test
+ fun init_register_onChangeListener() {
+ verify(settingsCache).register(HAPTIC_FEEDBACK_URI, underTest.mHapticChangeListener)
+ }
+
+ @Test
+ fun close_unregister_onChangeListener() {
+ underTest.close()
+
+ verify(settingsCache).unregister(HAPTIC_FEEDBACK_URI, underTest.mHapticChangeListener)
+ }
+
+ @Test
+ fun vibrate() {
+ underTest.vibrate(OVERVIEW_HAPTIC)
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(OVERVIEW_HAPTIC, VIBRATION_ATTRS)
+ }
+
+ @Test
+ fun vibrate_primitive_id() {
+ underTest.vibrate(PRIMITIVE_TICK, 1f, OVERVIEW_HAPTIC)
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
+ val expectedEffect =
+ VibrationEffect.startComposition().addPrimitive(PRIMITIVE_TICK, 1f).compose()
+ assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
+ }
+
+ @Test
+ fun vibrate_with_invalid_primitive_id_use_fallback_effect() {
+ underTest.vibrate(-1, 1f, OVERVIEW_HAPTIC)
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(OVERVIEW_HAPTIC, VIBRATION_ATTRS)
+ }
+
+ @Test
+ fun vibrate_for_taskbar_unstash() {
+ underTest.vibrateForTaskbarUnstash()
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
+ val expectedEffect =
+ VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_LOW_TICK, VibratorWrapper.LOW_TICK_SCALE)
+ .compose()
+ assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
+ }
+
+ @Test
+ fun vibrate_for_drag_bump() {
+ underTest.vibrateForDragBump()
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
+ val expectedEffect =
+ VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_LOW_TICK, VibratorWrapper.DRAG_BUMP_SCALE)
+ .compose()
+ assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
+ }
+
+ @Test
+ fun vibrate_for_drag_commit() {
+ underTest.vibrateForDragCommit()
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
+ val expectedEffect =
+ VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_TICK, VibratorWrapper.DRAG_COMMIT_SCALE)
+ .compose()
+ assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect)
+ }
+
+ @Test
+ fun vibrate_for_drag_texture() {
+ SystemClock.setCurrentTimeMillis(40000)
+
+ underTest.vibrateForDragTexture()
+
+ awaitTasksCompleted()
+ verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS))
+ assertThat(vibrationEffectCaptor.value).isEqualTo(VibratorWrapper.getDragEffect())
+ }
+
+ @Test
+ fun vibrate_for_drag_texture_within_time_window_noOp() {
+ SystemClock.setCurrentTimeMillis(40000)
+ underTest.vibrateForDragTexture()
+ awaitTasksCompleted()
+ reset(vibrator)
+
+ underTest.vibrateForDragTexture()
+
+ verifyNoMoreInteractions(vibrator)
+ }
+
+ @Test
+ fun haptic_feedback_disabled_no_vibrate() {
+ `when`(vibrator.hasVibrator()).thenReturn(false)
+ underTest = VibratorWrapper(vibrator, settingsCache)
+
+ underTest.vibrate(OVERVIEW_HAPTIC)
+
+ awaitTasksCompleted()
+ verify(vibrator, never())
+ .vibrate(any(VibrationEffect::class.java), any(AudioAttributes::class.java))
+ }
+
+ @Test
+ fun cancel_vibrate() {
+ underTest.cancelVibrate()
+
+ awaitTasksCompleted()
+ verify(vibrator).cancel()
+ }
+
+ private fun awaitTasksCompleted() {
+ Executors.UI_HELPER_EXECUTOR.submit<Any> { null }.get()
+ }
+}