Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 834b65d8 authored by Lais Andrade's avatar Lais Andrade
Browse files

Move VibrationInfo initialization to cpp

Remove all individual vibrator info getter from the VibratorController
native wrapper and add a single getInfo that returns a complete instance
of VibratorInfo.

This is in preparation for adding all required fields for frequency
control.

Bug: 167947076
Test: VibratorControllerTest
Change-Id: Ie436f19006bdf5a7fe4dbff1b1edc72a9441239f
parent 1bd6aac4
Loading
Loading
Loading
Loading
+8 −35
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

import libcore.util.NativeAllocationRegistry;

@@ -65,13 +66,9 @@ final class VibratorController {
            NativeWrapper nativeWrapper) {
        mNativeWrapper = nativeWrapper;
        mNativeWrapper.init(vibratorId, listener);

        // TODO(b/167947076): load supported ones from HAL once API introduced
        VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping(
                Float.NaN, nativeWrapper.getResonantFrequency(), Float.NaN, Float.NaN, null);
        mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(),
                nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives(),
                nativeWrapper.getQFactor(), frequencyMapping);
        mVibratorInfo = mNativeWrapper.getInfo();
        Preconditions.checkNotNull(mVibratorInfo, "Failed to retrieve data for vibrator %d",
                vibratorId);
    }

    /** Register state listener for this vibrator. */
@@ -338,19 +335,15 @@ final class VibratorController {
        private static native long on(long nativePtr, long milliseconds, long vibrationId);
        private static native void off(long nativePtr);
        private static native void setAmplitude(long nativePtr, float amplitude);
        private static native int[] getSupportedEffects(long nativePtr);
        private static native int[] getSupportedPrimitives(long nativePtr);
        private static native long performEffect(long nativePtr, long effect, long strength,
                long vibrationId);
        private static native long performComposedEffect(long nativePtr, PrimitiveSegment[] effect,
                long vibrationId);
        private static native void setExternalControl(long nativePtr, boolean enabled);
        private static native long getCapabilities(long nativePtr);
        private static native void alwaysOnEnable(long nativePtr, long id, long effect,
                long strength);
        private static native void alwaysOnDisable(long nativePtr, long id);
        private static native float getResonantFrequency(long nativePtr);
        private static native float getQFactor(long nativePtr);
        private static native VibratorInfo getInfo(long nativePtr);

        private long mNativePtr = 0;

@@ -387,16 +380,6 @@ final class VibratorController {
            setAmplitude(mNativePtr, amplitude);
        }

        /** Returns all predefined effects supported by the device vibrator. */
        public int[] getSupportedEffects() {
            return getSupportedEffects(mNativePtr);
        }

        /** Returns all compose primitives supported by the device vibrator. */
        public int[] getSupportedPrimitives() {
            return getSupportedPrimitives(mNativePtr);
        }

        /** Turns vibrator on to perform one of the supported effects. */
        public long perform(long effect, long strength, long vibrationId) {
            return performEffect(mNativePtr, effect, strength, vibrationId);
@@ -412,11 +395,6 @@ final class VibratorController {
            setExternalControl(mNativePtr, enabled);
        }

        /** Returns all capabilities of the device vibrator. */
        public long getCapabilities() {
            return getCapabilities(mNativePtr);
        }

        /** Enable always-on vibration with given id and effect. */
        public void alwaysOnEnable(long id, long effect, long strength) {
            alwaysOnEnable(mNativePtr, id, effect, strength);
@@ -427,14 +405,9 @@ final class VibratorController {
            alwaysOnDisable(mNativePtr, id);
        }

        /** Gets the vibrator's resonant frequency (F0) */
        public float getResonantFrequency() {
            return getResonantFrequency(mNativePtr);
        }

        /** Gets the vibrator's Q factor */
        public float getQFactor() {
            return getQFactor(mNativePtr);
        /** Return device vibrator metadata. */
        public VibratorInfo getInfo() {
            return getInfo(mNativePtr);
        }
    }
}
+91 −74
Original line number Diff line number Diff line
@@ -39,6 +39,10 @@ namespace android {

static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnComplete;
static jclass sFrequencyMappingClass;
static jmethodID sFrequencyMappingCtor;
static jclass sVibratorInfoClass;
static jmethodID sVibratorInfoCtor;
static struct {
    jfieldID id;
    jfieldID scale;
@@ -97,7 +101,17 @@ public:
        jniEnv->DeleteGlobalRef(mCallbackListener);
    }

    vibrator::HalController* hal() const { return mHal.get(); }
    int32_t getVibratorId() const { return mVibratorId; }

    vibrator::Info getVibratorInfo() { return mHal->getInfo(); }

    void initHal() { mHal->init(); }

    template <typename T>
    vibrator::HalResult<T> halCall(const vibrator::HalFunction<vibrator::HalResult<T>>& fn,
                                   const char* functionName) {
        return mHal->doWithRetry(fn, functionName);
    }

    std::function<void()> createCallback(jlong vibrationId) {
        return [vibrationId, this]() {
@@ -133,7 +147,7 @@ static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId
                                jobject callbackListener) {
    std::unique_ptr<VibratorControllerWrapper> wrapper =
            std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener);
    wrapper->hal()->init();
    wrapper->initHal();
    return reinterpret_cast<jlong>(wrapper.release());
}

@@ -147,7 +161,8 @@ static jboolean vibratorIsAvailable(JNIEnv* env, jclass /* clazz */, jlong ptr)
        ALOGE("vibratorIsAvailable failed because native wrapper was not initialized");
        return JNI_FALSE;
    }
    return wrapper->hal()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
    auto pingFn = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->ping(); };
    return wrapper->halCall<void>(pingFn, "ping").isOk() ? JNI_TRUE : JNI_FALSE;
}

