1 /*
2 * Copyright (C) 2020 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 #include "host/libs/config/custom_actions.h"
17
18 #include <android-base/logging.h>
19 #include <json/json.h>
20
21 #include <optional>
22 #include <string>
23 #include <vector>
24
25 #include "host/libs/config/cuttlefish_config.h"
26
27 namespace cuttlefish {
28 namespace {
29
30 const char* kCustomActionShellCommand = "shell_command";
31 const char* kCustomActionServer = "server";
32 const char* kCustomActionDeviceStates = "device_states";
33 const char* kCustomActionDeviceStateLidSwitchOpen = "lid_switch_open";
34 const char* kCustomActionDeviceStateHingeAngleValue = "hinge_angle_value";
35 const char* kCustomActionButton = "button";
36 const char* kCustomActionButtons = "buttons";
37 const char* kCustomActionButtonCommand = "command";
38 const char* kCustomActionButtonTitle = "title";
39 const char* kCustomActionButtonIconName = "icon_name";
40
41 } //namespace
42
43
CustomActionConfig(const Json::Value & dictionary)44 CustomActionConfig::CustomActionConfig(const Json::Value& dictionary) {
45 if (dictionary.isMember(kCustomActionShellCommand) +
46 dictionary.isMember(kCustomActionServer) +
47 dictionary.isMember(kCustomActionDeviceStates) !=
48 1) {
49 LOG(FATAL) << "Custom action must contain exactly one of shell_command, "
50 << "server, or device_states";
51 return;
52 }
53 if (dictionary.isMember(kCustomActionShellCommand)) {
54 // Shell command with one button.
55 Json::Value button_entry = dictionary[kCustomActionButton];
56 buttons = {{button_entry[kCustomActionButtonCommand].asString(),
57 button_entry[kCustomActionButtonTitle].asString(),
58 button_entry[kCustomActionButtonIconName].asString()}};
59 shell_command = dictionary[kCustomActionShellCommand].asString();
60 } else if (dictionary.isMember(kCustomActionServer)) {
61 // Action server with possibly multiple buttons.
62 for (const Json::Value& button_entry : dictionary[kCustomActionButtons]) {
63 ControlPanelButton button = {
64 button_entry[kCustomActionButtonCommand].asString(),
65 button_entry[kCustomActionButtonTitle].asString(),
66 button_entry[kCustomActionButtonIconName].asString()};
67 buttons.push_back(button);
68 }
69 server = dictionary[kCustomActionServer].asString();
70 } else if (dictionary.isMember(kCustomActionDeviceStates)) {
71 // Device state(s) with one button.
72 // Each button press cycles to the next state, then repeats to the first.
73 Json::Value button_entry = dictionary[kCustomActionButton];
74 buttons = {{button_entry[kCustomActionButtonCommand].asString(),
75 button_entry[kCustomActionButtonTitle].asString(),
76 button_entry[kCustomActionButtonIconName].asString()}};
77 for (const Json::Value& device_state_entry :
78 dictionary[kCustomActionDeviceStates]) {
79 DeviceState state;
80 if (device_state_entry.isMember(kCustomActionDeviceStateLidSwitchOpen)) {
81 state.lid_switch_open =
82 device_state_entry[kCustomActionDeviceStateLidSwitchOpen].asBool();
83 }
84 if (device_state_entry.isMember(
85 kCustomActionDeviceStateHingeAngleValue)) {
86 state.hinge_angle_value =
87 device_state_entry[kCustomActionDeviceStateHingeAngleValue].asInt();
88 }
89 device_states.push_back(state);
90 }
91 } else {
92 LOG(FATAL) << "Unknown custom action type.";
93 }
94 }
95
ToJson() const96 Json::Value CustomActionConfig::ToJson() const {
97 Json::Value custom_action;
98 if (shell_command) {
99 // Shell command with one button.
100 custom_action[kCustomActionShellCommand] = *shell_command;
101 custom_action[kCustomActionButton] = Json::Value();
102 custom_action[kCustomActionButton][kCustomActionButtonCommand] =
103 buttons[0].command;
104 custom_action[kCustomActionButton][kCustomActionButtonTitle] =
105 buttons[0].title;
106 custom_action[kCustomActionButton][kCustomActionButtonIconName] =
107 buttons[0].icon_name;
108 } else if (server) {
109 // Action server with possibly multiple buttons.
110 custom_action[kCustomActionServer] = *server;
111 custom_action[kCustomActionButtons] = Json::Value(Json::arrayValue);
112 for (const auto& button : buttons) {
113 Json::Value button_entry;
114 button_entry[kCustomActionButtonCommand] = button.command;
115 button_entry[kCustomActionButtonTitle] = button.title;
116 button_entry[kCustomActionButtonIconName] = button.icon_name;
117 custom_action[kCustomActionButtons].append(button_entry);
118 }
119 } else if (!device_states.empty()) {
120 // Device state(s) with one button.
121 custom_action[kCustomActionDeviceStates] = Json::Value(Json::arrayValue);
122 for (const auto& device_state : device_states) {
123 Json::Value device_state_entry;
124 if (device_state.lid_switch_open) {
125 device_state_entry[kCustomActionDeviceStateLidSwitchOpen] =
126 *device_state.lid_switch_open;
127 }
128 if (device_state.hinge_angle_value) {
129 device_state_entry[kCustomActionDeviceStateHingeAngleValue] =
130 *device_state.hinge_angle_value;
131 }
132 custom_action[kCustomActionDeviceStates].append(device_state_entry);
133 }
134 custom_action[kCustomActionButton] = Json::Value();
135 custom_action[kCustomActionButton][kCustomActionButtonCommand] =
136 buttons[0].command;
137 custom_action[kCustomActionButton][kCustomActionButtonTitle] =
138 buttons[0].title;
139 custom_action[kCustomActionButton][kCustomActionButtonIconName] =
140 buttons[0].icon_name;
141 } else {
142 LOG(FATAL) << "Unknown custom action type.";
143 }
144 return custom_action;
145 }
146
147 } // namespace cuttlefish
148