mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 18:58:19 +00:00
Merge "[Test Week] Add VibratorWrapperTest" into main
This commit is contained in:
@@ -31,6 +31,7 @@ import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
@@ -49,14 +50,14 @@ public class VibratorWrapper implements SafeCloseable {
|
||||
|
||||
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 class VibratorWrapper implements SafeCloseable {
|
||||
*/
|
||||
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 @@ public class VibratorWrapper implements SafeCloseable {
|
||||
|
||||
// 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 @@ public class VibratorWrapper implements SafeCloseable {
|
||||
@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 @@ public class VibratorWrapper implements SafeCloseable {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user