diff options
author | Vince Leung <leungv@google.com> | 2021-02-11 02:21:57 +0000 |
---|---|---|
committer | Vince Leung <leungv@google.com> | 2021-03-24 06:20:21 +0000 |
commit | 823cf5f4551721aa41403d0c873940294984ece4 (patch) | |
tree | affcfbc7baf549503c9568ed38c2e5beddd0c870 | |
parent | aa32e6903901574780c9aeb6617729bb0fcbe1d5 (diff) |
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
19 files changed, 984 insertions, 67 deletions
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 0000000000..de3ad3c032 --- /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 0000000000..d38c584d76 --- /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 0000000000..fa7b43abd0 --- /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 0995d2d7af..3be58a1490 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 0b4b527359..50de13fc27 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 0d2b340a6c..adf0f2009f 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 808644a4b5..af5e15871b 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 1f2d946836..b7afb663cf 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 @@ interface IVibrator { 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 @@ interface IVibrator { 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 f99ecc1143..99d6d2290d 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 8e3ac88e8c..290c68d877 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 0000000000..584bcf4a47 --- /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 0000000000..fd5f8d1973 --- /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 0000000000..2bc51db3f6 --- /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 0000000000..00675ed0fc --- /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 cba76dc745..592d151d32 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 @@ interface IVibrator { * 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 @@ interface IVibrator { 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. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_GET_RESONANT_FREQUENCY) * - * @return Measured resonant frequency in Hz. + * @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. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_GET_Q_FACTOR) * - * @return Measured 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 0000000000..813c7dcb33 --- /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 bf61bfec91..c6682b318f 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -26,9 +26,16 @@ namespace vibrator { 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 @@ ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { 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 @@ ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) { 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 a2af9637ed..4203bf212c 100644 --- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h +++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h @@ -46,6 +46,15 @@ class Vibrator : public BnVibrator { 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 2540d0b1d5..a9d1ed5a51 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::ProcessState; 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 @@ const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStr 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 @@ class VibratorAidl : public testing::TestWithParam<std::tuple<int32_t, int32_t>> 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, OnThenOffBeforeTimeout) { } 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 @@ TEST_P(VibratorAidl, ValidateEffect) { 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 @@ TEST_P(VibratorAidl, ValidateEffect) { 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 @@ TEST_P(VibratorAidl, ValidateEffectWithCallback) { 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, ValidateEffectWithCallback) { } 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 @@ TEST_P(VibratorAidl, InvalidEffectsUnsupported) { 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 @@ TEST_P(VibratorAidl, InvalidEffectsUnsupported) { 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, ChangeVibrationExternalControl) { 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 @@ TEST_P(VibratorAidl, GetSupportedPrimitives) { 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 @@ TEST_P(VibratorAidl, GetPrimitiveDuration) { 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 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { 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 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { 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, ComposeUnsupportedPrimitives) { 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 @@ TEST_P(VibratorAidl, ComposeCallback) { 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 @@ TEST_P(VibratorAidl, ComposeCallback) { 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 @@ TEST_P(VibratorAidl, AlwaysOn) { 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, AlwaysOn) { } 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 @@ std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() { 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 @@ std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() { 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 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl); 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(); |