static jlong vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeoutMs,
@@ -158,7 +173,10 @@ static jlong vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeou
        return -1;
    }
    auto callback = wrapper->createCallback(vibrationId);
    auto result = wrapper->hal()->on(std::chrono::milliseconds(timeoutMs), callback);
    auto onFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->on(std::chrono::milliseconds(timeoutMs), callback);
    };
    auto result = wrapper->halCall<void>(onFn, "on");
    return result.isOk() ? timeoutMs : (result.isUnsupported() ? 0 : -1);
}

@@ -168,7 +186,8 @@ static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong ptr) {
        ALOGE("vibratorOff failed because native wrapper was not initialized");
        return;
    }
    wrapper->hal()->off();
    auto offFn = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
    wrapper->halCall<void>(offFn, "off");
}

static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfloat amplitude) {
@@ -177,7 +196,10 @@ static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfl
        ALOGE("vibratorSetAmplitude failed because native wrapper was not initialized");
        return;
    }
    wrapper->hal()->setAmplitude(static_cast<float>(amplitude));
    auto setAmplitudeFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->setAmplitude(static_cast<float>(amplitude));
    };
    wrapper->halCall<void>(setAmplitudeFn, "setAmplitude");
}

static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong ptr,
@@ -187,41 +209,10 @@ static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong pt
        ALOGE("vibratorSetExternalControl failed because native wrapper was not initialized");
        return;
    }
    wrapper->hal()->setExternalControl(enabled);
}

static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
    if (wrapper == nullptr) {
        ALOGE("vibratorGetSupportedEffects failed because native wrapper was not initialized");
        return nullptr;
    }
    auto result = wrapper->hal()->getSupportedEffects();
    if (!result.isOk()) {
        return nullptr;
    }
    std::vector<aidl::Effect> supportedEffects = result.value();
    jintArray effects = env->NewIntArray(supportedEffects.size());
    env->SetIntArrayRegion(effects, 0, supportedEffects.size(),
                           reinterpret_cast<jint*>(supportedEffects.data()));
    return effects;
}

static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
    if (wrapper == nullptr) {
        ALOGE("vibratorGetSupportedPrimitives failed because native wrapper was not initialized");
        return nullptr;
    }
    auto result = wrapper->hal()->getSupportedPrimitives();
    if (!result.isOk()) {
        return nullptr;
    }
    std::vector<aidl::CompositePrimitive> supportedPrimitives = result.value();
    jintArray primitives = env->NewIntArray(supportedPrimitives.size());
    env->SetIntArrayRegion(primitives, 0, supportedPrimitives.size(),
                           reinterpret_cast<jint*>(supportedPrimitives.data()));
    return primitives;
    auto setExternalControlFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->setExternalControl(enabled);
    };
    wrapper->halCall<void>(setExternalControlFn, "setExternalControl");
}

static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong effect,
@@ -234,7 +225,10 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, j
    aidl::Effect effectType = static_cast<aidl::Effect>(effect);
    aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
    auto callback = wrapper->createCallback(vibrationId);
    auto result = wrapper->hal()->performEffect(effectType, effectStrength, callback);
    auto performEffectFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->performEffect(effectType, effectStrength, callback);
    };
    auto result = wrapper->halCall<std::chrono::milliseconds>(performEffectFn, "performEffect");
    return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1);
}

@@ -252,20 +246,14 @@ static jlong vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlon
        effects.push_back(effectFromJavaPrimitive(env, element));
    }
    auto callback = wrapper->createCallback(vibrationId);
    auto result = wrapper->hal()->performComposedEffect(effects, callback);
    auto performComposedEffectFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->performComposedEffect(effects, callback);
    };
    auto result = wrapper->halCall<std::chrono::milliseconds>(performComposedEffectFn,
                                                              "performComposedEffect");
    return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1);
}

