Create VibratorServiceTest
Add basic tests to cover main interaction between VibratorService.java and it's native methods, which will be changed after vibrator HAL controller is integrated. Bug: 153418251 Test: atest FrameworksServicesTests:VibratorServiceTest Change-Id: Ib0122a67d08e380501b71a8652bd4202aae7c002
This commit is contained in:
@@ -43,6 +43,7 @@ import android.os.IBinder;
|
||||
import android.os.IExternalVibratorService;
|
||||
import android.os.IVibratorService;
|
||||
import android.os.IVibratorStateListener;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.ServiceType;
|
||||
import android.os.PowerManagerInternal;
|
||||
@@ -70,6 +71,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
@@ -134,7 +136,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private final SparseArray<VibrationEffect> mFallbackEffects;
|
||||
private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
|
||||
private final WorkSource mTmpWorkSource = new WorkSource();
|
||||
private final Handler mH = new Handler();
|
||||
private final Handler mH;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final Context mContext;
|
||||
@@ -147,6 +149,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private Vibrator mVibrator;
|
||||
private SettingsObserver mSettingObserver;
|
||||
|
||||
private final NativeWrapper mNativeWrapper;
|
||||
private volatile VibrateThread mThread;
|
||||
|
||||
// mInputDeviceVibrators lock should be acquired after mLock, if both are
|
||||
@@ -208,7 +211,12 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
};
|
||||
|
||||
private class Vibration implements IBinder.DeathRecipient {
|
||||
/**
|
||||
* Holder for a vibration to be played. This class can be shared with native methods for
|
||||
* hardware callback support.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public final class Vibration implements IBinder.DeathRecipient {
|
||||
public final IBinder token;
|
||||
// Start time in CLOCK_BOOTTIME base.
|
||||
public final long startTime;
|
||||
@@ -248,9 +256,9 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// Called by native
|
||||
@SuppressWarnings("unused")
|
||||
private void onComplete() {
|
||||
/** Callback for when vibration is complete, to be called by native. */
|
||||
@VisibleForTesting
|
||||
public void onComplete() {
|
||||
synchronized (mLock) {
|
||||
if (this == mCurrentVibration) {
|
||||
doCancelVibrateLocked();
|
||||
@@ -354,15 +362,23 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
|
||||
VibratorService(Context context) {
|
||||
vibratorInit();
|
||||
this(context, new Injector());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
VibratorService(Context context, Injector injector) {
|
||||
mNativeWrapper = injector.getNativeWrapper();
|
||||
mH = injector.createHandler(Looper.myLooper());
|
||||
|
||||
mNativeWrapper.vibratorInit();
|
||||
// Reset the hardware to a default state, in case this is a runtime
|
||||
// restart instead of a fresh boot.
|
||||
vibratorOff();
|
||||
mNativeWrapper.vibratorOff();
|
||||
|
||||
mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
|
||||
mSupportsExternalControl = vibratorSupportsExternalControl();
|
||||
mSupportedEffects = asList(vibratorGetSupportedEffects());
|
||||
mCapabilities = vibratorGetCapabilities();
|
||||
mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
|
||||
mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
|
||||
mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
|
||||
mCapabilities = mNativeWrapper.vibratorGetCapabilities();
|
||||
|
||||
mContext = context;
|
||||
PowerManager pm = context.getSystemService(PowerManager.class);
|
||||
@@ -419,7 +435,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
|
||||
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
|
||||
|
||||
ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
|
||||
injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
|
||||
}
|
||||
|
||||
private VibrationEffect createEffectFromResource(int resId) {
|
||||
@@ -642,7 +658,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
if (effect == null) {
|
||||
synchronized (mLock) {
|
||||
mAlwaysOnEffects.delete(alwaysOnId);
|
||||
vibratorAlwaysOnDisable(alwaysOnId);
|
||||
mNativeWrapper.vibratorAlwaysOnDisable(alwaysOnId);
|
||||
}
|
||||
} else {
|
||||
if (!verifyVibrationEffect(effect)) {
|
||||
@@ -1198,11 +1214,11 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private void updateAlwaysOnLocked(int id, Vibration vib) {
|
||||
final int intensity = getCurrentIntensityLocked(vib);
|
||||
if (!shouldVibrate(vib, intensity)) {
|
||||
vibratorAlwaysOnDisable(id);
|
||||
mNativeWrapper.vibratorAlwaysOnDisable(id);
|
||||
} else {
|
||||
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
|
||||
final int strength = intensityToEffectStrength(intensity);
|
||||
vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
|
||||
mNativeWrapper.vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,7 +1254,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
//synchronized (mInputDeviceVibrators) {
|
||||
// return !mInputDeviceVibrators.isEmpty() || vibratorExists();
|
||||
//}
|
||||
return vibratorExists();
|
||||
return mNativeWrapper.vibratorExists();
|
||||
}
|
||||
|
||||
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
|
||||
@@ -1262,7 +1278,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
// Note: ordering is important here! Many haptic drivers will reset their
|
||||
// amplitude when enabled, so we always have to enable first, then set the
|
||||
// amplitude.
|
||||
vibratorOn(millis);
|
||||
mNativeWrapper.vibratorOn(millis);
|
||||
doVibratorSetAmplitude(amplitude);
|
||||
}
|
||||
}
|
||||
@@ -1273,7 +1289,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
private void doVibratorSetAmplitude(int amplitude) {
|
||||
if (mSupportsAmplitudeControl) {
|
||||
vibratorSetAmplitude(amplitude);
|
||||
mNativeWrapper.vibratorSetAmplitude(amplitude);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,7 +1307,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mInputDeviceVibrators.get(i).cancel();
|
||||
}
|
||||
} else {
|
||||
vibratorOff();
|
||||
mNativeWrapper.vibratorOff();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -1310,7 +1326,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
// Input devices don't support prebaked effect, so skip trying it with them.
|
||||
if (!usingInputDeviceVibrators) {
|
||||
long duration = vibratorPerformEffect(prebaked.getId(),
|
||||
long duration = mNativeWrapper.vibratorPerformEffect(prebaked.getId(),
|
||||
prebaked.getEffectStrength(), vib,
|
||||
hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
|
||||
long timeout = duration;
|
||||
@@ -1363,7 +1379,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
PrimitiveEffect[] primitiveEffects =
|
||||
composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
|
||||
vibratorPerformComposedEffect(primitiveEffects, vib);
|
||||
mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
|
||||
|
||||
// Composed effects don't actually give us an estimated duration, so we just guess here.
|
||||
noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
|
||||
@@ -1454,7 +1470,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
mVibratorUnderExternalControl = externalControl;
|
||||
vibratorSetExternalControl(externalControl);
|
||||
mNativeWrapper.vibratorSetExternalControl(externalControl);
|
||||
}
|
||||
|
||||
private void dumpInternal(PrintWriter pw) {
|
||||
@@ -1688,6 +1704,100 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrapper around the static-native methods of {@link VibratorService} for tests. */
|
||||
@VisibleForTesting
|
||||
public static class NativeWrapper {
|
||||
|
||||
/** Checks if vibrator exists on device. */
|
||||
public boolean vibratorExists() {
|
||||
return VibratorService.vibratorExists();
|
||||
}
|
||||
|
||||
/** Initializes connection to vibrator HAL service. */
|
||||
public void vibratorInit() {
|
||||
VibratorService.vibratorInit();
|
||||
}
|
||||
|
||||
/** Turns vibrator on for given time. */
|
||||
public void vibratorOn(long milliseconds) {
|
||||
VibratorService.vibratorOn(milliseconds);
|
||||
}
|
||||
|
||||
/** Turns vibrator off. */
|
||||
public void vibratorOff() {
|
||||
VibratorService.vibratorOff();
|
||||
}
|
||||
|
||||
/** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
|
||||
public boolean vibratorSupportsAmplitudeControl() {
|
||||
return VibratorService.vibratorSupportsAmplitudeControl();
|
||||
}
|
||||
|
||||
/** Sets the amplitude for the vibrator to run. */
|
||||
public void vibratorSetAmplitude(int amplitude) {
|
||||
VibratorService.vibratorSetAmplitude(amplitude);
|
||||
}
|
||||
|
||||
/** Returns all predefined effects supported by the device vibrator. */
|
||||
public int[] vibratorGetSupportedEffects() {
|
||||
return VibratorService.vibratorGetSupportedEffects();
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported effects. */
|
||||
public long vibratorPerformEffect(long effect, long strength, Vibration vibration,
|
||||
boolean withCallback) {
|
||||
return VibratorService.vibratorPerformEffect(effect, strength, vibration, withCallback);
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported composed effects. */
|
||||
public void vibratorPerformComposedEffect(
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
|
||||
VibratorService.vibratorPerformComposedEffect(effect, vibration);
|
||||
}
|
||||
|
||||
/** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
|
||||
public boolean vibratorSupportsExternalControl() {
|
||||
return VibratorService.vibratorSupportsExternalControl();
|
||||
}
|
||||
|
||||
/** Enabled the device vibrator to be controlled by another service. */
|
||||
public void vibratorSetExternalControl(boolean enabled) {
|
||||
VibratorService.vibratorSetExternalControl(enabled);
|
||||
}
|
||||
|
||||
/** Returns all capabilities of the device vibrator. */
|
||||
public long vibratorGetCapabilities() {
|
||||
return VibratorService.vibratorGetCapabilities();
|
||||
}
|
||||
|
||||
/** Enable always-on vibration with given id and effect. */
|
||||
public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
|
||||
VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
|
||||
}
|
||||
|
||||
/** Disable always-on vibration for given id. */
|
||||
public void vibratorAlwaysOnDisable(long id) {
|
||||
VibratorService.vibratorAlwaysOnDisable(id);
|
||||
}
|
||||
}
|
||||
|
||||
/** Point of injection for test dependencies */
|
||||
@VisibleForTesting
|
||||
static class Injector {
|
||||
|
||||
NativeWrapper getNativeWrapper() {
|
||||
return new NativeWrapper();
|
||||
}
|
||||
|
||||
Handler createHandler(Looper looper) {
|
||||
return new Handler(looper);
|
||||
}
|
||||
|
||||
void addService(String name, IBinder service) {
|
||||
ServiceManager.addService(name, service);
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
@@ -59,6 +59,7 @@ android_test {
|
||||
libs: [
|
||||
"android.hardware.power-java",
|
||||
"android.hardware.tv.cec-V1.0-java",
|
||||
"android.hardware.vibrator-java",
|
||||
"android.hidl.manager-V1.0-java",
|
||||
"android.test.mock",
|
||||
"android.test.base",
|
||||
|
||||
@@ -81,6 +81,9 @@
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
|
||||
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON"/>
|
||||
|
||||
<!-- Uses API introduced in O (26) -->
|
||||
<uses-sdk android:minSdkVersion="1"
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.server;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IVibratorStateListener;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManagerInternal;
|
||||
import android.os.Process;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/**
|
||||
* Tests for {@link VibratorService}.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksServicesTests:VibratorServiceTest
|
||||
*/
|
||||
@Presubmit
|
||||
public class VibratorServiceTest {
|
||||
|
||||
private static final int UID = Process.ROOT_UID;
|
||||
private static final String PACKAGE_NAME = "package";
|
||||
private static final VibrationAttributes ALARM_ATTRS =
|
||||
new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
|
||||
|
||||
@Rule public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Mock private PackageManagerInternal mPackageManagerInternalMock;
|
||||
@Mock private PowerManagerInternal mPowerManagerInternalMock;
|
||||
@Mock private VibratorService.NativeWrapper mNativeWrapperMock;
|
||||
@Mock private IVibratorStateListener mVibratorStateListenerMock;
|
||||
@Mock private IBinder mVibratorStateListenerBinderMock;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTestLooper = new TestLooper();
|
||||
|
||||
when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
|
||||
when(mPackageManagerInternalMock.getSystemUiServiceComponent())
|
||||
.thenReturn(new ComponentName("", ""));
|
||||
|
||||
addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
}
|
||||
|
||||
private VibratorService createService() {
|
||||
return new VibratorService(InstrumentationRegistry.getContext(),
|
||||
new VibratorService.Injector() {
|
||||
@Override
|
||||
VibratorService.NativeWrapper getNativeWrapper() {
|
||||
return mNativeWrapperMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
Handler createHandler(Looper looper) {
|
||||
return new Handler(mTestLooper.getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
void addService(String name, IBinder service) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createService_initializesNativeService() {
|
||||
createService();
|
||||
verify(mNativeWrapperMock).vibratorInit();
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasVibrator_withVibratorHalPresent_returnsTrue() {
|
||||
when(mNativeWrapperMock.vibratorExists()).thenReturn(true);
|
||||
assertTrue(createService().hasVibrator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasVibrator_withNoVibratorHalPresent_returnsFalse() {
|
||||
when(mNativeWrapperMock.vibratorExists()).thenReturn(false);
|
||||
assertFalse(createService().hasVibrator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
|
||||
when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
|
||||
assertTrue(createService().hasAmplitudeControl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
|
||||
when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
|
||||
assertFalse(createService().hasAmplitudeControl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
|
||||
when(mNativeWrapperMock.vibratorGetSupportedEffects()).thenReturn(null);
|
||||
assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
|
||||
createService().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
|
||||
int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
|
||||
|
||||
when(mNativeWrapperMock.vibratorGetSupportedEffects())
|
||||
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
|
||||
assertArrayEquals(
|
||||
new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
Vibrator.VIBRATION_EFFECT_SUPPORT_NO},
|
||||
createService().areEffectsSupported(effects));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withoutComposeCapability_returnsAlwaysFalse() {
|
||||
assertArrayEquals(new boolean[]{false, false},
|
||||
createService().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_TICK
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withComposeCapability_returnsAlwaysTrue() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
assertArrayEquals(new boolean[]{true, true},
|
||||
createService().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAlwaysOnEffect_withCapabilityAndValidEffect_enablesAlwaysOnEffect() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
|
||||
|
||||
assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
|
||||
VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
|
||||
verify(mNativeWrapperMock).vibratorAlwaysOnEnable(
|
||||
eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAlwaysOnEffect_withNonPrebakedEffect_ignoresEffect() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
|
||||
|
||||
assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
|
||||
VibrationEffect.createOneShot(100, 255), ALARM_ATTRS));
|
||||
verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
|
||||
verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAlwaysOnEffect_withNullEffect_disablesAlwaysOnEffect() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
|
||||
|
||||
assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
|
||||
verify(mNativeWrapperMock).vibratorAlwaysOnDisable(eq(1L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAlwaysOnEffect_withoutCapability_ignoresEffect() {
|
||||
assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
|
||||
VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
|
||||
verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
|
||||
verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
|
||||
when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(100, 128));
|
||||
assertTrue(service.isVibrating());
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L));
|
||||
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withOneShotAndNoAmplitudeControl_turnsVibratorOnAndIgnoresAmplitude() {
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(100, 128));
|
||||
assertTrue(service.isVibrating());
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L));
|
||||
verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withPrebaked_performsEffect() {
|
||||
when(mNativeWrapperMock.vibratorGetSupportedEffects())
|
||||
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
|
||||
any(VibratorService.Vibration.class), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withComposed_performsEffect() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
|
||||
.compose();
|
||||
vibrate(service, effect);
|
||||
|
||||
ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
|
||||
ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
primitivesCaptor.capture(), any(VibratorService.Vibration.class));
|
||||
|
||||
// Check all primitive effect fields are passed down to the HAL.
|
||||
assertEquals(1, primitivesCaptor.getValue().length);
|
||||
VibrationEffect.Composition.PrimitiveEffect primitive = primitivesCaptor.getValue()[0];
|
||||
assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.id);
|
||||
assertEquals(0.5f, primitive.scale, /* delta= */ 1e-2);
|
||||
assertEquals(10, primitive.delay);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withCallback_finishesVibrationWhenCallbackTriggered() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(), any(VibratorService.Vibration.class));
|
||||
|
||||
// Use vibration with delay so there is time for the callback to be triggered.
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
|
||||
.compose();
|
||||
vibrate(service, effect);
|
||||
|
||||
// Vibration canceled once before perform and once by native callback.
|
||||
verify(mNativeWrapperMock, times(2)).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(VibrationEffect.Composition.PrimitiveEffect[].class),
|
||||
any(VibratorService.Vibration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_whenBinderDies_cancelsVibration() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(), any(VibratorService.Vibration.class));
|
||||
|
||||
// Use vibration with delay so there is time for the callback to be triggered.
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
|
||||
.compose();
|
||||
vibrate(service, effect);
|
||||
|
||||
// Vibration canceled once before perform and once by native binder death.
|
||||
verify(mNativeWrapperMock, times(2)).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(VibrationEffect.Composition.PrimitiveEffect[].class),
|
||||
any(VibratorService.Vibration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelVibrate_withDeviceVibrating_callsVibratorOff() {
|
||||
VibratorService service = createService();
|
||||
vibrate(service, VibrationEffect.createOneShot(100, 128));
|
||||
assertTrue(service.isVibrating());
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
service.cancelVibrate(service);
|
||||
assertFalse(service.isVibrating());
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelVibrate_withDeviceNotVibrating_ignoresCall() {
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
service.cancelVibrate(service);
|
||||
assertFalse(service.isVibrating());
|
||||
verify(mNativeWrapperMock, never()).vibratorOff();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
|
||||
VibratorService service = createService();
|
||||
|
||||
service.registerVibratorStateListener(mVibratorStateListenerMock);
|
||||
verify(mVibratorStateListenerMock).onVibrating(false);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
verify(mVibratorStateListenerMock).onVibrating(true);
|
||||
|
||||
// Run the scheduled callback to finish one-shot vibration.
|
||||
mTestLooper.moveTimeForward(10);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(mVibratorStateListenerMock, times(2)).onVibrating(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
|
||||
VibratorService service = createService();
|
||||
|
||||
service.registerVibratorStateListener(mVibratorStateListenerMock);
|
||||
verify(mVibratorStateListenerMock).onVibrating(false);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(5, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
verify(mVibratorStateListenerMock).onVibrating(true);
|
||||
|
||||
service.unregisterVibratorStateListener(mVibratorStateListenerMock);
|
||||
Mockito.clearInvocations(mVibratorStateListenerMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
verifyNoMoreInteractions(mVibratorStateListenerMock);
|
||||
}
|
||||
|
||||
private void vibrate(VibratorService service, VibrationEffect effect) {
|
||||
service.vibrate(UID, PACKAGE_NAME, effect, ALARM_ATTRS, "some reason", service);
|
||||
}
|
||||
|
||||
private void mockVibratorCapabilities(int capabilities) {
|
||||
when(mNativeWrapperMock.vibratorGetCapabilities()).thenReturn((long) capabilities);
|
||||
}
|
||||
|
||||
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
|
||||
LocalServices.removeServiceForTest(clazz);
|
||||
LocalServices.addService(clazz, mock);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user