Merge "Create parcelable VibratorInfo to expose HAL profile"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0ba049d769
@@ -18,10 +18,12 @@ package android.os;
|
||||
|
||||
import android.os.CombinedVibrationEffect;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibratorInfo;
|
||||
|
||||
/** {@hide} */
|
||||
interface IVibratorManagerService {
|
||||
int[] getVibratorIds();
|
||||
VibratorInfo getVibratorInfo(int vibratorId);
|
||||
boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
|
||||
in CombinedVibrationEffect effect, in VibrationAttributes attributes);
|
||||
void vibrate(int uid, String opPkg, in CombinedVibrationEffect effect,
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.os;
|
||||
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.IVibratorStateListener;
|
||||
|
||||
/** {@hide} */
|
||||
@@ -25,11 +26,10 @@ interface IVibratorService
|
||||
{
|
||||
boolean hasVibrator();
|
||||
boolean isVibrating();
|
||||
VibratorInfo getVibratorInfo();
|
||||
boolean registerVibratorStateListener(in IVibratorStateListener listener);
|
||||
boolean unregisterVibratorStateListener(in IVibratorStateListener listener);
|
||||
boolean hasAmplitudeControl();
|
||||
int[] areEffectsSupported(in int[] effectIds);
|
||||
boolean[] arePrimitivesSupported(in int[] primitiveIds);
|
||||
void vibrate(int uid, String opPkg, in VibrationEffect effect,
|
||||
in VibrationAttributes attributes, String reason, IBinder token);
|
||||
void cancelVibrate(IBinder token);
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.os;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.media.AudioAttributes;
|
||||
@@ -39,8 +40,11 @@ public class SystemVibrator extends Vibrator {
|
||||
|
||||
private final IVibratorService mService;
|
||||
private final IVibratorManagerService mManagerService;
|
||||
private final Object mLock = new Object();
|
||||
private final Binder mToken = new Binder();
|
||||
private final Context mContext;
|
||||
@GuardedBy("mLock")
|
||||
private VibratorInfo mVibratorInfo;
|
||||
|
||||
@GuardedBy("mDelegates")
|
||||
private final ArrayMap<OnVibratorStateChangedListener,
|
||||
@@ -242,23 +246,26 @@ public class SystemVibrator extends Vibrator {
|
||||
|
||||
@Override
|
||||
public int[] areEffectsSupported(@VibrationEffect.EffectType int... effectIds) {
|
||||
try {
|
||||
return mService.areEffectsSupported(effectIds);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to query effect support");
|
||||
throw e.rethrowAsRuntimeException();
|
||||
VibratorInfo vibratorInfo = getVibratorInfo();
|
||||
int[] supported = new int[effectIds.length];
|
||||
for (int i = 0; i < effectIds.length; i++) {
|
||||
supported[i] = vibratorInfo == null
|
||||
? Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN
|
||||
: vibratorInfo.isEffectSupported(effectIds[i]);
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] arePrimitivesSupported(
|
||||
@NonNull @VibrationEffect.Composition.Primitive int... primitiveIds) {
|
||||
try {
|
||||
return mService.arePrimitivesSupported(primitiveIds);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to query effect support");
|
||||
throw e.rethrowAsRuntimeException();
|
||||
VibratorInfo vibratorInfo = getVibratorInfo();
|
||||
boolean[] supported = new boolean[primitiveIds.length];
|
||||
for (int i = 0; i < primitiveIds.length; i++) {
|
||||
supported[i] = vibratorInfo == null
|
||||
? false : vibratorInfo.isPrimitiveSupported(primitiveIds[i]);
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -272,4 +279,22 @@ public class SystemVibrator extends Vibrator {
|
||||
Log.w(TAG, "Failed to cancel vibration.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VibratorInfo getVibratorInfo() {
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (mVibratorInfo != null) {
|
||||
return mVibratorInfo;
|
||||
}
|
||||
if (mService == null) {
|
||||
return null;
|
||||
}
|
||||
return mVibratorInfo = mService.getVibratorInfo();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to query vibrator info");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,6 +476,28 @@ public abstract class VibrationEffect implements Parcelable {
|
||||
return a * fx;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static String effectIdToString(int effectId) {
|
||||
switch (effectId) {
|
||||
case EFFECT_CLICK:
|
||||
return "CLICK";
|
||||
case EFFECT_TICK:
|
||||
return "TICK";
|
||||
case EFFECT_HEAVY_CLICK:
|
||||
return "HEAVY_CLICK";
|
||||
case EFFECT_DOUBLE_CLICK:
|
||||
return "DOUBLE_CLICK";
|
||||
case EFFECT_POP:
|
||||
return "POP";
|
||||
case EFFECT_THUD:
|
||||
return "THUD";
|
||||
case EFFECT_TEXTURE_TICK:
|
||||
return "TEXTURE_TICK";
|
||||
default:
|
||||
return Integer.toString(effectId);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public static class OneShot extends VibrationEffect implements Parcelable {
|
||||
@@ -1201,10 +1223,8 @@ public abstract class VibrationEffect implements Parcelable {
|
||||
return "PRIMITIVE_QUICK_FALL";
|
||||
case PRIMITIVE_TICK:
|
||||
return "PRIMITIVE_TICK";
|
||||
|
||||
default:
|
||||
return Integer.toString(id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
core/java/android/os/VibratorInfo.aidl
Normal file
19
core/java/android/os/VibratorInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 android.os;
|
||||
|
||||
parcelable VibratorInfo;
|
||||
229
core/java/android/os/VibratorInfo.java
Normal file
229
core/java/android/os/VibratorInfo.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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 android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A VibratorInfo describes the capabilities of a {@link Vibrator}.
|
||||
*
|
||||
* This description includes its capabilities, list of supported effects and composition primitives.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class VibratorInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* Capability to set amplitude values to vibrations.
|
||||
* @hide
|
||||
*/
|
||||
// Internally this maps to the HAL constant IVibrator::CAP_AMPLITUDE_CONTROL
|
||||
public static final int CAPABILITY_AMPLITUDE_CONTROL = 4;
|
||||
|
||||
/**
|
||||
* Capability to compose primitives into a single effect.
|
||||
* @hide
|
||||
*/
|
||||
// Internally this maps to the HAL constant IVibrator::CAP_COMPOSE_EFFECTS
|
||||
public static final int CAPABILITY_COMPOSE_EFFECTS = 32;
|
||||
|
||||
private final int mId;
|
||||
private final long mCapabilities;
|
||||
@Nullable
|
||||
private final SparseBooleanArray mSupportedEffects;
|
||||
@Nullable
|
||||
private final SparseBooleanArray mSupportedPrimitives;
|
||||
|
||||
VibratorInfo(Parcel in) {
|
||||
mId = in.readInt();
|
||||
mCapabilities = in.readLong();
|
||||
mSupportedEffects = in.readSparseBooleanArray();
|
||||
mSupportedPrimitives = in.readSparseBooleanArray();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public VibratorInfo(int id, long capabilities, int[] supportedEffects,
|
||||
int[] supportedPrimitives) {
|
||||
mId = id;
|
||||
mCapabilities = capabilities;
|
||||
mSupportedEffects = toSparseBooleanArray(supportedEffects);
|
||||
mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mId);
|
||||
dest.writeLong(mCapabilities);
|
||||
dest.writeSparseBooleanArray(mSupportedEffects);
|
||||
dest.writeSparseBooleanArray(mSupportedPrimitives);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof VibratorInfo)) {
|
||||
return false;
|
||||
}
|
||||
VibratorInfo that = (VibratorInfo) o;
|
||||
return mId == that.mId && mCapabilities == that.mCapabilities
|
||||
&& Objects.equals(mSupportedEffects, that.mSupportedEffects)
|
||||
&& Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VibratorInfo{"
|
||||
+ "mId=" + mId
|
||||
+ ", mCapabilities=" + Arrays.toString(getCapabilitiesNames())
|
||||
+ ", mCapabilities flags=" + mCapabilities
|
||||
+ ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
|
||||
+ ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/** Return the id of this vibrator. */
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the vibrator has amplitude control.
|
||||
*
|
||||
* @return True if the hardware can control the amplitude of the vibrations, otherwise false.
|
||||
*/
|
||||
public boolean hasAmplitudeControl() {
|
||||
return hasCapability(CAPABILITY_AMPLITUDE_CONTROL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query whether the vibrator supports the given effect.
|
||||
*
|
||||
* @param effectId Which effects to query for.
|
||||
* @return {@link Vibrator#VIBRATION_EFFECT_SUPPORT_YES} if the effect is supported,
|
||||
* {@link Vibrator#VIBRATION_EFFECT_SUPPORT_NO} if it isn't supported, or
|
||||
* {@link Vibrator#VIBRATION_EFFECT_SUPPORT_UNKNOWN} if the system can't determine whether it's
|
||||
* supported or not.
|
||||
*/
|
||||
@Vibrator.VibrationEffectSupport
|
||||
public int isEffectSupported(@VibrationEffect.EffectType int effectId) {
|
||||
if (mSupportedEffects == null) {
|
||||
return Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN;
|
||||
}
|
||||
return mSupportedEffects.get(effectId, false) ? Vibrator.VIBRATION_EFFECT_SUPPORT_YES
|
||||
: Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query whether the vibrator supports the given primitive.
|
||||
*
|
||||
* @param primitiveId Which primitives to query for.
|
||||
* @return Whether the primitive is supported.
|
||||
*/
|
||||
public boolean isPrimitiveSupported(@VibrationEffect.Composition.Primitive int primitiveId) {
|
||||
return hasCapability(CAPABILITY_COMPOSE_EFFECTS) && mSupportedPrimitives != null
|
||||
&& mSupportedPrimitives.get(primitiveId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check against this vibrator capabilities.
|
||||
*
|
||||
* @param capability one of IVibrator.CAP_*
|
||||
* @return true if this vibrator has this capability, false otherwise
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasCapability(long capability) {
|
||||
return (mCapabilities & capability) == capability;
|
||||
}
|
||||
|
||||
private String[] getCapabilitiesNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
if (hasCapability(CAPABILITY_AMPLITUDE_CONTROL)) {
|
||||
names.add("AMPLITUDE_CONTROL");
|
||||
}
|
||||
if (hasCapability(CAPABILITY_COMPOSE_EFFECTS)) {
|
||||
names.add("COMPOSE_EFFECTS");
|
||||
}
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
private String[] getSupportedEffectsNames() {
|
||||
if (mSupportedEffects == null) {
|
||||
return new String[0];
|
||||
}
|
||||
String[] names = new String[mSupportedEffects.size()];
|
||||
for (int i = 0; i < mSupportedEffects.size(); i++) {
|
||||
names[i] = VibrationEffect.effectIdToString(mSupportedEffects.keyAt(i));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private String[] getSupportedPrimitivesNames() {
|
||||
if (mSupportedPrimitives == null) {
|
||||
return new String[0];
|
||||
}
|
||||
String[] names = new String[mSupportedPrimitives.size()];
|
||||
for (int i = 0; i < mSupportedPrimitives.size(); i++) {
|
||||
names[i] = VibrationEffect.Composition.primitiveToString(mSupportedPrimitives.keyAt(i));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SparseBooleanArray toSparseBooleanArray(int[] values) {
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
SparseBooleanArray array = new SparseBooleanArray();
|
||||
for (int value : values) {
|
||||
array.put(value, true);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<VibratorInfo> CREATOR =
|
||||
new Creator<VibratorInfo>() {
|
||||
@Override
|
||||
public VibratorInfo createFromParcel(Parcel in) {
|
||||
return new VibratorInfo(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VibratorInfo[] newArray(int size) {
|
||||
return new VibratorInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
112
core/tests/coretests/src/android/os/VibratorInfoTest.java
Normal file
112
core/tests/coretests/src/android/os/VibratorInfoTest.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 android.os;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(JUnit4.class)
|
||||
public class VibratorInfoTest {
|
||||
|
||||
@Test
|
||||
public void testHasAmplitudeControl() {
|
||||
assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl());
|
||||
assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS
|
||||
| VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL).hasAmplitudeControl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasCapabilities() {
|
||||
assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
|
||||
.hasCapability(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS));
|
||||
assertFalse(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
|
||||
.hasCapability(VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEffectSupported() {
|
||||
VibratorInfo info = new VibratorInfo(/* id= */ 0, /* capabilities= */0,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null);
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
|
||||
createInfo(/* capabilities= */ 0).isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPrimitiveSupported() {
|
||||
VibratorInfo info = new VibratorInfo(/* id= */ 0, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
|
||||
|
||||
// Returns false when there is no compose capability.
|
||||
info = new VibratorInfo(/* id= */ 0, /* capabilities= */ 0,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
VibratorInfo empty = new VibratorInfo(1, 0, null, null);
|
||||
VibratorInfo complete = new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
|
||||
assertEquals(complete, complete);
|
||||
assertEquals(complete, new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}));
|
||||
|
||||
assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
|
||||
new int[]{}, new int[]{})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
VibratorInfo original = new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
original.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
VibratorInfo restored = VibratorInfo.CREATOR.createFromParcel(parcel);
|
||||
assertEquals(original, restored);
|
||||
}
|
||||
|
||||
private static VibratorInfo createInfo(long capabilities) {
|
||||
return new VibratorInfo(/* id= */ 0, capabilities, null, null);
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,26 @@ public class VibratorTest {
|
||||
mVibratorSpy = spy(InstrumentationRegistry.getContext().getSystemService(Vibrator.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_returnsArrayOfSameSize() {
|
||||
assertEquals(0, mVibratorSpy.areEffectsSupported(new int[0]).length);
|
||||
assertEquals(1,
|
||||
mVibratorSpy.areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}).length);
|
||||
assertEquals(2,
|
||||
mVibratorSpy.areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK,
|
||||
VibrationEffect.EFFECT_TICK}).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_returnsArrayOfSameSize() {
|
||||
assertEquals(0, mVibratorSpy.arePrimitivesSupported(new int[0]).length);
|
||||
assertEquals(1, mVibratorSpy.arePrimitivesSupported(
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}).length);
|
||||
assertEquals(2, mVibratorSpy.arePrimitivesSupported(
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
|
||||
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.os.Trace;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
@@ -165,6 +166,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@Nullable
|
||||
public VibratorInfo getVibratorInfo(int vibratorId) {
|
||||
VibratorController controller = mVibrators.get(vibratorId);
|
||||
return controller == null ? null : controller.getVibratorInfo();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public int[] getVibratorIds() {
|
||||
return Arrays.copyOf(mVibratorIds, mVibratorIds.length);
|
||||
|
||||
@@ -51,6 +51,7 @@ import android.os.Trace;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
@@ -343,6 +344,11 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
return mVibratorController.isVibrating();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public VibratorInfo getVibratorInfo() {
|
||||
return mVibratorController.getVibratorInfo();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean registerVibratorStateListener(IVibratorStateListener listener) {
|
||||
if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
|
||||
@@ -367,16 +373,6 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|| mVibratorController.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public int[] areEffectsSupported(int[] effectIds) {
|
||||
return mVibratorController.areEffectsSupported(effectIds);
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean[] arePrimitivesSupported(int[] primitiveIds) {
|
||||
return mVibratorController.arePrimitivesSupported(primitiveIds);
|
||||
}
|
||||
|
||||
private void verifyIncomingUid(int uid) {
|
||||
if (uid == Binder.getCallingUid()) {
|
||||
return;
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.os.IVibratorStateListener;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -31,10 +31,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** Controls a single vibrator. */
|
||||
// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
|
||||
public final class VibratorController {
|
||||
@@ -42,12 +38,7 @@ public final class VibratorController {
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final NativeWrapper mNativeWrapper;
|
||||
private final int mVibratorId;
|
||||
private final long mCapabilities;
|
||||
@Nullable
|
||||
private final Set<Integer> mSupportedEffects;
|
||||
@Nullable
|
||||
private final Set<Integer> mSupportedPrimitives;
|
||||
private final VibratorInfo mVibratorInfo;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
|
||||
@@ -115,13 +106,11 @@ public final class VibratorController {
|
||||
@VisibleForTesting
|
||||
public VibratorController(int vibratorId, OnVibrationCompleteListener listener,
|
||||
NativeWrapper nativeWrapper) {
|
||||
mVibratorId = vibratorId;
|
||||
mNativeWrapper = nativeWrapper;
|
||||
mNativeWrapper.init(vibratorId, listener);
|
||||
|
||||
nativeWrapper.init(vibratorId, listener);
|
||||
mCapabilities = nativeWrapper.getCapabilities();
|
||||
mSupportedEffects = asSet(nativeWrapper.getSupportedEffects());
|
||||
mSupportedPrimitives = asSet(nativeWrapper.getSupportedPrimitives());
|
||||
mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(),
|
||||
nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives());
|
||||
}
|
||||
|
||||
/** Register state listener for this vibrator. */
|
||||
@@ -153,9 +142,9 @@ public final class VibratorController {
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the id of the vibrator controlled by this instance. */
|
||||
public int getVibratorId() {
|
||||
return mVibratorId;
|
||||
/** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */
|
||||
public VibratorInfo getVibratorInfo() {
|
||||
return mVibratorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,43 +173,7 @@ public final class VibratorController {
|
||||
* @return true if this vibrator has this capability, false otherwise
|
||||
*/
|
||||
public boolean hasCapability(long capability) {
|
||||
return (mCapabilities & capability) == capability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check against this vibrator supported effects.
|
||||
*
|
||||
* @param effectIds list of effects, one of VibrationEffect.EFFECT_*
|
||||
* @return one entry per requested effectId, with one of Vibrator.VIBRATION_EFFECT_SUPPORT_*
|
||||
*/
|
||||
public int[] areEffectsSupported(int[] effectIds) {
|
||||
int[] supported = new int[effectIds.length];
|
||||
if (mSupportedEffects == null) {
|
||||
Arrays.fill(supported, Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN);
|
||||
} else {
|
||||
for (int i = 0; i < effectIds.length; i++) {
|
||||
supported[i] = mSupportedEffects.contains(effectIds[i])
|
||||
? Vibrator.VIBRATION_EFFECT_SUPPORT_YES
|
||||
: Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check against this vibrator supported primitives.
|
||||
*
|
||||
* @param primitiveIds list of primitives, one of VibrationEffect.Composition.EFFECT_*
|
||||
* @return one entry per requested primitiveId, with true if it is supported
|
||||
*/
|
||||
public boolean[] arePrimitivesSupported(int[] primitiveIds) {
|
||||
boolean[] supported = new boolean[primitiveIds.length];
|
||||
if (mSupportedPrimitives != null && hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
|
||||
for (int i = 0; i < primitiveIds.length; i++) {
|
||||
supported[i] = mSupportedPrimitives.contains(primitiveIds[i]);
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
return mVibratorInfo.hasCapability(capability);
|
||||
}
|
||||
|
||||
/** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
|
||||
@@ -234,7 +187,7 @@ public final class VibratorController {
|
||||
* <p>This will affect the state of {@link #isUnderExternalControl()}.
|
||||
*/
|
||||
public void setExternalControl(boolean externalControl) {
|
||||
if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
|
||||
if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
|
||||
return;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
@@ -248,7 +201,7 @@ public final class VibratorController {
|
||||
* if given {@code effect} is {@code null}.
|
||||
*/
|
||||
public void updateAlwaysOn(int id, @Nullable VibrationEffect.Prebaked effect) {
|
||||
if (!hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
|
||||
if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
|
||||
return;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
@@ -263,7 +216,7 @@ public final class VibratorController {
|
||||
/** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
|
||||
public void setAmplitude(int amplitude) {
|
||||
synchronized (mLock) {
|
||||
if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
|
||||
if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
|
||||
mNativeWrapper.setAmplitude(amplitude);
|
||||
}
|
||||
}
|
||||
@@ -306,7 +259,7 @@ public final class VibratorController {
|
||||
* <p>This will affect the state of {@link #isVibrating()}.
|
||||
*/
|
||||
public void on(VibrationEffect.Composed effect, long vibrationId) {
|
||||
if (!hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
|
||||
if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
|
||||
return;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
@@ -327,10 +280,7 @@ public final class VibratorController {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VibratorController{"
|
||||
+ "mVibratorId=" + mVibratorId
|
||||
+ ", mCapabilities=" + mCapabilities
|
||||
+ ", mSupportedEffects=" + mSupportedEffects
|
||||
+ ", mSupportedPrimitives=" + mSupportedPrimitives
|
||||
+ "mVibratorInfo=" + mVibratorInfo
|
||||
+ ", mIsVibrating=" + mIsVibrating
|
||||
+ ", mIsUnderExternalControl=" + mIsUnderExternalControl
|
||||
+ ", mVibratorStateListeners count="
|
||||
@@ -375,18 +325,6 @@ public final class VibratorController {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Set<Integer> asSet(int[] values) {
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
HashSet<Integer> set = new HashSet<>();
|
||||
for (int value : values) {
|
||||
set.add(value);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/** Wrapper around the static-native methods of {@link VibratorController} for tests. */
|
||||
@VisibleForTesting
|
||||
public static class NativeWrapper {
|
||||
|
||||
@@ -19,7 +19,10 @@ package com.android.server;
|
||||
import static com.android.server.testutils.TestUtils.assertExpectException;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -38,6 +41,8 @@ import android.os.PowerSaveState;
|
||||
import android.os.Process;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
@@ -134,17 +139,48 @@ public class VibratorManagerServiceTest {
|
||||
|
||||
@Test
|
||||
public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() {
|
||||
mNativeWrappers.put(1, mockVibrator(0));
|
||||
mNativeWrappers.put(2, mockVibrator(0));
|
||||
mNativeWrappers.put(1, mockVibrator(/* capabilities= */ 0));
|
||||
mNativeWrappers.put(2, mockVibrator(/* capabilities= */ 0));
|
||||
when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{2, 1});
|
||||
assertArrayEquals(new int[]{2, 1}, createService().getVibratorIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVibratorInfo_withMissingVibratorId_returnsNull() {
|
||||
mockVibrators(mockVibrator(/* capabilities= */ 0));
|
||||
assertNull(createService().getVibratorInfo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVibratorInfo_withExistingVibratorId_returnsHalInfoForVibrator() {
|
||||
VibratorController.NativeWrapper vibratorMock = mockVibrator(
|
||||
IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||
when(vibratorMock.getSupportedEffects()).thenReturn(
|
||||
new int[]{VibrationEffect.EFFECT_CLICK});
|
||||
when(vibratorMock.getSupportedPrimitives()).thenReturn(
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
mNativeWrappers.put(1, vibratorMock);
|
||||
when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{1});
|
||||
VibratorInfo info = createService().getVibratorInfo(1);
|
||||
|
||||
assertNotNull(info);
|
||||
assertEquals(1, info.getId());
|
||||
assertTrue(info.hasAmplitudeControl());
|
||||
assertTrue(info.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
|
||||
assertFalse(info.hasCapability(IVibrator.CAP_ON_CALLBACK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAlwaysOnEffect_withMono_enablesAlwaysOnEffectToAllVibratorsWithCapability() {
|
||||
VibratorController.NativeWrapper[] vibratorMocks = new VibratorController.NativeWrapper[] {
|
||||
VibratorController.NativeWrapper[] vibratorMocks = new VibratorController.NativeWrapper[]{
|
||||
mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
|
||||
mockVibrator(0),
|
||||
mockVibrator(/* capabilities= */ 0),
|
||||
mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
|
||||
};
|
||||
mockVibrators(vibratorMocks);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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;
|
||||
@@ -62,6 +61,7 @@ import android.os.UserHandle;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorInfo;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
@@ -235,56 +235,21 @@ public class VibratorServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
|
||||
when(mNativeWrapperMock.getSupportedEffects()).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};
|
||||
|
||||
public void getVibratorInfo_returnsSameInfoFromNative() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||
when(mNativeWrapperMock.getSupportedEffects())
|
||||
.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_withNullResultFromNative_returnsAlwaysFalse() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
when(mNativeWrapperMock.getSupportedPrimitives()).thenReturn(null);
|
||||
|
||||
assertArrayEquals(new boolean[]{false, false},
|
||||
createService().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withSomeSupportedPrimitives_returnsBasedOnNativeResult() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
when(mNativeWrapperMock.getSupportedPrimitives())
|
||||
.thenReturn(new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
|
||||
assertArrayEquals(new boolean[]{true, false},
|
||||
createService().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
|
||||
}));
|
||||
VibratorInfo info = createService().getVibratorInfo();
|
||||
assertTrue(info.hasAmplitudeControl());
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -38,7 +37,6 @@ import android.hardware.vibrator.IVibrator;
|
||||
import android.os.IBinder;
|
||||
import android.os.IVibratorStateListener;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
@@ -100,7 +98,7 @@ public class VibratorControllerTest {
|
||||
public void createController_initializesNativeWrapper() {
|
||||
int vibratorId = 13;
|
||||
VibratorController controller = createController(vibratorId);
|
||||
assertEquals(vibratorId, controller.getVibratorId());
|
||||
assertEquals(vibratorId, controller.getVibratorInfo().getId());
|
||||
verify(mNativeWrapperMock).init(eq(vibratorId), notNull());
|
||||
}
|
||||
|
||||
@@ -131,59 +129,6 @@ public class VibratorControllerTest {
|
||||
assertFalse(createController().hasCapability(IVibrator.CAP_ON_CALLBACK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
|
||||
when(mNativeWrapperMock.getSupportedEffects()).thenReturn(null);
|
||||
assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
|
||||
createController().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
|
||||
int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
|
||||
|
||||
when(mNativeWrapperMock.getSupportedEffects())
|
||||
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
|
||||
assertArrayEquals(
|
||||
new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
Vibrator.VIBRATION_EFFECT_SUPPORT_NO},
|
||||
createController().areEffectsSupported(effects));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withoutComposeCapability_returnsAlwaysFalse() {
|
||||
assertArrayEquals(new boolean[]{false, false},
|
||||
createController().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_TICK
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withNullResultFromNative_returnsAlwaysFalse() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
when(mNativeWrapperMock.getSupportedPrimitives()).thenReturn(null);
|
||||
|
||||
assertArrayEquals(new boolean[]{false, false},
|
||||
createController().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arePrimitivesSupported_withSomeSupportedPrimitives_returnsBasedOnNativeResult() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
when(mNativeWrapperMock.getSupportedPrimitives())
|
||||
.thenReturn(new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
|
||||
assertArrayEquals(new boolean[]{true, false},
|
||||
createController().arePrimitivesSupported(new int[]{
|
||||
VibrationEffect.Composition.PRIMITIVE_CLICK,
|
||||
VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExternalControl_withCapability_enablesExternalControl() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
|
||||
|
||||
Reference in New Issue
Block a user