static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
    if (wrapper == nullptr) {
        ALOGE("vibratorGetCapabilities failed because native wrapper was not initialized");
        return 0;
    }
    auto result = wrapper->hal()->getCapabilities();
    return result.isOk() ? static_cast<jlong>(result.value()) : 0;
}

static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id,
                                   jlong effect, jlong strength) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
@@ -273,8 +261,11 @@ static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, j
        ALOGE("vibratorAlwaysOnEnable failed because native wrapper was not initialized");
        return;
    }
    wrapper->hal()->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
    auto alwaysOnEnableFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
                                   static_cast<aidl::EffectStrength>(strength));
    };
    wrapper->halCall<void>(alwaysOnEnableFn, "alwaysOnEnable");
}

static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id) {
@@ -283,27 +274,48 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr,
        ALOGE("vibratorAlwaysOnDisable failed because native wrapper was not initialized");
        return;
    }
    wrapper->hal()->alwaysOnDisable(static_cast<int32_t>(id));
    auto alwaysOnDisableFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) {
        return hal->alwaysOnDisable(static_cast<int32_t>(id));
    };
    wrapper->halCall<void>(alwaysOnDisableFn, "alwaysOnDisable");
}

static float vibratorGetResonantFrequency(JNIEnv* env, jclass /* clazz */, jlong ptr) {
static jobject vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
    if (wrapper == nullptr) {
        ALOGE("vibratorGetResonantFrequency failed because native wrapper was not initialized");
        return NAN;
    }
    auto result = wrapper->hal()->getResonantFrequency();
    return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
        ALOGE("vibratorGetInfo failed because native wrapper was not initialized");
        return nullptr;
    }
    vibrator::Info info = wrapper->getVibratorInfo();

static float vibratorGetQFactor(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
    if (wrapper == nullptr) {
        ALOGE("vibratorGetQFactor failed because native wrapper was not initialized");
        return NAN;
    jlong capabilities =
            static_cast<jlong>(info.capabilities.valueOr(vibrator::Capabilities::NONE));
    jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN));
    jfloat qFactor = static_cast<jfloat>(info.qFactor.valueOr(NAN));
    jintArray supportedEffects = nullptr;
    jintArray supportedPrimitives = nullptr;

    if (info.supportedEffects.isOk()) {
        std::vector<aidl::Effect> effects = info.supportedEffects.value();
        supportedEffects = env->NewIntArray(effects.size());
        env->SetIntArrayRegion(supportedEffects, 0, effects.size(),
                               reinterpret_cast<jint*>(effects.data()));
    }
    auto result = wrapper->hal()->getQFactor();
    return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
    if (info.supportedPrimitives.isOk()) {
        std::vector<aidl::CompositePrimitive> primitives = info.supportedPrimitives.value();
        supportedPrimitives = env->NewIntArray(primitives.size());
        env->SetIntArrayRegion(supportedPrimitives, 0, primitives.size(),
                               reinterpret_cast<jint*>(primitives.data()));
    }

    jobject frequencyMapping =
            env->NewObject(sFrequencyMappingClass, sFrequencyMappingCtor, NAN /* minFrequencyHz*/,
                           resonantFrequency, NAN /* frequencyResolutionHz*/,
                           NAN /* suggestedSafeRangeHz */, nullptr /* maxAmplitudes */);

    return env->NewObject(sVibratorInfoClass, sVibratorInfoCtor, wrapper->getVibratorId(),
                          capabilities, supportedEffects, supportedPrimitives, qFactor,
                          frequencyMapping);
}

