blob: 49ad8b5d69587a6f23ecef8f5ada9081ac43c30c [file] [log] [blame]
Chris Yee2b1e5c2021-03-10 22:45:12 -08001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <locale>
18#include <regex>
Vaibhav Devmurari16c24192023-05-04 15:20:12 +000019#include <sstream>
20#include <string>
Chris Yee2b1e5c2021-03-10 22:45:12 -080021
Vaibhav Devmurari16c24192023-05-04 15:20:12 +000022#include <android/sysprop/InputProperties.sysprop.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080023#include <ftl/enum.h>
Chris Yee2b1e5c2021-03-10 22:45:12 -080024
Dominik Laskowski75788452021-02-09 18:51:25 -080025#include "../Macros.h"
Chris Ye1dd2e5c2021-04-04 23:12:41 -070026#include "PeripheralController.h"
Chris Yee2b1e5c2021-03-10 22:45:12 -080027
Chris Yee2b1e5c2021-03-10 22:45:12 -080028namespace android {
29
30static inline int32_t getAlpha(int32_t color) {
31 return (color >> 24) & 0xff;
32}
33
34static inline int32_t getRed(int32_t color) {
35 return (color >> 16) & 0xff;
36}
37
38static inline int32_t getGreen(int32_t color) {
39 return (color >> 8) & 0xff;
40}
41
42static inline int32_t getBlue(int32_t color) {
43 return color & 0xff;
44}
45
46static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int32_t blue) {
47 return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
48}
49
Vaibhav Devmurari16c24192023-05-04 15:20:12 +000050static inline bool isKeyboardBacklightCustomLevelsEnabled() {
51 return sysprop::InputProperties::enable_keyboard_backlight_custom_levels().value_or(true);
52}
53
Chris Yee2b1e5c2021-03-10 22:45:12 -080054/**
55 * Input controller owned by InputReader device, implements the native API for querying input
56 * lights, getting and setting the lights brightness and color, by interacting with EventHub
57 * devices.
58 */
Chris Ye1dd2e5c2021-04-04 23:12:41 -070059PeripheralController::PeripheralController(InputDeviceContext& deviceContext)
Chris Yee2b1e5c2021-03-10 22:45:12 -080060 : mDeviceContext(deviceContext) {
61 configureBattries();
62 configureLights();
63}
64
Chris Ye1dd2e5c2021-04-04 23:12:41 -070065PeripheralController::~PeripheralController() {}
Chris Yee2b1e5c2021-03-10 22:45:12 -080066
Chris Ye1dd2e5c2021-04-04 23:12:41 -070067std::optional<std::int32_t> PeripheralController::Light::getRawLightBrightness(int32_t rawLightId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -080068 std::optional<RawLightInfo> rawInfoOpt = context.getRawLightInfo(rawLightId);
69 if (!rawInfoOpt.has_value()) {
70 return std::nullopt;
71 }
72 std::optional<int32_t> brightnessOpt = context.getLightBrightness(rawLightId);
73 if (!brightnessOpt.has_value()) {
74 return std::nullopt;
75 }
76 int brightness = brightnessOpt.value();
77
78 // If the light node doesn't have max brightness, use the default max brightness.
79 int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS);
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +000080 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
Chris Yee2b1e5c2021-03-10 22:45:12 -080081 // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
82 if (rawMaxBrightness != MAX_BRIGHTNESS) {
83 brightness = brightness * ratio;
84 }
85 if (DEBUG_LIGHT_DETAILS) {
86 ALOGD("getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
87 brightness, ratio);
88 }
89 return brightness;
90}
91
Chris Ye1dd2e5c2021-04-04 23:12:41 -070092void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
Chris Yee2b1e5c2021-03-10 22:45:12 -080093 std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
94 if (!rawInfo.has_value()) {
95 return;
96 }
97 // If the light node doesn't have max brightness, use the default max brightness.
98 int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +000099 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
Chris Yee2b1e5c2021-03-10 22:45:12 -0800100 // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
101 if (rawMaxBrightness != MAX_BRIGHTNESS) {
102 brightness = ceil(brightness / ratio);
103 }
104 if (DEBUG_LIGHT_DETAILS) {
105 ALOGD("setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
106 brightness, ratio);
107 }
108 context.setLightBrightness(rawLightId, brightness);
109}
110
Chris Ye85758332021-05-16 23:05:17 -0700111bool PeripheralController::MonoLight::setLightColor(int32_t color) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800112 int32_t brightness = getAlpha(color);
113 setRawLightBrightness(rawId, brightness);
114
115 return true;
116}
117
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700118bool PeripheralController::RgbLight::setLightColor(int32_t color) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800119 // Compose color value as per:
120 // https://developer.android.com/reference/android/graphics/Color?hl=en
121 // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
122 // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
123 // MAX_BRIGHTNESS.
124 brightness = getAlpha(color);
125 int32_t red = 0;
126 int32_t green = 0;
127 int32_t blue = 0;
128 if (brightness > 0) {
129 float ratio = MAX_BRIGHTNESS / brightness;
130 red = ceil(getRed(color) / ratio);
131 green = ceil(getGreen(color) / ratio);
132 blue = ceil(getBlue(color) / ratio);
133 }
134 setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
135 setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
136 setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
137 if (rawGlobalId.has_value()) {
138 setRawLightBrightness(rawGlobalId.value(), brightness);
139 }
140
141 return true;
142}
143
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700144bool PeripheralController::MultiColorLight::setLightColor(int32_t color) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800145 std::unordered_map<LightColor, int32_t> intensities;
146 intensities.emplace(LightColor::RED, getRed(color));
147 intensities.emplace(LightColor::GREEN, getGreen(color));
148 intensities.emplace(LightColor::BLUE, getBlue(color));
149
150 context.setLightIntensities(rawId, intensities);
151 setRawLightBrightness(rawId, getAlpha(color));
152 return true;
153}
154
Chris Ye85758332021-05-16 23:05:17 -0700155std::optional<int32_t> PeripheralController::MonoLight::getLightColor() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800156 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
157 if (!brightness.has_value()) {
158 return std::nullopt;
159 }
160
Harry Cutts33476232023-01-30 19:57:29 +0000161 return toArgb(brightness.value(), /*red=*/0, /*green=*/0, /*blue=*/0);
Chris Yee2b1e5c2021-03-10 22:45:12 -0800162}
163
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700164std::optional<int32_t> PeripheralController::RgbLight::getLightColor() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800165 // If the Alpha component is zero, then return color 0.
166 if (brightness == 0) {
167 return 0;
168 }
169 // Compose color value as per:
170 // https://developer.android.com/reference/android/graphics/Color?hl=en
171 // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
172 std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
173 std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
174 std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
175 // If we can't get brightness for any of the RGB light
176 if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
177 return std::nullopt;
178 }
179
180 // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
181 // value, scale it back to return the nominal color value.
182 float ratio = MAX_BRIGHTNESS / brightness;
183 int32_t red = round(redOr.value() * ratio);
184 int32_t green = round(greenOr.value() * ratio);
185 int32_t blue = round(blueOr.value() * ratio);
186
187 if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
188 // Previously stored brightness isn't valid for current LED values, so just reset to max
189 // brightness since an app couldn't have provided these values in the first place.
190 red = redOr.value();
191 green = greenOr.value();
192 blue = blueOr.value();
193 brightness = MAX_BRIGHTNESS;
194 }
195
196 return toArgb(brightness, red, green, blue);
197}
198
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700199std::optional<int32_t> PeripheralController::MultiColorLight::getLightColor() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800200 auto ret = context.getLightIntensities(rawId);
201 if (!ret.has_value()) {
202 return std::nullopt;
203 }
204 std::unordered_map<LightColor, int32_t> intensities = ret.value();
205 // Get red, green, blue colors
Harry Cutts33476232023-01-30 19:57:29 +0000206 int32_t color = toArgb(/*brightness=*/0, intensities.at(LightColor::RED),
207 intensities.at(LightColor::GREEN), intensities.at(LightColor::BLUE));
Chris Yee2b1e5c2021-03-10 22:45:12 -0800208 // Get brightness
209 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
210 if (brightness.has_value()) {
Harry Cutts33476232023-01-30 19:57:29 +0000211 return toArgb(/*brightness=*/brightness.value(), 0, 0, 0) | color;
Chris Yee2b1e5c2021-03-10 22:45:12 -0800212 }
213 return std::nullopt;
214}
215
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700216bool PeripheralController::PlayerIdLight::setLightPlayerId(int32_t playerId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800217 if (rawLightIds.find(playerId) == rawLightIds.end()) {
218 return false;
219 }
220 for (const auto& [id, rawId] : rawLightIds) {
221 if (playerId == id) {
222 setRawLightBrightness(rawId, MAX_BRIGHTNESS);
223 } else {
224 setRawLightBrightness(rawId, 0);
225 }
226 }
227 return true;
228}
229
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700230std::optional<int32_t> PeripheralController::PlayerIdLight::getLightPlayerId() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800231 for (const auto& [id, rawId] : rawLightIds) {
232 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
233 if (brightness.has_value() && brightness.value() > 0) {
234 return id;
235 }
236 }
237 return std::nullopt;
238}
239
Chris Ye85758332021-05-16 23:05:17 -0700240void PeripheralController::MonoLight::dump(std::string& dump) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800241 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
242}
243
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700244void PeripheralController::PlayerIdLight::dump(std::string& dump) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800245 dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
246 dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
247 for (const auto& [id, rawId] : rawLightIds) {
248 dump += StringPrintf("id %d -> %d ", id, rawId);
249 }
250 dump += "\n";
251}
252
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700253void PeripheralController::RgbLight::dump(std::string& dump) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800254 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
255 dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
256 rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
257 if (rawGlobalId.has_value()) {
258 dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
259 }
260 dump += "\n";
261}
262
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700263void PeripheralController::MultiColorLight::dump(std::string& dump) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800264 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
265}
266
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700267void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800268 // TODO: b/180733860 Remove this after enabling multi-battery
269 if (!mBatteries.empty()) {
270 deviceInfo->setHasBattery(true);
271 }
272
273 for (const auto& [batteryId, battery] : mBatteries) {
274 InputDeviceBatteryInfo batteryInfo(battery->name, battery->id);
275 deviceInfo->addBatteryInfo(batteryInfo);
276 }
277
278 for (const auto& [lightId, light] : mLights) {
279 // Input device light doesn't support ordinal, always pass 1.
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000280 InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags,
Vaibhav Devmurari16c24192023-05-04 15:20:12 +0000281 /*ordinal=*/1, getPreferredBrightnessLevels(light.get()));
Chris Yee2b1e5c2021-03-10 22:45:12 -0800282 deviceInfo->addLightInfo(lightInfo);
283 }
284}
285
Vaibhav Devmurari16c24192023-05-04 15:20:12 +0000286// TODO(b/281822656): Move to constructor and add as a parameter to avoid parsing repeatedly.
287// Need to change lifecycle of Peripheral controller so that Input device configuration map is
288// available at construction time before moving this logic to constructor.
289std::set<BrightnessLevel> PeripheralController::getPreferredBrightnessLevels(
290 const Light* light) const {
291 std::set<BrightnessLevel> levels;
292 if (!isKeyboardBacklightCustomLevelsEnabled() ||
293 light->type != InputDeviceLightType::KEYBOARD_BACKLIGHT) {
294 return levels;
295 }
296 std::optional<std::string> keyboardBacklightLevels =
297 mDeviceContext.getConfiguration().getString("keyboard.backlight.brightnessLevels");
298 if (!keyboardBacklightLevels) {
299 return levels;
300 }
301 std::stringstream ss(*keyboardBacklightLevels);
302 while (ss.good()) {
303 std::string substr;
304 std::getline(ss, substr, ',');
305 char* end;
306 int32_t value = static_cast<int32_t>(strtol(substr.c_str(), &end, 10));
307 if (*end != '\0' || value < 0 || value > 255) {
308 ALOGE("Error parsing keyboard backlight brightness levels, provided levels = %s",
309 keyboardBacklightLevels->c_str());
310 levels.clear();
311 break;
312 }
313 levels.insert(BrightnessLevel(value));
314 }
315 return levels;
316}
317
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700318void PeripheralController::dump(std::string& dump) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800319 dump += INDENT2 "Input Controller:\n";
320 if (!mLights.empty()) {
321 dump += INDENT3 "Lights:\n";
322 for (const auto& [lightId, light] : mLights) {
323 dump += StringPrintf(INDENT4 "Id: %d", lightId);
324 dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
Dominik Laskowski75788452021-02-09 18:51:25 -0800325 dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000326 dump += StringPrintf(INDENT4 "Capability flags: %s",
327 light->capabilityFlags.string().c_str());
Chris Yee2b1e5c2021-03-10 22:45:12 -0800328 light->dump(dump);
329 }
330 }
331 // Dump raw lights
332 dump += INDENT3 "RawLights:\n";
333 dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
334 const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
335 // Map from raw light id to raw light info
336 std::unordered_map<int32_t, RawLightInfo> rawInfos;
337 for (const auto& rawId : rawLightIds) {
338 std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
339 if (!rawInfo.has_value()) {
340 continue;
341 }
342 dump += StringPrintf(INDENT4 "%d", rawId);
343 dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
344 dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
345 dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
346 dump += StringPrintf(INDENT4 "%d\n",
347 getDeviceContext().getLightBrightness(rawId).value_or(-1));
348 }
349
350 if (!mBatteries.empty()) {
351 dump += INDENT3 "Batteries:\n";
352 for (const auto& [batteryId, battery] : mBatteries) {
353 dump += StringPrintf(INDENT4 "Id: %d", batteryId);
354 dump += StringPrintf(INDENT4 "Name: %s", battery->name.c_str());
355 dump += getBatteryCapacity(batteryId).has_value()
356 ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity(batteryId).value())
357 : StringPrintf(INDENT3 "Capacity: Unknown");
358
359 std::string status;
360 switch (getBatteryStatus(batteryId).value_or(BATTERY_STATUS_UNKNOWN)) {
361 case BATTERY_STATUS_CHARGING:
362 status = "Charging";
363 break;
364 case BATTERY_STATUS_DISCHARGING:
365 status = "Discharging";
366 break;
367 case BATTERY_STATUS_NOT_CHARGING:
368 status = "Not charging";
369 break;
370 case BATTERY_STATUS_FULL:
371 status = "Full";
372 break;
373 default:
374 status = "Unknown";
375 }
376 dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
377 }
378 }
379}
380
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700381void PeripheralController::configureBattries() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800382 // Check raw batteries
383 const std::vector<int32_t> rawBatteryIds = getDeviceContext().getRawBatteryIds();
384
385 for (const auto& rawId : rawBatteryIds) {
386 std::optional<RawBatteryInfo> rawInfo = getDeviceContext().getRawBatteryInfo(rawId);
387 if (!rawInfo.has_value()) {
388 continue;
389 }
390 std::unique_ptr<Battery> battery =
391 std::make_unique<Battery>(getDeviceContext(), rawInfo->name, rawInfo->id);
392 mBatteries.insert_or_assign(rawId, std::move(battery));
393 }
394}
395
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700396void PeripheralController::configureLights() {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800397 bool hasRedLed = false;
398 bool hasGreenLed = false;
399 bool hasBlueLed = false;
400 std::optional<int32_t> rawGlobalId = std::nullopt;
401 // Player ID light common name string
402 std::string playerIdName;
403 // Raw RGB color to raw light ID
404 std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
405 // Map from player Id to raw light Id
406 std::unordered_map<int32_t, int32_t> playerIdLightIds;
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000407 // Set of Keyboard backlights
408 std::set<int32_t> keyboardBacklightIds;
Chris Yee2b1e5c2021-03-10 22:45:12 -0800409
410 // Check raw lights
411 const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
412 // Map from raw light id to raw light info
413 std::unordered_map<int32_t, RawLightInfo> rawInfos;
414 for (const auto& rawId : rawLightIds) {
415 std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
416 if (!rawInfo.has_value()) {
417 continue;
418 }
419 rawInfos.insert_or_assign(rawId, rawInfo.value());
420 // Check if this is a group LEDs for player ID
Josep del Rioa1046a82023-08-24 19:57:27 +0000421 // The name for the light has already been parsed and is the `function`
422 // value; for player ID lights the function is expected to be `player-#`.
423 // However, the Sony driver will use `sony#` instead on SIXAXIS
424 // gamepads.
425 std::regex lightPattern("(player|sony)-?([0-9]+)");
Chris Yee2b1e5c2021-03-10 22:45:12 -0800426 std::smatch results;
427 if (std::regex_match(rawInfo->name, results, lightPattern)) {
428 std::string commonName = results[1].str();
429 int32_t playerId = std::stoi(results[2]);
430 if (playerIdLightIds.empty()) {
431 playerIdName = commonName;
432 playerIdLightIds.insert_or_assign(playerId, rawId);
433 } else {
434 // Make sure the player ID leds have common string name
435 if (playerIdName.compare(commonName) == 0 &&
436 playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
437 playerIdLightIds.insert_or_assign(playerId, rawId);
438 }
439 }
440 }
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000441 // Check if this is a Keyboard backlight
442 if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) {
443 keyboardBacklightIds.insert(rawId);
444 }
Chris Yee2b1e5c2021-03-10 22:45:12 -0800445 // Check if this is an LED of RGB light
446 if (rawInfo->flags.test(InputLightClass::RED)) {
447 hasRedLed = true;
448 rawRgbIds.emplace(LightColor::RED, rawId);
449 }
450 if (rawInfo->flags.test(InputLightClass::GREEN)) {
451 hasGreenLed = true;
452 rawRgbIds.emplace(LightColor::GREEN, rawId);
453 }
454 if (rawInfo->flags.test(InputLightClass::BLUE)) {
455 hasBlueLed = true;
456 rawRgbIds.emplace(LightColor::BLUE, rawId);
457 }
458 if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
459 rawGlobalId = rawId;
460 }
461 if (DEBUG_LIGHT_DETAILS) {
462 ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id, rawInfo->name.c_str(),
463 rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS), rawInfo->flags.string().c_str());
464 }
465 }
466
467 // Construct a player ID light
468 if (playerIdLightIds.size() > 1) {
469 std::unique_ptr<Light> light =
470 std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
471 playerIdLightIds);
472 mLights.insert_or_assign(light->id, std::move(light));
473 // Remove these raw lights from raw light info as they've been used to compose a
Chris Ye85758332021-05-16 23:05:17 -0700474 // Player ID light, so we do not expose these raw lights as mono lights.
Chris Yee2b1e5c2021-03-10 22:45:12 -0800475 for (const auto& [playerId, rawId] : playerIdLightIds) {
476 rawInfos.erase(rawId);
477 }
478 }
479 // Construct a RGB light for composed RGB light
480 if (hasRedLed && hasGreenLed && hasBlueLed) {
481 if (DEBUG_LIGHT_DETAILS) {
482 ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
483 rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
484 }
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000485 bool isKeyboardBacklight = keyboardBacklightIds.find(rawRgbIds.at(LightColor::RED)) !=
486 keyboardBacklightIds.end() &&
487 keyboardBacklightIds.find(rawRgbIds.at(LightColor::GREEN)) !=
488 keyboardBacklightIds.end() &&
489 keyboardBacklightIds.find(rawRgbIds.at(LightColor::BLUE)) !=
490 keyboardBacklightIds.end() &&
491 (!rawGlobalId.has_value() ||
492 keyboardBacklightIds.find(rawGlobalId.value()) != keyboardBacklightIds.end());
493
Chris Yee2b1e5c2021-03-10 22:45:12 -0800494 std::unique_ptr<Light> light =
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000495 std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
496 isKeyboardBacklight
497 ? InputDeviceLightType::KEYBOARD_BACKLIGHT
498 : InputDeviceLightType::INPUT,
499 rawRgbIds, rawGlobalId);
Chris Yee2b1e5c2021-03-10 22:45:12 -0800500 mLights.insert_or_assign(light->id, std::move(light));
501 // Remove from raw light info as they've been composed a RBG light.
502 rawInfos.erase(rawRgbIds.at(LightColor::RED));
503 rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
504 rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
505 if (rawGlobalId.has_value()) {
506 rawInfos.erase(rawGlobalId.value());
507 }
508 }
509
510 // Check the rest of raw light infos
511 for (const auto& [rawId, rawInfo] : rawInfos) {
DingYong99f2c3c2023-12-20 15:46:06 +0800512 InputDeviceLightType type;
513 if (keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()) {
514 type = InputDeviceLightType::KEYBOARD_BACKLIGHT;
515 } else if (rawInfo.flags.test(InputLightClass::KEYBOARD_MIC_MUTE)) {
516 type = InputDeviceLightType::KEYBOARD_MIC_MUTE;
517 } else {
518 type = InputDeviceLightType::INPUT;
519 }
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000520
Chris Yee2b1e5c2021-03-10 22:45:12 -0800521 // If the node is multi-color led, construct a MULTI_COLOR light
522 if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
523 rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) {
524 if (DEBUG_LIGHT_DETAILS) {
525 ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
526 }
527 std::unique_ptr<Light> light =
528 std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId,
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000529 type, rawInfo.id);
Chris Yee2b1e5c2021-03-10 22:45:12 -0800530 mLights.insert_or_assign(light->id, std::move(light));
531 continue;
532 }
Chris Ye85758332021-05-16 23:05:17 -0700533 // Construct a Mono LED light
Chris Yee2b1e5c2021-03-10 22:45:12 -0800534 if (DEBUG_LIGHT_DETAILS) {
Chris Ye85758332021-05-16 23:05:17 -0700535 ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
Chris Yee2b1e5c2021-03-10 22:45:12 -0800536 }
Chris Ye85758332021-05-16 23:05:17 -0700537 std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name,
Vaibhav Devmurari82b37d62022-09-12 13:36:48 +0000538 ++mNextId, type, rawInfo.id);
Chris Yee2b1e5c2021-03-10 22:45:12 -0800539
540 mLights.insert_or_assign(light->id, std::move(light));
541 }
542}
543
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700544std::optional<int32_t> PeripheralController::getBatteryCapacity(int batteryId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800545 return getDeviceContext().getBatteryCapacity(batteryId);
546}
547
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700548std::optional<int32_t> PeripheralController::getBatteryStatus(int batteryId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800549 return getDeviceContext().getBatteryStatus(batteryId);
550}
551
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700552bool PeripheralController::setLightColor(int32_t lightId, int32_t color) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800553 auto it = mLights.find(lightId);
554 if (it == mLights.end()) {
555 return false;
556 }
557 auto& light = it->second;
558 if (DEBUG_LIGHT_DETAILS) {
559 ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
Dominik Laskowski75788452021-02-09 18:51:25 -0800560 ftl::enum_string(light->type).c_str(), color);
Chris Yee2b1e5c2021-03-10 22:45:12 -0800561 }
562 return light->setLightColor(color);
563}
564
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700565std::optional<int32_t> PeripheralController::getLightColor(int32_t lightId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800566 auto it = mLights.find(lightId);
567 if (it == mLights.end()) {
568 return std::nullopt;
569 }
570 auto& light = it->second;
571 std::optional<int32_t> color = light->getLightColor();
572 if (DEBUG_LIGHT_DETAILS) {
573 ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
Dominik Laskowski75788452021-02-09 18:51:25 -0800574 ftl::enum_string(light->type).c_str(), color.value_or(0));
Chris Yee2b1e5c2021-03-10 22:45:12 -0800575 }
576 return color;
577}
578
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700579bool PeripheralController::setLightPlayerId(int32_t lightId, int32_t playerId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800580 auto it = mLights.find(lightId);
581 if (it == mLights.end()) {
582 return false;
583 }
584 auto& light = it->second;
585 return light->setLightPlayerId(playerId);
586}
587
Chris Ye1dd2e5c2021-04-04 23:12:41 -0700588std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) {
Chris Yee2b1e5c2021-03-10 22:45:12 -0800589 auto it = mLights.find(lightId);
590 if (it == mLights.end()) {
591 return std::nullopt;
592 }
593 auto& light = it->second;
594 return light->getLightPlayerId();
595}
596
Andy Chenf9f1a022022-08-29 20:07:10 -0400597int32_t PeripheralController::getEventHubId() const {
598 return getDeviceContext().getEventHubId();
599}
Chris Yee2b1e5c2021-03-10 22:45:12 -0800600} // namespace android