Add Chirp APIs for PWLE sequence creation
Add the necessary Chirp APIs required to allow for piecewise-linear
equation sequencing of haptic waveforms. These APIs will allow
developers to create a fully customizable sequence of haptics waveforms
for playback.
Bug: 162859057
Test: verify pwle sequences can be created and played using idlcli
command. Also verify using atest.
Change-Id: I7fec224b7090e482bbcd1c94a3799ec232cc547f
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl
new file mode 100644
index 0000000..de3ad3c
--- /dev/null
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.vibrator;
+@VintfStability
+parcelable ActivePwle {
+ float startAmplitude;
+ float startFrequency;
+ float endAmplitude;
+ float endFrequency;
+ int duration;
+}
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl
new file mode 100644
index 0000000..d38c584
--- /dev/null
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.vibrator;
+@Backing(type="int") @VintfStability
+enum Braking {
+ NONE = 0,
+ CLAB = 1,
+}
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl
new file mode 100644
index 0000000..fa7b43a
--- /dev/null
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.vibrator;
+@VintfStability
+parcelable BrakingPwle {
+ android.hardware.vibrator.Braking braking;
+ int duration;
+}
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
index 0995d2d..3be58a1 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
index 0b4b527..50de13f 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
index 0d2b340..adf0f20 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
index 808644a..af5e158 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
index 1f2d946..b7afb66 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
@@ -50,6 +51,13 @@
void alwaysOnDisable(in int id);
float getResonantFrequency();
float getQFactor();
+ float getFrequencyResolution();
+ float getFrequencyMinimum();
+ float[] getBandwidthAmplitudeMap();
+ int getPwlePrimitiveDurationMax();
+ int getPwleCompositionSizeMax();
+ android.hardware.vibrator.Braking[] getSupportedBraking();
+ void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
const int CAP_ON_CALLBACK = 1;
const int CAP_PERFORM_CALLBACK = 2;
const int CAP_AMPLITUDE_CONTROL = 4;
@@ -59,4 +67,6 @@
const int CAP_ALWAYS_ON_CONTROL = 64;
const int CAP_GET_RESONANT_FREQUENCY = 128;
const int CAP_GET_Q_FACTOR = 256;
+ const int CAP_FREQUENCY_CONTROL = 512;
+ const int CAP_COMPOSE_PWLE_EFFECTS = 1024;
}
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
index f99ecc1..99d6d22 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
index 8e3ac88..290c68d 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
@@ -12,7 +12,8 @@
* 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.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl
new file mode 100644
index 0000000..584bcf4
--- /dev/null
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.vibrator;
+@VintfStability
+union PrimitivePwle {
+ android.hardware.vibrator.ActivePwle active;
+ android.hardware.vibrator.BrakingPwle braking;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl b/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl
new file mode 100644
index 0000000..fd5f8d1
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.hardware.vibrator;
+
+@VintfStability
+parcelable ActivePwle {
+ /**
+ * Amplitude ranging from 0.0 (inclusive) to 1.0 (inclusive)
+ * in units of output acceleration amplitude, not voltage amplitude.
+ *
+ * 0.0 represents no output acceleration amplitude
+ * 1.0 represents maximum output acceleration amplitude at resonant frequency
+ */
+ float startAmplitude;
+ /**
+ * Absolute frequency point in the units of hertz
+ */
+ float startFrequency;
+ /**
+ * Amplitude ranging from 0.0 (inclusive) to 1.0 (inclusive)
+ * in units of output acceleration amplitude, not voltage amplitude.
+ *
+ * 0.0 represents no output acceleration amplitude
+ * 1.0 represents maximum output acceleration amplitude at resonant frequency
+ */
+ float endAmplitude;
+ /**
+ * Absolute frequency point in the units of hertz
+ */
+ float endFrequency;
+ /**
+ * Total duration from start point to end point in the units of milliseconds
+ */
+ int duration;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
new file mode 100644
index 0000000..2bc51db
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 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.hardware.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum Braking {
+ /**
+ * No braking mechanism used.
+ * This is the default if the hardware does not support any braking mechanism.
+ */
+ NONE,
+ /**
+ * Closed-loop active braking.
+ *
+ * This effect should produce a sharp, crisp end to the waveform
+ * Support is optional.
+ */
+ CLAB,
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl b/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl
new file mode 100644
index 0000000..00675ed
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.hardware.vibrator;
+
+import android.hardware.vibrator.Braking;
+
+/**
+ * BrakingPwle is defined as a segment of zero output acceleration amplitude of duration length.
+ *
+ * There should be no output acceleration and the vibrator should be off for the entire duration.
+ * If the hardware supports braking mechanism(s), they can be set here.
+ */
+@VintfStability
+parcelable BrakingPwle {
+ /**
+ * Braking mechanism applied to adjacent segments
+ */
+ Braking braking;
+ /**
+ * Total duration of zero output acceleration in the units of milliseconds.
+ */
+ int duration;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index cba76dc..592d151 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -17,10 +17,12 @@
package android.hardware.vibrator;
import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.vibrator.Braking;
import android.hardware.vibrator.Effect;
import android.hardware.vibrator.EffectStrength;
import android.hardware.vibrator.CompositeEffect;
import android.hardware.vibrator.CompositePrimitive;
+import android.hardware.vibrator.PrimitivePwle;
@VintfStability
interface IVibrator {
@@ -60,6 +62,14 @@
* Whether getQFactor is supported.
*/
const int CAP_GET_Q_FACTOR = 1 << 8;
+ /**
+ * Whether frequency control is supported.
+ */
+ const int CAP_FREQUENCY_CONTROL = 1 << 9;
+ /**
+ * Whether composePwle is supported.
+ */
+ const int CAP_COMPOSE_PWLE_EFFECTS = 1 << 10;
/**
* Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -240,18 +250,109 @@
void alwaysOnDisable(in int id);
/**
- * Retrieve the measured resonant frequency of the actuator. This may not be supported
- * and this support is reflected in getCapabilities (CAP_GET_RESONANT_FREQUENCY)
+ * Retrieve the measured resonant frequency of the actuator.
*
- * @return Measured resonant frequency in Hz.
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_GET_RESONANT_FREQUENCY)
+ *
+ * @return Measured resonant frequency in Hz. Non-zero value if supported,
+ * or value should be ignored if not supported.
*/
float getResonantFrequency();
/**
- * Retrieve the measured Q factor. This may not be supported
- * and this support is reflected in getCapabilities (CAP_GET_Q_FACTOR)
+ * Retrieve the measured Q factor.
*
- * @return Measured Q factor.
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_GET_Q_FACTOR)
+ *
+ * @return Measured Q factor. Non-zero value if supported, or value should be
+ * ignored if not supported.
*/
float getQFactor();
+
+ /**
+ * Retrieve the frequency resolution used in getBandwidthAmplitudeMap() in units of hertz
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_FREQUENCY_CONTROL).
+ *
+ * @return The frequency resolution of the bandwidth amplitude map.
+ * Non-zero value if supported, or value should be ignored if not supported.
+ */
+ float getFrequencyResolution();
+
+ /**
+ * Retrieve the minimum allowed frequency in units of hertz
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_FREQUENCY_CONTROL).
+ *
+ * @return The minimum frequency allowed. Non-zero value if supported,
+ * or value should be ignored if not supported.
+ */
+ float getFrequencyMinimum();
+
+ /**
+ * Retrieve the output acceleration amplitude values per frequency supported
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_FREQUENCY_CONTROL).
+ *
+ * The mapping is represented as a list of amplitude values in the inclusive range [0.0, 1.0].
+ * The first value represents the amplitude at the frequency returned by getFrequencyMinimum().
+ * Each subsequent element is the amplitude at the next supported frequency, in increments
+ * of getFrequencyResolution(). The value returned by getResonantFrequency() must be
+ * represented in the returned list.
+ *
+ * @return The maximum output acceleration amplitude for each supported frequency,
+ * starting at getMinimumFrequency()
+ */
+ float[] getBandwidthAmplitudeMap();
+
+ /**
+ * Retrieve the maximum duration allowed for any primitive PWLE in units of milliseconds.
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+ *
+ * @return The maximum duration allowed for a single PrimitivePwle.
+ * Non-zero value if supported, or value should be ignored if not supported.
+ */
+ int getPwlePrimitiveDurationMax();
+
+ /**
+ * Retrieve the maximum count for allowed PWLEs in one composition.
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+ *
+ * @return The maximum count allowed. Non-zero value if supported,
+ * or value should be ignored if not supported.
+ */
+ int getPwleCompositionSizeMax();
+
+ /**
+ * List of supported braking mechanism.
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+ * Implementations are optional but encouraged if available.
+ *
+ * @return The braking mechanisms which are supported by the composePwle API.
+ */
+ Braking[] getSupportedBraking();
+
+ /**
+ * Fire off a string of PWLEs.
+ *
+ * This may not be supported and this support is reflected in
+ * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+ *
+ * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+ * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
+ *
+ * @param composite Array of PWLEs.
+ */
+ void composePwle(in PrimitivePwle[] composite, in IVibratorCallback callback);
}
diff --git a/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl b/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl
new file mode 100644
index 0000000..813c7dc
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.hardware.vibrator;
+
+import android.hardware.vibrator.ActivePwle;
+import android.hardware.vibrator.BrakingPwle;
+
+@VintfStability
+union PrimitivePwle {
+ ActivePwle active;
+ BrakingPwle braking;
+}
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index bf61bfe..c6682b3 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -26,9 +26,16 @@
static constexpr int32_t kComposeDelayMaxMs = 1000;
static constexpr int32_t kComposeSizeMax = 256;
+static constexpr int32_t kComposePwleSizeMax = 127;
static constexpr float kResonantFrequency = 150.0;
static constexpr float kQFactor = 11.0;
+static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
+static constexpr float PWLE_LEVEL_MIN = 0.0;
+static constexpr float PWLE_LEVEL_MAX = 0.98256;
+static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
+static constexpr float PWLE_FREQUENCY_MIN_HZ = 140.0;
+static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0;
ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
LOG(INFO) << "Vibrator reporting capabilities";
@@ -36,7 +43,8 @@
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
- IVibrator::CAP_GET_Q_FACTOR;
+ IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
+ IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
return ndk::ScopedAStatus::ok();
}
@@ -215,6 +223,169 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
+ *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
+ *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
+ // A valid array should be of size:
+ // (PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ
+ *_aidl_return = {0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10,
+ 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20};
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
+ *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
+ *maxSize = kComposePwleSizeMax;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
+ *supported = {
+ Braking::NONE,
+ Braking::CLAB,
+ };
+ return ndk::ScopedAStatus::ok();
+}
+
+void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
+ const float reset = -1.0;
+ prevEndAmplitude = reset;
+ prevEndFrequency = reset;
+}
+
+void incrementIndex(int &index) {
+ index += 1;
+}
+
+void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
+ pwleBuilder << ",C" << segmentIdx << ":1";
+ pwleBuilder << ",B" << segmentIdx << ":0";
+ pwleBuilder << ",AR" << segmentIdx << ":0";
+ pwleBuilder << ",V" << segmentIdx << ":0";
+}
+
+void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
+ float amplitude, float frequency) {
+ pwleBuilder << ",T" << segmentIdx << ":" << duration;
+ pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
+ pwleBuilder << ",F" << segmentIdx << ":" << frequency;
+ constructActiveDefaults(pwleBuilder, segmentIdx);
+}
+
+void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
+ Braking brakingType) {
+ pwleBuilder << ",T" << segmentIdx << ":" << duration;
+ pwleBuilder << ",L" << segmentIdx << ":" << 0;
+ pwleBuilder << ",F" << segmentIdx << ":" << 0;
+ pwleBuilder << ",C" << segmentIdx << ":0";
+ pwleBuilder << ",B" << segmentIdx << ":"
+ << static_cast<std::underlying_type<Braking>::type>(brakingType);
+ pwleBuilder << ",AR" << segmentIdx << ":0";
+ pwleBuilder << ",V" << segmentIdx << ":0";
+}
+
+ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
+ const std::shared_ptr<IVibratorCallback> &callback) {
+ std::ostringstream pwleBuilder;
+ std::string pwleQueue;
+
+ int compositionSizeMax;
+ getPwleCompositionSizeMax(&compositionSizeMax);
+ if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ float prevEndAmplitude;
+ float prevEndFrequency;
+ resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
+
+ int segmentIdx = 0;
+ uint32_t totalDuration = 0;
+
+ pwleBuilder << "S:0,WF:4,RP:0,WT:0";
+
+ for (auto &e : composite) {
+ switch (e.getTag()) {
+ case PrimitivePwle::active: {
+ auto active = e.get<PrimitivePwle::active>();
+ if (active.duration < 0 ||
+ active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (active.startAmplitude < PWLE_LEVEL_MIN ||
+ active.startAmplitude > PWLE_LEVEL_MAX ||
+ active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
+ active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
+ active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
+ active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (!((active.startAmplitude == prevEndAmplitude) &&
+ (active.startFrequency == prevEndFrequency))) {
+ constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
+ active.startFrequency);
+ incrementIndex(segmentIdx);
+ }
+
+ constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
+ active.endAmplitude, active.endFrequency);
+ incrementIndex(segmentIdx);
+
+ prevEndAmplitude = active.endAmplitude;
+ prevEndFrequency = active.endFrequency;
+ totalDuration += active.duration;
+ break;
+ }
+ case PrimitivePwle::braking: {
+ auto braking = e.get<PrimitivePwle::braking>();
+ if (braking.braking > Braking::CLAB) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
+ incrementIndex(segmentIdx);
+
+ constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
+ incrementIndex(segmentIdx);
+
+ resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
+ totalDuration += braking.duration;
+ break;
+ }
+ }
+ }
+
+ std::thread([=] {
+ LOG(INFO) << "Starting composePwle on another thread";
+ usleep(totalDuration * 1000);
+ if (callback != nullptr) {
+ LOG(INFO) << "Notifying compose PWLE complete";
+ callback->onComplete();
+ }
+ }).detach();
+
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace vibrator
} // namespace hardware
} // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index a2af963..4203bf2 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -46,6 +46,15 @@
ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
ndk::ScopedAStatus getResonantFrequency(float *resonantFreqHz) override;
ndk::ScopedAStatus getQFactor(float *qFactor) override;
+ ndk::ScopedAStatus getFrequencyResolution(float *freqResolutionHz) override;
+ ndk::ScopedAStatus getFrequencyMinimum(float *freqMinimumHz) override;
+ ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) override;
+ ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t *durationMs) override;
+ ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t *maxSize) override;
+ ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
+ ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
+ const std::shared_ptr<IVibratorCallback> &callback) override;
+
};
} // namespace vibrator
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 2540d0b..a9d1ed5 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,7 +15,6 @@
*/
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
-
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <android/hardware/vibrator/IVibratorManager.h>
@@ -29,13 +28,17 @@
using android::sp;
using android::String16;
using android::binder::Status;
+using android::hardware::vibrator::ActivePwle;
using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::Braking;
+using android::hardware::vibrator::BrakingPwle;
using android::hardware::vibrator::CompositeEffect;
using android::hardware::vibrator::CompositePrimitive;
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
using android::hardware::vibrator::IVibratorManager;
+using android::hardware::vibrator::PrimitivePwle;
using std::chrono::high_resolution_clock;
const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
@@ -44,32 +47,32 @@
android::enum_range<EffectStrength>().end()};
const std::vector<Effect> kInvalidEffects = {
- static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
- static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
+ static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
+ static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
};
const std::vector<EffectStrength> kInvalidEffectStrengths = {
- static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
- static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
+ static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
+ static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
};
const std::vector<CompositePrimitive> kCompositePrimitives{
- android::enum_range<CompositePrimitive>().begin(),
- android::enum_range<CompositePrimitive>().end()};
+ android::enum_range<CompositePrimitive>().begin(),
+ android::enum_range<CompositePrimitive>().end()};
const std::vector<CompositePrimitive> kOptionalPrimitives = {
- CompositePrimitive::THUD,
- CompositePrimitive::SPIN,
+ CompositePrimitive::THUD,
+ CompositePrimitive::SPIN,
};
const std::vector<CompositePrimitive> kInvalidPrimitives = {
- static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
- static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
+ static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
+ static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
};
class CompletionCallback : public BnVibratorCallback {
public:
- CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
+ CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
Status onComplete() override {
mCallback();
return Status::ok();
@@ -109,6 +112,89 @@
int32_t capabilities;
};
+static float getResonantFrequencyHz(sp<IVibrator> vibrator, int32_t capabilities) {
+ float resonantFrequencyHz;
+ Status status = vibrator->getResonantFrequency(&resonantFrequencyHz);
+ if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+ EXPECT_GT(resonantFrequencyHz, 0);
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+ return resonantFrequencyHz;
+}
+
+static float getFrequencyResolutionHz(sp<IVibrator> vibrator, int32_t capabilities) {
+ float freqResolutionHz;
+ Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
+ if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ EXPECT_GT(freqResolutionHz, 0);
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+ return freqResolutionHz;
+}
+
+static float getFrequencyMinimumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+ float freqMinimumHz;
+ Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+ if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+
+ float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities);
+
+ EXPECT_GT(freqMinimumHz, 0);
+ EXPECT_LE(freqMinimumHz, resonantFrequencyHz);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+ return freqMinimumHz;
+}
+
+static float getFrequencyMaximumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+ std::vector<float> bandwidthAmplitudeMap;
+ Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+ if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+
+ float freqMaximumHz =
+ (bandwidthAmplitudeMap.size() * getFrequencyResolutionHz(vibrator, capabilities)) +
+ getFrequencyMinimumHz(vibrator, capabilities);
+ return freqMaximumHz;
+}
+
+static float getAmplitudeMin() {
+ return 0.0;
+}
+
+static float getAmplitudeMax() {
+ return 1.0;
+}
+
+static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+ float frequencyHz;
+ if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+ frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
+ } else if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ frequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
+ } else {
+ frequencyHz = 150.0; // default value commonly used
+ }
+
+ ActivePwle active;
+ active.startAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2;
+ active.startFrequency = frequencyHz;
+ active.endAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2;
+ active.endFrequency = frequencyHz;
+ active.duration = 1000;
+
+ return active;
+}
+
TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
sleep(1);
@@ -116,12 +202,13 @@
}
TEST_P(VibratorAidl, OnWithCallback) {
- if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) return;
+ if (!(capabilities & IVibrator::CAP_ON_CALLBACK))
+ return;
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
uint32_t durationMs = 250;
std::chrono::milliseconds timeout{durationMs * 2};
EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
@@ -142,7 +229,7 @@
for (Effect effect : kEffects) {
bool isEffectSupported =
- std::find(supported.begin(), supported.end(), effect) != supported.end();
+ std::find(supported.begin(), supported.end(), effect) != supported.end();
for (EffectStrength strength : kEffectStrengths) {
int32_t lengthMs = 0;
@@ -154,27 +241,28 @@
usleep(lengthMs * 1000);
} else {
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << toString(effect) << " " << toString(strength);
+ << toString(effect) << " " << toString(strength);
}
}
}
}
TEST_P(VibratorAidl, ValidateEffectWithCallback) {
- if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+ if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK))
+ return;
std::vector<Effect> supported;
ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
for (Effect effect : kEffects) {
bool isEffectSupported =
- std::find(supported.begin(), supported.end(), effect) != supported.end();
+ std::find(supported.begin(), supported.end(), effect) != supported.end();
for (EffectStrength strength : kEffectStrengths) {
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
int lengthMs = 0;
Status status = vibrator->perform(effect, strength, callback, &lengthMs);
@@ -185,7 +273,8 @@
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
}
- if (!status.isOk()) continue;
+ if (!status.isOk())
+ continue;
std::chrono::milliseconds timeout{lengthMs * 2};
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
@@ -194,7 +283,8 @@
}
TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) {
- if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return;
+ if (capabilities & IVibrator::CAP_PERFORM_CALLBACK)
+ return;
for (Effect effect : kEffects) {
for (EffectStrength strength : kEffectStrengths) {
@@ -212,7 +302,7 @@
int32_t lengthMs;
Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << toString(effect) << " " << toString(strength);
+ << toString(effect) << " " << toString(strength);
}
}
for (Effect effect : kEffects) {
@@ -220,7 +310,7 @@
int32_t lengthMs;
Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
- << toString(effect) << " " << toString(strength);
+ << toString(effect) << " " << toString(strength);
}
}
}
@@ -261,7 +351,7 @@
TEST_P(VibratorAidl, ExternalAmplitudeControl) {
const bool supportsExternalAmplitudeControl =
- (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
+ (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
@@ -293,10 +383,10 @@
for (auto primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
- std::find(supported.begin(), supported.end(), primitive) != supported.end();
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
bool isPrimitiveOptional =
- std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
- kOptionalPrimitives.end();
+ std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
+ kOptionalPrimitives.end();
EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
}
@@ -310,7 +400,7 @@
for (auto primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
- std::find(supported.begin(), supported.end(), primitive) != supported.end();
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
int32_t duration;
Status status = vibrator->getPrimitiveDuration(primitive, &duration);
@@ -366,7 +456,7 @@
for (auto primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
- std::find(supported.begin(), supported.end(), primitive) != supported.end();
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
if (!isPrimitiveSupported) {
unsupported.push_back(primitive);
@@ -376,7 +466,7 @@
for (auto primitive : unsupported) {
std::vector<CompositeEffect> composite(1);
- for (auto& effect : composite) {
+ for (auto &effect : composite) {
effect.delayMs = 0;
effect.primitive = primitive;
effect.scale = 1.0f;
@@ -391,7 +481,7 @@
TEST_P(VibratorAidl, ComposeScaleBoundary) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
std::vector<CompositeEffect> composite(1);
- CompositeEffect& effect = composite[0];
+ CompositeEffect &effect = composite[0];
effect.delayMs = 0;
effect.primitive = CompositePrimitive::CLICK;
@@ -478,7 +568,7 @@
std::promise<void> completionPromise;
std::future<void> completionFuture{completionPromise.get_future()};
sp<CompletionCallback> callback =
- new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
CompositeEffect effect;
std::vector<CompositeEffect> composite;
int32_t durationMs;
@@ -493,16 +583,15 @@
EXPECT_EQ(Status::EX_NONE,
vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode())
- << toString(primitive);
+ << toString(primitive);
duration = std::chrono::milliseconds(durationMs);
EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
- << toString(primitive);
+ << toString(primitive);
start = high_resolution_clock::now();
- EXPECT_EQ(completionFuture.wait_for(duration + allowedLatency),
- std::future_status::ready)
- << toString(primitive);
+ EXPECT_EQ(completionFuture.wait_for(duration + allowedLatency), std::future_status::ready)
+ << toString(primitive);
end = high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
@@ -519,17 +608,17 @@
for (Effect effect : kEffects) {
bool isEffectSupported =
- std::find(supported.begin(), supported.end(), effect) != supported.end();
+ std::find(supported.begin(), supported.end(), effect) != supported.end();
for (EffectStrength strength : kEffectStrengths) {
Status status = vibrator->alwaysOnEnable(0, effect, strength);
if (isEffectSupported) {
EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
- << toString(effect) << " " << toString(strength);
+ << toString(effect) << " " << toString(strength);
} else {
EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode())
- << toString(effect) << " " << toString(strength);
+ << toString(effect) << " " << toString(strength);
}
}
}
@@ -539,27 +628,253 @@
}
TEST_P(VibratorAidl, GetResonantFrequency) {
- float resonantFrequency;
- Status status = vibrator->getResonantFrequency(&resonantFrequency);
- if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
- ASSERT_NE(resonantFrequency, 0);
- EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
- } else {
- EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
- }
+ getResonantFrequencyHz(vibrator, capabilities);
}
TEST_P(VibratorAidl, GetQFactor) {
float qFactor;
Status status = vibrator->getQFactor(&qFactor);
if (capabilities & IVibrator::CAP_GET_Q_FACTOR) {
- ASSERT_NE(qFactor, 0);
+ ASSERT_GT(qFactor, 0);
EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
} else {
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
}
}
+TEST_P(VibratorAidl, GetFrequencyResolution) {
+ getFrequencyResolutionHz(vibrator, capabilities);
+}
+
+TEST_P(VibratorAidl, GetFrequencyMinimum) {
+ getFrequencyMinimumHz(vibrator, capabilities);
+}
+
+TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
+ std::vector<float> bandwidthAmplitudeMap;
+ Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+ if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ ASSERT_FALSE(bandwidthAmplitudeMap.empty());
+
+ int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
+ getFrequencyMinimumHz(vibrator, capabilities)) /
+ getFrequencyResolutionHz(vibrator, capabilities);
+ ASSERT_GT(bandwidthAmplitudeMap.size(), minMapSize);
+
+ for (float e : bandwidthAmplitudeMap) {
+ ASSERT_GE(e, 0.0);
+ ASSERT_LE(e, 1.0);
+ }
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+}
+
+TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) {
+ int32_t durationMs;
+ Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ ASSERT_NE(durationMs, 0);
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+}
+
+TEST_P(VibratorAidl, GetPwleCompositionSizeMax) {
+ int32_t maxSize;
+ Status status = vibrator->getPwleCompositionSizeMax(&maxSize);
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ ASSERT_NE(maxSize, 0);
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+}
+
+TEST_P(VibratorAidl, GetSupportedBraking) {
+ std::vector<Braking> supported;
+ Status status = vibrator->getSupportedBraking(&supported);
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ bool isDefaultNoneSupported =
+ std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end();
+ ASSERT_TRUE(isDefaultNoneSupported);
+ EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+ } else {
+ EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+ }
+}
+
+TEST_P(VibratorAidl, ComposeValidPwle) {
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+ std::vector<Braking> supported;
+ ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+ bool isClabSupported =
+ std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
+ BrakingPwle braking;
+ braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
+ braking.duration = 100;
+
+ std::vector<PrimitivePwle> pwleQueue;
+ PrimitivePwle pwle;
+ pwle = active;
+ pwleQueue.emplace_back(std::move(pwle));
+ pwle = braking;
+ pwleQueue.emplace_back(std::move(pwle));
+ pwle = active;
+ pwleQueue.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+ vibrator->off();
+ }
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleWithCallback) {
+ if (!((capabilities & IVibrator::CAP_ON_CALLBACK) &&
+ (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS)))
+ return;
+
+ std::promise<void> completionPromise;
+ std::future<void> completionFuture{completionPromise.get_future()};
+ sp<CompletionCallback> callback =
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ uint32_t durationMs = 2100; // Sum of 2 active and 1 braking below
+ std::chrono::milliseconds timeout{durationMs * 2};
+
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+ std::vector<Braking> supported;
+ ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+ bool isClabSupported =
+ std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
+ BrakingPwle braking;
+ braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
+ braking.duration = 100;
+
+ std::vector<PrimitivePwle> pwleQueue;
+ PrimitivePwle pwle;
+ pwle = active;
+ pwleQueue.emplace_back(std::move(pwle));
+ pwle = braking;
+ pwleQueue.emplace_back(std::move(pwle));
+ pwle = active;
+ pwleQueue.emplace_back(std::move(pwle));
+
+ EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk());
+ EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+ EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, ComposePwleSegmentBoundary) {
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ std::vector<PrimitivePwle> pwleQueue;
+ // test empty queue
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+ vibrator->off();
+
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+ PrimitivePwle pwle;
+ pwle = active;
+ int segmentCountMax;
+ vibrator->getPwleCompositionSizeMax(&segmentCountMax);
+
+ // Create PWLE queue with more segments than allowed
+ for (int i = 0; i < segmentCountMax + 10; i++) {
+ pwleQueue.emplace_back(std::move(pwle));
+ }
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+ vibrator->off();
+ }
+}
+
+TEST_P(VibratorAidl, ComposePwleAmplitudeParameterBoundary) {
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+ active.startAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
+ active.endAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
+
+ std::vector<PrimitivePwle> pwleQueueGreater;
+ PrimitivePwle pwle;
+ pwle = active;
+ pwleQueueGreater.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
+ vibrator->off();
+
+ active.startAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed
+ active.endAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed
+
+ std::vector<PrimitivePwle> pwleQueueLess;
+ pwle = active;
+ pwleQueueLess.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
+ vibrator->off();
+ }
+}
+
+TEST_P(VibratorAidl, ComposePwleFrequencyParameterBoundary) {
+ if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) &&
+ (capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
+ float freqMinimumHz = getFrequencyMinimumHz(vibrator, capabilities);
+ float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities);
+ float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
+
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+ active.startFrequency =
+ freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
+ active.endFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
+
+ std::vector<PrimitivePwle> pwleQueueGreater;
+ PrimitivePwle pwle;
+ pwle = active;
+ pwleQueueGreater.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
+ vibrator->off();
+
+ active.startFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed
+ active.endFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed
+
+ std::vector<PrimitivePwle> pwleQueueLess;
+ pwle = active;
+ pwleQueueLess.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
+ vibrator->off();
+ }
+}
+
+TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) {
+ if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+ ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+ int segmentDurationMaxMs;
+ vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
+ active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed
+
+ std::vector<PrimitivePwle> pwleQueue;
+ PrimitivePwle pwle;
+ pwle = active;
+ pwleQueue.emplace_back(std::move(pwle));
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+ vibrator->off();
+ }
+}
+
std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
std::vector<std::tuple<int32_t, int32_t>> tuples;
auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
@@ -569,7 +884,7 @@
auto managerName = String16(managerAidlNames[i].c_str());
auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
- for (auto& vibratorId : vibratorIds) {
+ for (auto &vibratorId : vibratorIds) {
tuples.push_back(std::make_tuple(i, vibratorId));
}
}
@@ -583,8 +898,8 @@
return tuples;
}
-std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType>& info) {
- const auto& [managerIdx, vibratorId] = info.param;
+std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType> &info) {
+ const auto &[managerIdx, vibratorId] = info.param;
if (managerIdx < 0) {
return std::string("TOP_LEVEL_VIBRATOR_") + std::to_string(vibratorId);
}
@@ -596,7 +911,7 @@
INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(GenerateVibratorMapping()),
PrintGeneratedTest);
-int main(int argc, char** argv) {
+int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
ProcessState::self()->setThreadPoolMaxThreadCount(1);
ProcessState::self()->startThreadPool();