Fix haptics scaling to match VibrationEffect function

Fix the scale function in ExternalVibrationUtils to match the one used
by VibrationEffect. Add flagged fix with new tests for the module
libvibrator.

Bug: 356144312
Flag: android.os.vibrator.fix_audio_coupled_haptics_scaling
Test: libvibrator_test
Change-Id: I56116536d7cddab29448f0e436ee752c7181eb45
diff --git a/libs/vibrator/tests/ExternalVibrationTest.cpp b/libs/vibrator/tests/ExternalVibrationTest.cpp
new file mode 100644
index 0000000..3141380
--- /dev/null
+++ b/libs/vibrator/tests/ExternalVibrationTest.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <binder/Parcel.h>
+#include <gtest/gtest.h>
+#include <vibrator/ExternalVibration.h>
+
+using namespace android;
+using namespace testing;
+
+using HapticLevel = os::HapticLevel;
+using ScaleLevel = os::ExternalVibrationScale::ScaleLevel;
+
+class TestVibrationController : public os::IExternalVibrationController {
+public:
+    explicit TestVibrationController() {}
+    IBinder *onAsBinder() override { return nullptr; }
+    binder::Status mute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+    binder::Status unmute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+};
+
+class ExternalVibrationTest : public Test {
+protected:
+    HapticLevel toHapticLevel(ScaleLevel level) {
+        os::ExternalVibrationScale externalVibrationScale;
+        externalVibrationScale.scaleLevel = level;
+        os::HapticScale hapticScale =
+                os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale);
+        return hapticScale.getLevel();
+    }
+};
+
+TEST_F(ExternalVibrationTest, TestReadAndWriteToParcel) {
+    int32_t uid = 1;
+    std::string pkg("package.name");
+    audio_attributes_t originalAttrs;
+    originalAttrs.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
+    originalAttrs.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    originalAttrs.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+    originalAttrs.flags = AUDIO_FLAG_BYPASS_MUTE;
+    sp<TestVibrationController> vibrationController = new TestVibrationController();
+    ASSERT_NE(vibrationController, nullptr);
+    sp<os::ExternalVibration> original =
+            new os::ExternalVibration(uid, pkg, originalAttrs, vibrationController);
+    ASSERT_NE(original, nullptr);
+    EXPECT_EQ(original->getUid(), uid);
+    EXPECT_EQ(original->getPackage(), pkg);
+    EXPECT_EQ(original->getAudioAttributes().content_type, originalAttrs.content_type);
+    EXPECT_EQ(original->getAudioAttributes().usage, originalAttrs.usage);
+    EXPECT_EQ(original->getAudioAttributes().source, originalAttrs.source);
+    EXPECT_EQ(original->getAudioAttributes().flags, originalAttrs.flags);
+    EXPECT_EQ(original->getController(), vibrationController);
+    audio_attributes_t defaultAttrs;
+    defaultAttrs.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+    defaultAttrs.usage = AUDIO_USAGE_UNKNOWN;
+    defaultAttrs.source = AUDIO_SOURCE_DEFAULT;
+    defaultAttrs.flags = AUDIO_FLAG_NONE;
+    sp<os::ExternalVibration> parceled =
+            new os::ExternalVibration(0, std::string(""), defaultAttrs, nullptr);
+    ASSERT_NE(parceled, nullptr);
+    Parcel parcel;
+    original->writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    parceled->readFromParcel(&parcel);
+    EXPECT_EQ(parceled->getUid(), uid);
+    EXPECT_EQ(parceled->getPackage(), pkg);
+    EXPECT_EQ(parceled->getAudioAttributes().content_type, originalAttrs.content_type);
+    EXPECT_EQ(parceled->getAudioAttributes().usage, originalAttrs.usage);
+    EXPECT_EQ(parceled->getAudioAttributes().source, originalAttrs.source);
+    EXPECT_EQ(parceled->getAudioAttributes().flags, originalAttrs.flags);
+    // TestVibrationController does not implement onAsBinder, skip controller parcel in this test.
+}
+
+TEST_F(ExternalVibrationTest, TestExternalVibrationScaleToHapticScale) {
+    os::ExternalVibrationScale externalVibrationScale;
+    externalVibrationScale.scaleLevel = ScaleLevel::SCALE_HIGH;
+    externalVibrationScale.adaptiveHapticsScale = 0.8f;
+    os::HapticScale hapticScale =
+            os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale);
+    // Check scale factor is forwarded.
+    EXPECT_EQ(hapticScale.getLevel(), HapticLevel::HIGH);
+    EXPECT_EQ(hapticScale.getAdaptiveScaleFactor(), 0.8f);
+    // Check conversion for all levels.
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_MUTE), HapticLevel::MUTE);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_LOW), HapticLevel::VERY_LOW);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_LOW), HapticLevel::LOW);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_NONE), HapticLevel::NONE);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_HIGH), HapticLevel::HIGH);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_HIGH), HapticLevel::VERY_HIGH);
+}