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
50 /**
51 * Input controller owned by InputReader device, implements the native API for querying input
52 * lights, getting and setting the lights brightness and color, by interacting with EventHub
53 * devices.
54 */
PeripheralController(InputDeviceContext & deviceContext)55 PeripheralController::PeripheralController(InputDeviceContext& deviceContext)
56 : mDeviceContext(deviceContext) {
57 configureBattries();
58 configureLights();
59 }
60
~PeripheralController()61 PeripheralController::~PeripheralController() {}
62
getRawLightBrightness(int32_t rawLightId)63 std::optional<std::int32_t> PeripheralController::Light::getRawLightBrightness(int32_t rawLightId) {
64 std::optional<RawLightInfo> rawInfoOpt = context.getRawLightInfo(rawLightId);
65 if (!rawInfoOpt.has_value()) {
66 return std::nullopt;
67 }
68 std::optional<int32_t> brightnessOpt = context.getLightBrightness(rawLightId);
69 if (!brightnessOpt.has_value()) {
70 return std::nullopt;
71 }
72 int brightness = brightnessOpt.value();
73
74 // If the light node doesn't have max brightness, use the default max brightness.
75 int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS);
76 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
77 // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
78 if (rawMaxBrightness != MAX_BRIGHTNESS) {
79 brightness = brightness * ratio;
80 }
81 ALOGD_IF(DEBUG_LIGHT_DETAILS, "getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f",
82 rawLightId, brightness, ratio);
83 return brightness;
84 }
85
setRawLightBrightness(int32_t rawLightId,int32_t brightness)86 void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
87 std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
88 if (!rawInfo.has_value()) {
89 return;
90 }
91 // If the light node doesn't have max brightness, use the default max brightness.
92 int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
93 float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
94 // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
95 if (rawMaxBrightness != MAX_BRIGHTNESS) {
96 brightness = ceil(brightness / ratio);
97 }
98 ALOGD_IF(DEBUG_LIGHT_DETAILS, "setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f",
99 rawLightId, brightness, ratio);
100 context.setLightBrightness(rawLightId, brightness);
101 }
102
setLightColor(int32_t color)103 bool PeripheralController::MonoLight::setLightColor(int32_t color) {
104 int32_t brightness = getAlpha(color);
105 setRawLightBrightness(rawId, brightness);
106
107 return true;
108 }
109
setLightColor(int32_t color)110 bool PeripheralController::RgbLight::setLightColor(int32_t color) {
111 // Compose color value as per:
112 // https://developer.android.com/reference/android/graphics/Color?hl=en
113 // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
114 // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
115 // MAX_BRIGHTNESS.
116 brightness = getAlpha(color);
117 int32_t red = 0;
118 int32_t green = 0;
119 int32_t blue = 0;
120 if (brightness > 0) {
121 float ratio = MAX_BRIGHTNESS / brightness;
122 red = ceil(getRed(color) / ratio);
123 green = ceil(getGreen(color) / ratio);
124 blue = ceil(getBlue(color) / ratio);
125 }
126 setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
127 setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
128 setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
129 if (rawGlobalId.has_value()) {
130 setRawLightBrightness(rawGlobalId.value(), brightness);
131 }
132
133 return true;
134 }
135
setLightColor(int32_t color)136 bool PeripheralController::MultiColorLight::setLightColor(int32_t color) {
137 std::unordered_map<LightColor, int32_t> intensities;
138 intensities.emplace(LightColor::RED, getRed(color));
139 intensities.emplace(LightColor::GREEN, getGreen(color));
140 intensities.emplace(LightColor::BLUE, getBlue(color));
141
142 context.setLightIntensities(rawId, intensities);
143 setRawLightBrightness(rawId, getAlpha(color));
144 return true;
145 }
146
getLightColor()147 std::optional<int32_t> PeripheralController::MonoLight::getLightColor() {
148 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
149 if (!brightness.has_value()) {
150 return std::nullopt;
151 }
152
153 return toArgb(brightness.value(), /*red=*/0, /*green=*/0, /*blue=*/0);
154 }
155
getLightColor()156 std::optional<int32_t> PeripheralController::RgbLight::getLightColor() {
157 // If the Alpha component is zero, then return color 0.
158 if (brightness == 0) {
159 return 0;
160 }
161 // Compose color value as per:
162 // https://developer.android.com/reference/android/graphics/Color?hl=en
163 // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
164 std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
165 std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
166 std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
167 // If we can't get brightness for any of the RGB light
168 if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
169 return std::nullopt;
170 }
171
172 // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
173 // value, scale it back to return the nominal color value.
174 float ratio = MAX_BRIGHTNESS / brightness;
175 int32_t red = round(redOr.value() * ratio);
176 int32_t green = round(greenOr.value() * ratio);
177 int32_t blue = round(blueOr.value() * ratio);
178
179 if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
180 // Previously stored brightness isn't valid for current LED values, so just reset to max
181 // brightness since an app couldn't have provided these values in the first place.
182 red = redOr.value();
183 green = greenOr.value();
184 blue = blueOr.value();
185 brightness = MAX_BRIGHTNESS;
186 }
187
188 return toArgb(brightness, red, green, blue);
189 }
190
getLightColor()191 std::optional<int32_t> PeripheralController::MultiColorLight::getLightColor() {
192 auto ret = context.getLightIntensities(rawId);
193 if (!ret.has_value()) {
194 return std::nullopt;
195 }
196 std::unordered_map<LightColor, int32_t> intensities = ret.value();
197 // Get red, green, blue colors
198 int32_t color = toArgb(/*brightness=*/0, intensities.at(LightColor::RED),
199 intensities.at(LightColor::GREEN), intensities.at(LightColor::BLUE));
200 // Get brightness
201 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
202 if (brightness.has_value()) {
203 return toArgb(/*brightness=*/brightness.value(), 0, 0, 0) | color;
204 }
205 return std::nullopt;
206 }
207
setLightPlayerId(int32_t playerId)208 bool PeripheralController::PlayerIdLight::setLightPlayerId(int32_t playerId) {
209 if (rawLightIds.find(playerId) == rawLightIds.end()) {
210 return false;
211 }
212 for (const auto& [id, rawId] : rawLightIds) {
213 if (playerId == id) {
214 setRawLightBrightness(rawId, MAX_BRIGHTNESS);
215 } else {
216 setRawLightBrightness(rawId, 0);
217 }
218 }
219 return true;
220 }
221
getLightPlayerId()222 std::optional<int32_t> PeripheralController::PlayerIdLight::getLightPlayerId() {
223 for (const auto& [id, rawId] : rawLightIds) {
224 std::optional<int32_t> brightness = getRawLightBrightness(rawId);
225 if (brightness.has_value() && brightness.value() > 0) {
226 return id;
227 }
228 }
229 return std::nullopt;
230 }
231
dump(std::string & dump)232 void PeripheralController::MonoLight::dump(std::string& dump) {
233 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
234 }
235
dump(std::string & dump)236 void PeripheralController::PlayerIdLight::dump(std::string& dump) {
237 dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
238 dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
239 for (const auto& [id, rawId] : rawLightIds) {
240 dump += StringPrintf("id %d -> %d ", id, rawId);
241 }
242 dump += "\n";
243 }
244
dump(std::string & dump)245 void PeripheralController::RgbLight::dump(std::string& dump) {
246 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
247 dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
248 rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
249 if (rawGlobalId.has_value()) {
250 dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
251 }
252 dump += "\n";
253 }
254
dump(std::string & dump)255 void PeripheralController::MultiColorLight::dump(std::string& dump) {
256 dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
257 }
258
populateDeviceInfo(InputDeviceInfo * deviceInfo)259 void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) {
260 // TODO: b/180733860 Remove this after enabling multi-battery
261 if (!mBatteries.empty()) {
262 deviceInfo->setHasBattery(true);
263 }
264
265 for (const auto& [batteryId, battery] : mBatteries) {
266 InputDeviceBatteryInfo batteryInfo(battery->name, battery->id);
267 deviceInfo->addBatteryInfo(batteryInfo);
268 }
269
270 for (const auto& [lightId, light] : mLights) {
271 // Input device light doesn't support ordinal, always pass 1.
272 InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags,
273 /*ordinal=*/1, getPreferredBrightnessLevels(light.get()));
274 deviceInfo->addLightInfo(lightInfo);
275 }
276 }
277
278 // TODO(b/281822656): Move to constructor and add as a parameter to avoid parsing repeatedly.
279 // Need to change lifecycle of Peripheral controller so that Input device configuration map is
280 // available at construction time before moving this logic to constructor.
getPreferredBrightnessLevels(const Light * light) const281 std::set<BrightnessLevel> PeripheralController::getPreferredBrightnessLevels(
282 const Light* light) const {
283 std::set<BrightnessLevel> levels;
284 if (light->type != InputDeviceLightType::KEYBOARD_BACKLIGHT) {
285 return levels;
286 }
287 std::optional<std::string> keyboardBacklightLevels =
288 mDeviceContext.getConfiguration().getString("keyboard.backlight.brightnessLevels");
289 if (!keyboardBacklightLevels) {
290 return levels;
291 }
292 std::stringstream ss(*keyboardBacklightLevels);
293 while (ss.good()) {
294 std::string substr;
295 std::getline(ss, substr, ',');
296 char* end;
297 int32_t value = static_cast<int32_t>(strtol(substr.c_str(), &end, 10));
298 if (*end != '\0' || value < 0 || value > 255) {
299 ALOGE("Error parsing keyboard backlight brightness levels, provided levels = %s",
300 keyboardBacklightLevels->c_str());
301 levels.clear();
302 break;
303 }
304 levels.insert(BrightnessLevel(value));
305 }
306 return levels;
307 }
308
dump(std::string & dump)309 void PeripheralController::dump(std::string& dump) {
310 dump += INDENT2 "Input Controller:\n";
311 if (!mLights.empty()) {
312 dump += INDENT3 "Lights:\n";
313 for (const auto& [lightId, light] : mLights) {
314 dump += StringPrintf(INDENT4 "Id: %d", lightId);
315 dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
316 dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
317 dump += StringPrintf(INDENT4 "Capability flags: %s",
318 light->capabilityFlags.string().c_str());
319 light->dump(dump);
320 }
321 }
322 // Dump raw lights
323 dump += INDENT3 "RawLights:\n";
324 dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
325 const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
326 // Map from raw light id to raw light info
327 std::unordered_map<int32_t, RawLightInfo> rawInfos;
328 for (const auto& rawId : rawLightIds) {
329 std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
330 if (!rawInfo.has_value()) {
331 continue;
332 }
333 dump += StringPrintf(INDENT4 "%d", rawId);
334 dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
335 dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
336 dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
337 dump += StringPrintf(INDENT4 "%d\n",
338 getDeviceContext().getLightBrightness(rawId).value_or(-1));
339 }
340
341 if (!mBatteries.empty()) {
342 dump += INDENT3 "Batteries:\n";
343 for (const auto& [batteryId, battery] : mBatteries) {
344 dump += StringPrintf(INDENT4 "Id: %d", batteryId);
345 dump += StringPrintf(INDENT4 "Name: %s", battery->name.c_str());
346 dump += getBatteryCapacity(batteryId).has_value()
347 ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity(batteryId).value())
348 : StringPrintf(INDENT3 "Capacity: Unknown");
349
350 std::string status;
351 switch (getBatteryStatus(batteryId).value_or(BATTERY_STATUS_UNKNOWN)) {
352 case BATTERY_STATUS_CHARGING:
353 status = "Charging";
354 break;
355 case BATTERY_STATUS_DISCHARGING:
356 status = "Discharging";
357 break;
358 case BATTERY_STATUS_NOT_CHARGING:
359 status = "Not charging";
360 break;
361 case BATTERY_STATUS_FULL:
362 status = "Full";
363 break;
364 default:
365 status = "Unknown";
366 }
367 dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
368 }
369 }
370 }
371
configureBattries()372 void PeripheralController::configureBattries() {
373 // Check raw batteries
374 const std::vector<int32_t> rawBatteryIds = getDeviceContext().getRawBatteryIds();
375
376 for (const auto& rawId : rawBatteryIds) {
377 std::optional<RawBatteryInfo> rawInfo = getDeviceContext().getRawBatteryInfo(rawId);
378 if (!rawInfo.has_value()) {
379 continue;
380 }
381 std::unique_ptr<Battery> battery =
382 std::make_unique<Battery>(getDeviceContext(), rawInfo->name, rawInfo->id);
383 mBatteries.insert_or_assign(rawId, std::move(battery));
384 }
385 }
386
configureLights()387 void PeripheralController::configureLights() {
388 bool hasRedLed = false;
389 bool hasGreenLed = false;
390 bool hasBlueLed = false;
391 std::optional<int32_t> rawGlobalId = std::nullopt;
392 // Player ID light common name string
393 std::string playerIdName;
394 // Raw RGB color to raw light ID
395 std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
396 // Map from player Id to raw light Id
397 std::unordered_map<int32_t, int32_t> playerIdLightIds;
398 // Set of Keyboard backlights
399 std::set<int32_t> keyboardBacklightIds;
400
401 // Check raw lights
402 const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
403 // Map from raw light id to raw light info
404 std::unordered_map<int32_t, RawLightInfo> rawInfos;
405 for (const auto& rawId : rawLightIds) {
406 std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
407 if (!rawInfo.has_value()) {
408 continue;
409 }
410 rawInfos.insert_or_assign(rawId, rawInfo.value());
411 // Check if this is a group LEDs for player ID
412 // The name for the light has already been parsed and is the `function`
413 // value; for player ID lights the function is expected to be `player-#`.
414 // However, the Sony driver will use `sony#` instead on SIXAXIS
415 // gamepads.
416 std::regex lightPattern("(player|sony)-?([0-9]+)");
417 std::smatch results;
418 if (std::regex_match(rawInfo->name, results, lightPattern)) {
419 std::string commonName = results[1].str();
420 int32_t playerId = std::stoi(results[2]);
421 if (playerIdLightIds.empty()) {
422 playerIdName = commonName;
423 playerIdLightIds.insert_or_assign(playerId, rawId);
424 } else {
425 // Make sure the player ID leds have common string name
426 if (playerIdName.compare(commonName) == 0 &&
427 playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
428 playerIdLightIds.insert_or_assign(playerId, rawId);
429 }
430 }
431 }
432 // Check if this is a Keyboard backlight
433 if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) {
434 keyboardBacklightIds.insert(rawId);
435 }
436 // Check if this is an LED of RGB light
437 if (rawInfo->flags.test(InputLightClass::RED)) {
438 hasRedLed = true;
439 rawRgbIds.emplace(LightColor::RED, rawId);
440 }
441 if (rawInfo->flags.test(InputLightClass::GREEN)) {
442 hasGreenLed = true;
443 rawRgbIds.emplace(LightColor::GREEN, rawId);
444 }
445 if (rawInfo->flags.test(InputLightClass::BLUE)) {
446 hasBlueLed = true;
447 rawRgbIds.emplace(LightColor::BLUE, rawId);
448 }
449 if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
450 rawGlobalId = rawId;
451 }
452 ALOGD_IF(DEBUG_LIGHT_DETAILS, "Light rawId %d name %s max %d flags %s\n", rawInfo->id,
453 rawInfo->name.c_str(), rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS),
454 rawInfo->flags.string().c_str());
455 }
456
457 // Construct a player ID light
458 if (playerIdLightIds.size() > 1) {
459 std::unique_ptr<Light> light =
460 std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
461 playerIdLightIds);
462 mLights.insert_or_assign(light->id, std::move(light));
463 // Remove these raw lights from raw light info as they've been used to compose a
464 // Player ID light, so we do not expose these raw lights as mono lights.
465 for (const auto& [playerId, rawId] : playerIdLightIds) {
466 rawInfos.erase(rawId);
467 }
468 }
469 // Construct a RGB light for composed RGB light
470 if (hasRedLed && hasGreenLed && hasBlueLed) {
471 ALOGD_IF(DEBUG_LIGHT_DETAILS, "Rgb light ids [%d, %d, %d]\n", rawRgbIds.at(LightColor::RED),
472 rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
473 bool isKeyboardBacklight = keyboardBacklightIds.find(rawRgbIds.at(LightColor::RED)) !=
474 keyboardBacklightIds.end() &&
475 keyboardBacklightIds.find(rawRgbIds.at(LightColor::GREEN)) !=
476 keyboardBacklightIds.end() &&
477 keyboardBacklightIds.find(rawRgbIds.at(LightColor::BLUE)) !=
478 keyboardBacklightIds.end() &&
479 (!rawGlobalId.has_value() ||
480 keyboardBacklightIds.find(rawGlobalId.value()) != keyboardBacklightIds.end());
481
482 std::unique_ptr<Light> light =
483 std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
484 isKeyboardBacklight
485 ? InputDeviceLightType::KEYBOARD_BACKLIGHT
486 : InputDeviceLightType::INPUT,
487 rawRgbIds, rawGlobalId);
488 mLights.insert_or_assign(light->id, std::move(light));
489 // Remove from raw light info as they've been composed a RBG light.
490 rawInfos.erase(rawRgbIds.at(LightColor::RED));
491 rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
492 rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
493 if (rawGlobalId.has_value()) {
494 rawInfos.erase(rawGlobalId.value());
495 }
496 }
497
498 // Check the rest of raw light infos
499 for (const auto& [rawId, rawInfo] : rawInfos) {
500 InputDeviceLightType type;
501 if (keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()) {
502 type = InputDeviceLightType::KEYBOARD_BACKLIGHT;
503 } else if (rawInfo.flags.test(InputLightClass::KEYBOARD_MIC_MUTE)) {
504 type = InputDeviceLightType::KEYBOARD_MIC_MUTE;
505 } else if (rawInfo.flags.test(InputLightClass::KEYBOARD_VOLUME_MUTE)) {
506 type = InputDeviceLightType::KEYBOARD_VOLUME_MUTE;
507 } else {
508 type = InputDeviceLightType::INPUT;
509 }
510
511 // If the node is multi-color led, construct a MULTI_COLOR light
512 if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
513 rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) {
514 ALOGD_IF(DEBUG_LIGHT_DETAILS, "Multicolor light Id %d name %s\n", rawInfo.id,
515 rawInfo.name.c_str());
516 std::unique_ptr<Light> light =
517 std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId,
518 type, rawInfo.id);
519 mLights.insert_or_assign(light->id, std::move(light));
520 continue;
521 }
522 // Construct a Mono LED light
523 ALOGD_IF(DEBUG_LIGHT_DETAILS, "Mono light Id %d name %s\n", rawInfo.id,
524 rawInfo.name.c_str());
525 std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name,
526 ++mNextId, type, rawInfo.id);
527
528 mLights.insert_or_assign(light->id, std::move(light));
529 }
530 }
531
getBatteryCapacity(int batteryId)532 std::optional<int32_t> PeripheralController::getBatteryCapacity(int batteryId) {
533 return getDeviceContext().getBatteryCapacity(batteryId);
534 }
535
getBatteryStatus(int batteryId)536 std::optional<int32_t> PeripheralController::getBatteryStatus(int batteryId) {
537 return getDeviceContext().getBatteryStatus(batteryId);
538 }
539
setLightColor(int32_t lightId,int32_t color)540 bool PeripheralController::setLightColor(int32_t lightId, int32_t color) {
541 auto it = mLights.find(lightId);
542 if (it == mLights.end()) {
543 return false;
544 }
545 auto& light = it->second;
546 ALOGD_IF(DEBUG_LIGHT_DETAILS, "setLightColor lightId %d type %s color 0x%x", lightId,
547 ftl::enum_string(light->type).c_str(), color);
548 return light->setLightColor(color);
549 }
550
getLightColor(int32_t lightId)551 std::optional<int32_t> PeripheralController::getLightColor(int32_t lightId) {
552 auto it = mLights.find(lightId);
553 if (it == mLights.end()) {
554 return std::nullopt;
555 }
556 auto& light = it->second;
557 std::optional<int32_t> color = light->getLightColor();
558 ALOGD_IF(DEBUG_LIGHT_DETAILS, "getLightColor lightId %d type %s color 0x%x", lightId,
559 ftl::enum_string(light->type).c_str(), color.value_or(0));
560 return color;
561 }
562
setLightPlayerId(int32_t lightId,int32_t playerId)563 bool PeripheralController::setLightPlayerId(int32_t lightId, int32_t playerId) {
564 auto it = mLights.find(lightId);
565 if (it == mLights.end()) {
566 return false;
567 }
568 auto& light = it->second;
569 return light->setLightPlayerId(playerId);
570 }
571
getLightPlayerId(int32_t lightId)572 std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) {
573 auto it = mLights.find(lightId);
574 if (it == mLights.end()) {
575 return std::nullopt;
576 }
577 auto& light = it->second;
578 return light->getLightPlayerId();
579 }
580
getEventHubId() const581 int32_t PeripheralController::getEventHubId() const {
582 return getDeviceContext().getEventHubId();
583 }
584 } // namespace android
585