static const JNINativeMethod method_table[] = {
@@ -318,14 +330,10 @@ static const JNINativeMethod method_table[] = {
        {"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
        {"performComposedEffect", "(J[Landroid/os/vibrator/PrimitiveSegment;J)J",
         (void*)vibratorPerformComposedEffect},
        {"getSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
        {"getSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
        {"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
        {"getCapabilities", "(J)J", (void*)vibratorGetCapabilities},
        {"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
        {"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
        {"getResonantFrequency", "(J)F", (void*)vibratorGetResonantFrequency},
        {"getQFactor", "(J)F", (void*)vibratorGetQFactor},
        {"getInfo", "(J)Landroid/os/VibratorInfo;", (void*)vibratorGetInfo},
};

int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
@@ -340,6 +348,15 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env
    sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "mScale", "F");
    sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "mDelay", "I");

    jclass frequencyMappingClass = FindClassOrDie(env, "android/os/VibratorInfo$FrequencyMapping");
    sFrequencyMappingClass = (jclass)env->NewGlobalRef(frequencyMappingClass);
    sFrequencyMappingCtor = GetMethodIDOrDie(env, sFrequencyMappingClass, "<init>", "(FFFF[F)V");

    jclass vibratorInfoClass = FindClassOrDie(env, "android/os/VibratorInfo");
    sVibratorInfoClass = (jclass)env->NewGlobalRef(vibratorInfoClass);
    sVibratorInfoCtor = GetMethodIDOrDie(env, sVibratorInfoClass, "<init>",
                                         "(IJ[I[IFLandroid/os/VibratorInfo$FrequencyMapping;)V");

    return jniRegisterNativeMethods(env,
                                    "com/android/server/vibrator/VibratorController$NativeWrapper",
                                    method_table, NELEM(method_table));
+9 −26
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.StepSegment;
@@ -38,7 +39,6 @@ import java.util.Map;
 * interactions.
 */
final class FakeVibratorControllerProvider {

    private static final int EFFECT_DURATION = 20;

    private final Map<Long, PrebakedSegment> mEnabledAlwaysOnEffects = new HashMap<>();
@@ -92,26 +92,6 @@ final class FakeVibratorControllerProvider {
            applyLatency();
        }

        @Override
        public int[] getSupportedEffects() {
            return mSupportedEffects;
        }

        @Override
        public int[] getSupportedPrimitives() {
            return mSupportedPrimitives;
        }

        @Override
        public float getResonantFrequency() {
            return mResonantFrequency;
        }

        @Override
        public float getQFactor() {
            return mQFactor;
        }

        @Override
        public long perform(long effect, long strength, long vibrationId) {
            if (mSupportedEffects == null
@@ -140,11 +120,6 @@ final class FakeVibratorControllerProvider {
        public void setExternalControl(boolean enabled) {
        }

        @Override
        public long getCapabilities() {
            return mCapabilities;
        }

        @Override
        public void alwaysOnEnable(long id, long effect, long strength) {
            PrebakedSegment prebaked = new PrebakedSegment((int) effect, false, (int) strength);
@@ -156,6 +131,14 @@ final class FakeVibratorControllerProvider {
            mEnabledAlwaysOnEffects.remove(id);
        }

        @Override
        public VibratorInfo getInfo() {
            VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping(
                    Float.NaN, mResonantFrequency, Float.NaN, Float.NaN, null);
            return new VibratorInfo(vibratorId, mCapabilities, mSupportedEffects,
                    mSupportedPrimitives, mQFactor, frequencyMapping);
        }

        private void applyLatency() {
            try {
                if (mLatency > 0) {
+12 −11
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.hardware.vibrator.IVibrator;
import android.os.IBinder;
import android.os.IVibratorStateListener;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.test.TestLooper;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
@@ -66,6 +67,7 @@ import org.mockito.junit.MockitoRule;
 */
@Presubmit
public class VibratorControllerTest {
    private static final int VIBRATOR_ID = 0;

    @Rule public MockitoRule rule = MockitoJUnit.rule();
    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@@ -86,23 +88,18 @@ public class VibratorControllerTest {
        ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
        when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
        when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
        mockVibratorCapabilities(0);
    }

    private VibratorController createController() {
        return new VibratorController(/* vibratorId= */ 0, mOnCompleteListenerMock,
                mNativeWrapperMock);
    }

    private VibratorController createController(int vibratorId) {
        return new VibratorController(vibratorId, mOnCompleteListenerMock, mNativeWrapperMock);
        return new VibratorController(VIBRATOR_ID, mOnCompleteListenerMock, mNativeWrapperMock);
    }

    @Test
    public void createController_initializesNativeWrapper() {
        int vibratorId = 13;
        VibratorController controller = createController(vibratorId);
        assertEquals(vibratorId, controller.getVibratorInfo().getId());
        verify(mNativeWrapperMock).init(eq(vibratorId), notNull());
        VibratorController controller = createController();
        assertEquals(VIBRATOR_ID, controller.getVibratorInfo().getId());
        verify(mNativeWrapperMock).init(eq(VIBRATOR_ID), notNull());
    }

    @Test
@@ -292,7 +289,11 @@ public class VibratorControllerTest {
    }

    private void mockVibratorCapabilities(int capabilities) {
        when(mNativeWrapperMock.getCapabilities()).thenReturn((long) capabilities);
        VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping(
                Float.NaN, Float.NaN, Float.NaN, Float.NaN, null);
        when(mNativeWrapperMock.getInfo()).thenReturn(
                new VibratorInfo(VIBRATOR_ID, capabilities, null, null, Float.NaN,
                        frequencyMapping));
    }

    private PrebakedSegment createPrebaked(int effectId, int effectStrength) {