Add AIDL Lights HAL to support multiple lights per type
This is a revision of the previous 2.0 HIDL-based light HAL.
It accomplishes 2 goals:
1) Support more than 1 light for a given type. This allows Assistant to
use the HAL on TV platforms that have usually 4 indicator lights.
2) Use AIDL, which is the more modern way of writing HALs.
The previous HAL is in hardware/interfaces/light/2.0 and the new one is
in versioned as aidl, as that supports forward compatibility.
Test: atest VtsHalLightTargetTest
Bug: 142715294, 142230898
Change-Id: I6d8c12b3df88e02f2a0fff8b6aa8543372b510c8
Merged-In: I08d831ca0380d8bb187e43f6d5c214810ff72f50
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index bb057fb..a9ea188 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -276,6 +276,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.light</name>
+ <interface>
+ <name>ILights</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.media.c2</name>
<version>1.0</version>
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
new file mode 100644
index 0000000..916a857
--- /dev/null
+++ b/light/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.light",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/light/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/light/aidl/android/hardware/light/BrightnessMode.aidl b/light/aidl/android/hardware/light/BrightnessMode.aidl
new file mode 100644
index 0000000..bc29699
--- /dev/null
+++ b/light/aidl/android/hardware/light/BrightnessMode.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum BrightnessMode {
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ USER = 0,
+
+ /**
+ * Light brightness is managed by a light sensor. This is typically used
+ * to control the display backlight, but not limited to it. HALs and
+ * hardware implementations are free to support sensor for other lights or
+ * none whatsoever.
+ */
+ SENSOR = 1,
+
+ /**
+ * Use a low-persistence mode for display backlights, where the pixel
+ * color transition times are lowered.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in LightState may be
+ * overridden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display must meet the following
+ * criteria in this mode:
+ * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms.
+ * - The display must support low-persistence with ≤ 3.5 ms persistence.
+ * Persistence is defined as the amount of time for which a pixel is
+ * emitting light for a single frame.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ * - The display must update at 60 Hz at least, but higher refresh rates are
+ * recommended for low latency.
+ *
+ */
+ LOW_PERSISTENCE = 2,
+}
diff --git a/light/aidl/android/hardware/light/FlashMode.aidl b/light/aidl/android/hardware/light/FlashMode.aidl
new file mode 100644
index 0000000..00c6b6a
--- /dev/null
+++ b/light/aidl/android/hardware/light/FlashMode.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum FlashMode {
+ /**
+ * Keep the light steady on or off.
+ */
+ NONE = 0,
+ /**
+ * Flash the light at specified rate, potentially using a software-based
+ * implementation.
+ */
+ TIMED = 1,
+ /**
+ * Flash the light using hardware flashing support. This may or may not
+ * support a user-defined flashing rate or other features.
+ */
+ HARDWARE = 2,
+}
diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl
new file mode 100644
index 0000000..43fdb4b
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLight.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.light;
+
+import android.hardware.light.LightType;
+
+/**
+ * A description of a single light. Multiple lights can map to the same physical
+ * LED. Separate physical LEDs are always represented by separate instances.
+ */
+@VintfStability
+parcelable HwLight {
+ /**
+ * Integer ID used for controlling this light
+ */
+ int id;
+
+ /**
+ * For a group of lights of the same logical type, sorting by ordinal should
+ * be give their physical order. No other meaning is carried by it.
+ */
+ int ordinal;
+
+ /**
+ * Logical type use of this light.
+ */
+ LightType type;
+}
diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl
new file mode 100644
index 0000000..24d3250
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLightState.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.BrightnessMode;
+import android.hardware.light.FlashMode;
+
+/**
+ * The parameters that can be set for a given light.
+ *
+ * Not all lights must support all parameters. If you
+ * can do something backward-compatible, do it.
+ */
+@VintfStability
+parcelable HwLightState {
+ /**
+ * The color of the LED in ARGB.
+ *
+ * The implementation of this in the HAL and hardware is a best-effort one.
+ * - If a light can only do red or green and blue is requested, green
+ * should be shown.
+ * - If only a brightness ramp is supported, then this formula applies:
+ * unsigned char brightness = ((77*((color>>16)&0x00ff))
+ * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+ * - If only on and off are supported, 0 is off, anything else is on.
+ *
+ * The high byte should be ignored. Callers should set it to 0xff (which
+ * would correspond to 255 alpha).
+ */
+ int color;
+
+ /**
+ * To flash the light at a given rate, set flashMode to FLASH_TIMED.
+ */
+ FlashMode flashMode;
+
+ /**
+ * flashOnMs should be set to the number of milliseconds to turn the
+ * light on, before it's turned off.
+ */
+ int flashOnMs;
+
+ /**
+ * flashOfMs should be set to the number of milliseconds to turn the
+ * light off, before it's turned back on.
+ */
+ int flashOffMs;
+
+ BrightnessMode brightnessMode;
+}
diff --git a/light/aidl/android/hardware/light/ILights.aidl b/light/aidl/android/hardware/light/ILights.aidl
new file mode 100644
index 0000000..2253f73
--- /dev/null
+++ b/light/aidl/android/hardware/light/ILights.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.HwLightState;
+import android.hardware.light.HwLight;
+
+/**
+ * Allows controlling logical lights/indicators, mapped to LEDs in a
+ * hardware-specific manner by the HAL implementation.
+ */
+@VintfStability
+interface ILights {
+ /**
+ * Set light identified by id to the provided state.
+ *
+ * If control over an invalid light is requested, this method exists with
+ * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
+ * device-specific best-effort basis and unsupported sub-features will not
+ * be reported.
+ *
+ * @param id ID of logical light to set as returned by getLights()
+ * @param state describes what the light should look like.
+ */
+ void setLightState(in int id, in HwLightState state);
+
+ /**
+ * Discover what lights are supported by the HAL implementation.
+ *
+ * @return List of available lights
+ */
+ HwLight[] getLights();
+}
diff --git a/light/aidl/android/hardware/light/LightType.aidl b/light/aidl/android/hardware/light/LightType.aidl
new file mode 100644
index 0000000..9a7f656
--- /dev/null
+++ b/light/aidl/android/hardware/light/LightType.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+/**
+ * These light IDs correspond to logical lights, not physical.
+ * So for example, if your INDICATOR light is in line with your
+ * BUTTONS, it might make sense to also light the INDICATOR
+ * light to a reasonable color when the BUTTONS are lit.
+ */
+@VintfStability
+enum LightType {
+ BACKLIGHT = 0,
+ KEYBOARD = 1,
+ BUTTONS = 2,
+ BATTERY = 3,
+ NOTIFICATIONS = 4,
+ ATTENTION = 5,
+ BLUETOOTH = 6,
+ WIFI = 7,
+ MICROPHONE = 8,
+}
diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp
new file mode 100644
index 0000000..ae3f463
--- /dev/null
+++ b/light/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_binary {
+ name: "android.hardware.lights-service.example",
+ relative_install_path: "hw",
+ init_rc: ["lights-default.rc"],
+ vintf_fragments: ["lights-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.light-ndk_platform",
+ ],
+ srcs: [
+ "Lights.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
new file mode 100644
index 0000000..74747d5
--- /dev/null
+++ b/light/aidl/default/Lights.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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 "Lights.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
+ LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* /*lights*/) {
+ LOG(INFO) << "Lights reporting supported lights";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
new file mode 100644
index 0000000..8cba5a1
--- /dev/null
+++ b/light/aidl/default/Lights.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/light/BnLights.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+// Default implementation that reports no supported lights.
+class Lights : public BnLights {
+ ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
+ ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
+};
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/lights-default.rc b/light/aidl/default/lights-default.rc
new file mode 100644
index 0000000..687ec97
--- /dev/null
+++ b/light/aidl/default/lights-default.rc
@@ -0,0 +1,5 @@
+service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.example
+ class hal
+ user nobody
+ group nobody
+ shutdown critical
diff --git a/light/aidl/default/lights-default.xml b/light/aidl/default/lights-default.xml
new file mode 100644
index 0000000..db604d6
--- /dev/null
+++ b/light/aidl/default/lights-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.light</name>
+ <fqname>ILights/default</fqname>
+ </hal>
+</manifest>
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
new file mode 100644
index 0000000..a860bf4
--- /dev/null
+++ b/light/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lights.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::light::Lights;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
+
+ const std::string instance = std::string() + Lights::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3dd8cf6
--- /dev/null
+++ b/light/aidl/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalLightTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalLightTargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+}
diff --git a/light/aidl/vts/functional/VtsHalLightTargetTest.cpp b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
new file mode 100644
index 0000000..3c26278
--- /dev/null
+++ b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "light_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android-base/logging.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+#include <set>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::light::BrightnessMode;
+using android::hardware::light::FlashMode;
+using android::hardware::light::HwLight;
+using android::hardware::light::HwLightState;
+using android::hardware::light::ILights;
+using android::hardware::light::LightType;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+const std::set<LightType> kAllTypes{android::enum_range<LightType>().begin(),
+ android::enum_range<LightType>().end()};
+
+class LightsAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ lights = android::waitForDeclaredService<ILights>(String16(GetParam().c_str()));
+ ASSERT_NE(lights, nullptr);
+ ASSERT_TRUE(lights->getLights(&supportedLights).isOk());
+ }
+
+ sp<ILights> lights;
+ std::vector<HwLight> supportedLights;
+
+ virtual void TearDown() override {
+ for (const HwLight& light : supportedLights) {
+ HwLightState off;
+ off.color = 0x00000000;
+ off.flashMode = FlashMode::NONE;
+ off.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, off).isOk());
+ }
+
+ // must leave the device in a useable condition
+ for (const HwLight& light : supportedLights) {
+ if (light.type == LightType::BACKLIGHT) {
+ HwLightState backlightOn;
+ backlightOn.color = 0xFFFFFFFF;
+ backlightOn.flashMode = FlashMode::TIMED;
+ backlightOn.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, backlightOn).isOk());
+ }
+ }
+ }
+};
+
+/**
+ * Ensure all reported lights actually work.
+ */
+TEST_P(LightsAidl, TestSupported) {
+ HwLightState whiteFlashing;
+ whiteFlashing.color = 0xFFFFFFFF;
+ whiteFlashing.flashMode = FlashMode::TIMED;
+ whiteFlashing.flashOnMs = 100;
+ whiteFlashing.flashOffMs = 50;
+ whiteFlashing.brightnessMode = BrightnessMode::USER;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(lights->setLightState(light.id, whiteFlashing).isOk());
+ }
+}
+
+/**
+ * Ensure all reported lights have one of the supported types.
+ */
+TEST_P(LightsAidl, TestSupportedLightTypes) {
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(kAllTypes.find(light.type) != kAllTypes.end());
+ }
+}
+
+/**
+ * Ensure all lights have a unique id.
+ */
+TEST_P(LightsAidl, TestUniqueIds) {
+ std::set<int> ids;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(ids.find(light.id) == ids.end());
+ ids.insert(light.id);
+ }
+}
+
+/**
+ * Ensure all lights have a unique ordinal for a given type.
+ */
+TEST_P(LightsAidl, TestUniqueOrdinalsForType) {
+ std::map<int, std::set<int>> ordinalsByType;
+ for (const HwLight& light : supportedLights) {
+ auto& ordinals = ordinalsByType[(int)light.type];
+ EXPECT_TRUE(ordinals.find(light.ordinal) == ordinals.end());
+ ordinals.insert(light.ordinal);
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returned if LOW_PERSISTENCE is not supported.
+ */
+TEST_P(LightsAidl, TestLowPersistence) {
+ HwLightState lowPersistence;
+ lowPersistence.color = 0xFF123456;
+ lowPersistence.flashMode = FlashMode::TIMED;
+ lowPersistence.flashOnMs = 100;
+ lowPersistence.flashOffMs = 50;
+ lowPersistence.brightnessMode = BrightnessMode::LOW_PERSISTENCE;
+ for (const HwLight& light : supportedLights) {
+ Status status = lights->setLightState(light.id, lowPersistence);
+ EXPECT_TRUE(status.isOk() || Status::EX_UNSUPPORTED_OPERATION == status.exceptionCode());
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returns for an invalid light id.
+ */
+TEST_P(LightsAidl, TestInvalidLightIdUnsupported) {
+ int maxId = INT_MIN;
+ for (const HwLight& light : supportedLights) {
+ maxId = std::max(maxId, light.id);
+ }
+
+ Status status = lights->setLightState(maxId + 1, HwLightState());
+ EXPECT_TRUE(status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+}
+
+INSTANTIATE_TEST_SUITE_P(Lights, LightsAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ILights::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/light/utils/Android.bp b/light/utils/Android.bp
index 4c287e4..e901129 100644
--- a/light/utils/Android.bp
+++ b/light/utils/Android.bp
@@ -23,7 +23,11 @@
shared_libs: [
"android.hardware.light@2.0",
"libbase",
+ "libbinder",
"libhidlbase",
"libutils",
],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
}
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index b834132..b9b6489 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -19,34 +19,23 @@
#include <android-base/logging.h>
#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+
+using android::sp;
+using android::waitForVintfService;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+
+namespace V2_0 = android::hardware::light::V2_0;
+namespace aidl = android::hardware::light;
void error(const std::string& msg) {
LOG(ERROR) << msg;
std::cerr << msg << std::endl;
}
-int main(int argc, char* argv[]) {
- using ::android::hardware::hidl_vec;
- using ::android::hardware::light::V2_0::Brightness;
- using ::android::hardware::light::V2_0::Flash;
- using ::android::hardware::light::V2_0::ILight;
- using ::android::hardware::light::V2_0::LightState;
- using ::android::hardware::light::V2_0::Status;
- using ::android::hardware::light::V2_0::Type;
- using ::android::sp;
-
- sp<ILight> service = ILight::getService();
- if (service == nullptr) {
- error("Could not retrieve light service.");
- return -1;
- }
-
- static LightState off = {
- .color = 0u,
- .flashMode = Flash::NONE,
- .brightnessMode = Brightness::USER,
- };
-
+int parseArgs(int argc, char* argv[], unsigned int* color) {
if (argc > 2) {
error("Usage: blank_screen [color]");
return -1;
@@ -54,25 +43,78 @@
if (argc > 1) {
char* col_ptr;
- unsigned int col_new;
- col_new = strtoul(argv[1], &col_ptr, 0);
+ *color = strtoul(argv[1], &col_ptr, 0);
if (*col_ptr != '\0') {
error("Failed to convert " + std::string(argv[1]) + " to number");
return -1;
}
- off.color = col_new;
+
+ return 0;
}
- service->getSupportedTypes([&](const hidl_vec<Type>& types) {
- for (Type type : types) {
- Status ret = service->setLight(type, off);
- if (ret != Status::SUCCESS) {
- error("Failed to shut off screen for type " +
+ *color = 0u;
+ return 0;
+}
+
+void setToColorAidl(sp<aidl::ILights> hal, unsigned int color) {
+ static aidl::HwLightState off;
+ off.color = color;
+ off.flashMode = aidl::FlashMode::NONE;
+ off.brightnessMode = aidl::BrightnessMode::USER;
+
+ std::vector<aidl::HwLight> lights;
+ Status status = hal->getLights(&lights);
+ if (!status.isOk()) {
+ error("Failed to list lights");
+ return;
+ }
+
+ for (auto light : lights) {
+ Status setStatus = hal->setLightState(light.id, off);
+ if (!setStatus.isOk()) {
+ error("Failed to shut off light id " + std::to_string(light.id));
+ }
+ }
+}
+
+void setToColorHidl(sp<V2_0::ILight> hal, unsigned int color) {
+ static V2_0::LightState off = {
+ .color = color,
+ .flashMode = V2_0::Flash::NONE,
+ .brightnessMode = V2_0::Brightness::USER,
+ };
+
+ hal->getSupportedTypes([&](const hidl_vec<V2_0::Type>& types) {
+ for (auto type : types) {
+ V2_0::Status ret = hal->setLight(type, off);
+ if (ret != V2_0::Status::SUCCESS) {
+ error("Failed to shut off light for type " +
std::to_string(static_cast<int>(type)));
}
}
});
+}
- return 0;
+int main(int argc, char* argv[]) {
+ unsigned int inputColor;
+ int result = parseArgs(argc, argv, &inputColor);
+ if (result != 0) {
+ return result;
+ }
+
+ auto aidlHal = waitForVintfService<aidl::ILights>();
+ if (aidlHal != nullptr) {
+ setToColorAidl(aidlHal, inputColor);
+ return 0;
+ }
+
+ sp<V2_0::ILight> hidlHal = V2_0::ILight::getService();
+ if (hidlHal != nullptr) {
+ setToColorHidl(hidlHal, inputColor);
+ return 0;
+ }
+
+ error("Could not retrieve light service.");
+ return -1;
}