1 /*
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>
19 #include <sstream>
20 #include <string>
21
22 #include <android/sysprop/InputProperties.sysprop.h>
23 #include <ftl/enum.h>
24
25 #include "../Macros.h"
26 #include "PeripheralController.h"
27
28 namespace android {
29
getAlpha(int32_t color)30 static inline int32_t getAlpha(int32_t color) {
31 return (color >> 24) & 0xff;
32 }
33
getRed(int32_t color)34 static inline int32_t getRed(int32_t color) {
35 return (color >> 16) & 0xff;
36 }
37
getGreen(int32_t color)38 static inline int32_t getGreen(int32_t color) {
39 return (color >> 8) & 0xff;
40 }
41
getBlue(int32_t color)42 static inline int32_t getBlue(int32_t color) {
43 return color & 0xff;
44 }
45
toArgb(int32_t brightness,int32_t red,int32_t green,int32_t blue)46 static 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
isKeyboardBacklightCustomLevelsEnabled()50 static inline bool isKeyboardBacklightCustomLevelsEnabled() {
51 return sysprop::InputProperties::enable_keyboard_backlight_custom_levels().value_or(true);
52 }
53
54 /**
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 */
PeripheralController(InputDeviceContext & deviceContext)59 PeripheralController::PeripheralController(InputDeviceContext& deviceContext)
60 : mDeviceContext(deviceContext) {
61 configureBattries();
62 configureLights();
63 }
64
~PeripheralController()65 PeripheralController::~PeripheralController() {}
66
getRawLightBrightness(int32_t rawLightId)67 std::optional<std::int32_t> PeripheralController::Light::getRawLightBrightness(int32_t rawLightId) {
68 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);
80 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
81 // 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
setRawLightBrightness(int32_t rawLightId,int32_t brightness)92 void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
93 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);
99 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
100 // 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
setLightColor(int32_t color)111 bool PeripheralController::MonoLight::setLightColor(int32_t color) {
112 int32_t brightness = getAlpha(color);
113 setRawLightBrightness(rawId, brightness);
114
115 return true;
116 }
117
setLightColor(int32_t color)118 bool PeripheralController::RgbLight::setLightColor(int32_t color) {
119 // 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
setLightColor(int32_t color)144 bool PeripheralController::MultiColorLight::setLightColor(int32_t color) {
145 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
getLightColor()155 std::optional<int32_t> PeripheralController::MonoLight::getLightColor() {
156 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
157 if (!brightness.has_value()) {
158 return std::nullopt;
159 }
160
161 return toArgb(brightness.value(), /*red=*/0, /*green=*/0, /*blue=*/0);
162 }
163
getLightColor()164 std::optional<int32_t> PeripheralController::RgbLight::getLightColor() {
165 // 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
getLightColor()199 std::optional<int32_t> PeripheralController::MultiColorLight::getLightColor() {
200 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
206 int32_t color = toArgb(/*brightness=*/0, intensities.at(LightColor::RED),
207 intensities.at(LightColor::GREEN), intensities.at(LightColor::BLUE));
208 // Get brightness
209 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
210 if (brightness.has_value()) {
211 return toArgb(/*brightness=*/brightness.value(), 0, 0, 0) | color;
212 }
213 return std::nullopt;
214 }
215
setLightPlayerId(int32_t playerId)216 bool PeripheralController::PlayerIdLight::setLightPlayerId(int32_t playerId) {
217 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
getLightPlayerId()230 std::optional<int32_t> PeripheralController::PlayerIdLight::getLightPlayerId() {
231 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
dump(std::string & dump)240 void PeripheralController::MonoLight::dump(std::string& dump) {
241 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
242 }
243
dump(std::string & dump)244 void PeripheralController::PlayerIdLight::dump(std::string& dump) {
245 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
dump(std::string & dump)253 void PeripheralController::RgbLight::dump(std::string& dump) {
254 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
dump(std::string & dump)263 void PeripheralController::MultiColorLight::dump(std::string& dump) {
264 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
265 }
266
populateDeviceInfo(InputDeviceInfo * deviceInfo)267 void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) {
268 // 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.
280 InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags,
281 /*ordinal=*/1, getPreferredBrightnessLevels(light.get()));
282 deviceInfo->addLightInfo(lightInfo);
283 }
284 }
285
286 // 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.
getPreferredBrightnessLevels(const Light * light) const289 std::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
dump(std::string & dump)318 void PeripheralController::dump(std::string& dump) {
319 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());
325 dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
326 dump += StringPrintf(INDENT4 "Capability flags: %s",
327 light->capabilityFlags.string().c_str());
328 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
configureBattries()381 void PeripheralController::configureBattries() {
382 // 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
configureLights()396 void PeripheralController::configureLights() {
397 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;
407 // Set of Keyboard backlights
408 std::set<int32_t> keyboardBacklightIds;
409
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
421 // 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]+)");
426 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 }
441 // Check if this is a Keyboard backlight
442 if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) {
443 keyboardBacklightIds.insert(rawId);
444 }
445 // 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
474 // Player ID light, so we do not expose these raw lights as mono lights.
475 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 }
485 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
494 std::unique_ptr<Light> light =
495 std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
496 isKeyboardBacklight
497 ? InputDeviceLightType::KEYBOARD_BACKLIGHT
498 : InputDeviceLightType::INPUT,
499 rawRgbIds, rawGlobalId);
500 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) {
512 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 }
520
521 // 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,
529 type, rawInfo.id);
530 mLights.insert_or_assign(light->id, std::move(light));
531 continue;
532 }
533 // Construct a Mono LED light
534 if (DEBUG_LIGHT_DETAILS) {
535 ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
536 }
537 std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name,
538 ++mNextId, type, rawInfo.id);
539
540 mLights.insert_or_assign(light->id, std::move(light));
541 }
542 }
543
getBatteryCapacity(int batteryId)544 std::optional<int32_t> PeripheralController::getBatteryCapacity(int batteryId) {
545 return getDeviceContext().getBatteryCapacity(batteryId);
546 }
547
getBatteryStatus(int batteryId)548 std::optional<int32_t> PeripheralController::getBatteryStatus(int batteryId) {
549 return getDeviceContext().getBatteryStatus(batteryId);
550 }
551
setLightColor(int32_t lightId,int32_t color)552 bool PeripheralController::setLightColor(int32_t lightId, int32_t color) {
553 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,
560 ftl::enum_string(light->type).c_str(), color);
561 }
562 return light->setLightColor(color);
563 }
564
getLightColor(int32_t lightId)565 std::optional<int32_t> PeripheralController::getLightColor(int32_t lightId) {
566 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,
574 ftl::enum_string(light->type).c_str(), color.value_or(0));
575 }
576 return color;
577 }
578
setLightPlayerId(int32_t lightId,int32_t playerId)579 bool PeripheralController::setLightPlayerId(int32_t lightId, int32_t playerId) {
580 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
getLightPlayerId(int32_t lightId)588 std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) {
589 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
getEventHubId() const597 int32_t PeripheralController::getEventHubId() const {
598 return getDeviceContext().getEventHubId();
599 }
600 } // namespace android
601