Injects hinge_angle sensor data using the guest sensor binary.
Bug: 181157794
Test: Use the device state buttons to inject hinge and lid swich data.
Change-Id: I3addaa747fdfcdde75a82403278529eb1e8a13de
diff --git a/guest/commands/rotate/main.cpp b/guest/commands/rotate/main.cpp
deleted file mode 100644
index 8967097..0000000
--- a/guest/commands/rotate/main.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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 <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <binder/IServiceManager.h>
-#include <utils/StrongPointer.h>
-#include <utils/SystemClock.h>
-
-#include <thread>
-
-#include "android/hardware/sensors/2.0/ISensors.h"
-
-using android::sp;
-using android::hardware::sensors::V1_0::Event;
-using android::hardware::sensors::V1_0::OperationMode;
-using android::hardware::sensors::V1_0::Result;
-using android::hardware::sensors::V1_0::SensorInfo;
-using android::hardware::sensors::V1_0::SensorStatus;
-using android::hardware::sensors::V1_0::SensorType;
-using android::hardware::sensors::V2_0::ISensors;
-
-void InjectOrientation(bool portrait) {
- const sp<ISensors> sensors = ISensors::getService();
- if (sensors == nullptr) {
- LOG(FATAL) << "Unable to get ISensors.";
- }
-
- Result result;
-
- // Place the ISensors HAL into DATA_INJECTION mode so that we can
- // inject events.
- result = sensors->setOperationMode(OperationMode::DATA_INJECTION);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to set ISensors operation mode to DATA_INJECTION: "
- << toString(result);
- }
-
- // Find the first available accelerometer sensor.
- int accel_handle = -1;
- const auto& getSensorsList_result =
- sensors->getSensorsList([&](const auto& list) {
- for (const SensorInfo& sensor : list) {
- if (sensor.type == SensorType::ACCELEROMETER) {
- accel_handle = sensor.sensorHandle;
- break;
- }
- }
- });
- if (!getSensorsList_result.isOk()) {
- LOG(FATAL) << "Unable to get ISensors sensors list: "
- << getSensorsList_result.description();
- }
- if (accel_handle == -1) {
- LOG(FATAL) << "Unable to find ACCELEROMETER sensor.";
- }
-
- // Create a base ISensors accelerometer event.
- Event event;
- event.sensorHandle = accel_handle;
- event.sensorType = SensorType::ACCELEROMETER;
- if (portrait) {
- event.u.vec3.x = 0;
- event.u.vec3.y = 9.2;
- } else {
- event.u.vec3.x = 9.2;
- event.u.vec3.y = 0;
- }
- event.u.vec3.z = 3.5;
- event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-
- // Repeatedly inject accelerometer events. The WindowManager orientation
- // listener responds to sustained accelerometer data, not just a single event.
- android::base::Timer timer;
- while (timer.duration() < 1s) {
- event.timestamp = android::elapsedRealtimeNano();
- result = sensors->injectSensorData(event);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to inject ISensors accelerometer event: "
- << toString(result);
- }
- std::this_thread::sleep_for(10ms);
- }
-
- // Return the ISensors HAL back to NORMAL mode.
- result = sensors->setOperationMode(OperationMode::NORMAL);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to set sensors operation mode to NORMAL: "
- << toString(result);
- }
-}
-
-int main(int argc, char** argv) {
- if (argc == 1) {
- LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
- }
-
- bool portrait = true;
- if (!strcmp(argv[1], "portrait")) {
- portrait = true;
- } else if (!strcmp(argv[1], "landscape")) {
- portrait = false;
- } else {
- LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
- }
-
- InjectOrientation(portrait);
-}
diff --git a/guest/commands/rotate/Android.bp b/guest/commands/sensor_injection/Android.bp
similarity index 79%
rename from guest/commands/rotate/Android.bp
rename to guest/commands/sensor_injection/Android.bp
index 6568c0e..a29250a 100644
--- a/guest/commands/rotate/Android.bp
+++ b/guest/commands/sensor_injection/Android.bp
@@ -3,11 +3,11 @@
}
cc_binary {
- name: "cuttlefish_rotate",
+ name: "cuttlefish_sensor_injection",
srcs: ["main.cpp"],
shared_libs: [
"[email protected]",
- "[email protected]",
+ "[email protected]",
"libbase",
"libbinder",
"libhidlbase",
diff --git a/guest/commands/sensor_injection/main.cpp b/guest/commands/sensor_injection/main.cpp
new file mode 100644
index 0000000..6eadb4a
--- /dev/null
+++ b/guest/commands/sensor_injection/main.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 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 <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include <thread>
+
+#include "android/hardware/sensors/2.1/ISensors.h"
+
+using android::sp;
+using android::hardware::sensors::V1_0::OperationMode;
+using android::hardware::sensors::V1_0::Result;
+using android::hardware::sensors::V1_0::SensorStatus;
+using android::hardware::sensors::V2_1::Event;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::SensorInfo;
+using android::hardware::sensors::V2_1::SensorType;
+
+sp<ISensors> startSensorInjection() {
+ const sp<ISensors> sensors = ISensors::getService();
+ if (sensors == nullptr) {
+ LOG(FATAL) << "Unable to get ISensors.";
+ }
+
+ // Place the ISensors HAL into DATA_INJECTION mode so that we can
+ // inject events.
+ Result result = sensors->setOperationMode(OperationMode::DATA_INJECTION);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to set ISensors operation mode to DATA_INJECTION: "
+ << toString(result);
+ }
+
+ return sensors;
+}
+
+int getSensorHandle(SensorType type, const sp<ISensors> sensors) {
+ // Find the first available sensor of the given type.
+ int handle = -1;
+ const auto& getSensorsList_result =
+ sensors->getSensorsList_2_1([&](const auto& list) {
+ for (const SensorInfo& sensor : list) {
+ if (sensor.type == type) {
+ handle = sensor.sensorHandle;
+ break;
+ }
+ }
+ });
+ if (!getSensorsList_result.isOk()) {
+ LOG(FATAL) << "Unable to get ISensors sensors list: "
+ << getSensorsList_result.description();
+ }
+ if (handle == -1) {
+ LOG(FATAL) << "Unable to find sensor.";
+ }
+ return handle;
+}
+
+void endSensorInjection(const sp<ISensors> sensors) {
+ // Return the ISensors HAL back to NORMAL mode.
+ Result result = sensors->setOperationMode(OperationMode::NORMAL);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to set sensors operation mode to NORMAL: "
+ << toString(result);
+ }
+}
+
+// Inject ACCELEROMETER events to corresponding to a given physical
+// device orientation: portrait or landscape.
+void InjectOrientation(bool portrait) {
+ sp<ISensors> sensors = startSensorInjection();
+ int handle = getSensorHandle(SensorType::ACCELEROMETER, sensors);
+
+ // Create a base ISensors accelerometer event.
+ Event event;
+ event.sensorHandle = handle;
+ event.sensorType = SensorType::ACCELEROMETER;
+ if (portrait) {
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 9.2;
+ } else {
+ event.u.vec3.x = 9.2;
+ event.u.vec3.y = 0;
+ }
+ event.u.vec3.z = 3.5;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+
+ // Repeatedly inject accelerometer events. The WindowManager orientation
+ // listener responds to sustained accelerometer data, not just a single event.
+ android::base::Timer timer;
+ Result result;
+ while (timer.duration() < 1s) {
+ event.timestamp = android::elapsedRealtimeNano();
+ result = sensors->injectSensorData_2_1(event);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to inject ISensors accelerometer event: "
+ << toString(result);
+ }
+ std::this_thread::sleep_for(10ms);
+ }
+
+ endSensorInjection(sensors);
+}
+
+// Inject a single HINGE_ANGLE event at the given angle.
+void InjectHingeAngle(int angle) {
+ sp<ISensors> sensors = startSensorInjection();
+ int handle = getSensorHandle(SensorType::HINGE_ANGLE, sensors);
+
+ // Create a base ISensors hinge_angle event.
+ Event event;
+ event.sensorHandle = handle;
+ event.sensorType = SensorType::HINGE_ANGLE;
+ event.u.scalar = angle;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ event.timestamp = android::elapsedRealtimeNano();
+ Result result = sensors->injectSensorData_2_1(event);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to inject HINGE_ANGLE data: " << toString(result);
+ }
+
+ endSensorInjection(sensors);
+}
+
+int main(int argc, char** argv) {
+ if (argc == 2) {
+ LOG(FATAL) << "Expected command line args 'rotate <portrait|landscape>' or "
+ "'hinge_angle <value>'";
+ }
+
+ if (!strcmp(argv[1], "rotate")) {
+ bool portrait = true;
+ if (!strcmp(argv[2], "portrait")) {
+ portrait = true;
+ } else if (!strcmp(argv[2], "landscape")) {
+ portrait = false;
+ } else {
+ LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
+ }
+ InjectOrientation(portrait);
+ } else if (!strcmp(argv[1], "hinge_angle")) {
+ int angle = std::stoi(argv[2]);
+ if (angle < 0 || angle > 360) {
+ LOG(FATAL) << "Bad hinge_angle value: " << argv[2];
+ }
+ InjectHingeAngle(angle);
+ } else {
+ LOG(FATAL) << "Unknown arg: " << argv[1];
+ }
+}
diff --git a/host/frontend/webrtc/connection_observer.cpp b/host/frontend/webrtc/connection_observer.cpp
index a8613e6..392539c 100644
--- a/host/frontend/webrtc/connection_observer.cpp
+++ b/host/frontend/webrtc/connection_observer.cpp
@@ -258,9 +258,9 @@
// invert the lid_switch_open value that is sent to the input device.
OnSwitchEvent(SW_LID, !evt["lid_switch_open"].asBool());
}
- // TODO(b/181157794) Propagate hinge angle sensor data.
if (evt.isMember("hinge_angle_value")) {
- LOG(WARNING) << "Hinge angle sensor is not yet implemented.";
+ // TODO(b/181157794) Propagate hinge angle sensor data using a custom
+ // Sensor HAL.
}
return;
}
diff --git a/host/frontend/webrtc_operator/assets/js/app.js b/host/frontend/webrtc_operator/assets/js/app.js
index 859b33b..61a9bf3 100644
--- a/host/frontend/webrtc_operator/assets/js/app.js
+++ b/host/frontend/webrtc_operator/assets/js/app.js
@@ -276,6 +276,13 @@
createControlPanelButton(button.command, button.title, button.icon_name,
getCustomDeviceStateButtonCb(button.device_states),
'control-panel-custom-buttons');
+ for (const device_state of button.device_states) {
+ // hinge_angle is currently injected via an adb shell command that
+ // triggers a guest binary.
+ if ('hinge_angle_value' in device_state) {
+ buttons[button.command].adb = true;
+ }
+ }
} else {
// This button's command is handled by custom action server.
createControlPanelButton(button.command, button.title, button.icon_name,
@@ -366,7 +373,7 @@
initializeAdb();
if (e.type == 'mousedown') {
adbShell(
- '/vendor/bin/cuttlefish_rotate ' +
+ '/vendor/bin/cuttlefish_sensor_injection rotate ' +
(currentRotation == 0 ? 'landscape' : 'portrait'))
}
}
@@ -394,6 +401,13 @@
};
deviceConnection.sendControlMessage(JSON.stringify(message));
console.log(JSON.stringify(message));
+ // TODO(b/181157794): Use a custom Sensor HAL for hinge_angle injection
+ // instead of this guest binary.
+ if ('hinge_angle_value' in states[index]) {
+ adbShell(
+ '/vendor/bin/cuttlefish_sensor_injection hinge_angle ' +
+ states[index].hinge_angle_value);
+ }
// Cycle to the next state.
index = (index + 1) % states.length;
}
diff --git a/shared/config/config_foldable.json b/shared/config/config_foldable.json
index 7a1e731..dd64d17 100644
--- a/shared/config/config_foldable.json
+++ b/shared/config/config_foldable.json
@@ -7,7 +7,8 @@
{
"device_states": [
{
- "lid_switch_open": false
+ "lid_switch_open": false,
+ "hinge_angle_value": 0
}
],
"button":{
@@ -19,7 +20,8 @@
{
"device_states": [
{
- "lid_switch_open": true
+ "lid_switch_open": true,
+ "hinge_angle_value": 180
}
],
"button":{
diff --git a/shared/device.mk b/shared/device.mk
index 089c662..123cdd2 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -147,7 +147,7 @@
#
PRODUCT_PACKAGES += \
CuttlefishService \
- cuttlefish_rotate \
+ cuttlefish_sensor_injection \
rename_netiface \
setup_wifi \
bt_vhci_forwarder \
diff --git a/shared/foldable/device_state_configuration.xml b/shared/foldable/device_state_configuration.xml
index b32eced..9618b11 100644
--- a/shared/foldable/device_state_configuration.xml
+++ b/shared/foldable/device_state_configuration.xml
@@ -9,13 +9,21 @@
</conditions>
</device-state>
<device-state>
- <!-- TODO(b/181583265): Use the hinge sensor for HALF_OPENED state.
- Currently using an identifier of 3 so that this state never takes
- precedence over the lower-identifier-value CLOSED and OPENED states,
- until a hinge sensor is available. -->
- <identifier>3</identifier>
+ <identifier>1</identifier>
<name>HALF_OPENED</name>
- <conditions></conditions>
+ <conditions>
+ <lid-switch>
+ <open>true</open>
+ </lid-switch>
+ <sensor>
+ <type>android.sensor.hinge_angle</type>
+ <name>Hinge Angle Sensor</name>
+ <value>
+ <min>0</min>
+ <max>180</max>
+ </value>
+ </sensor>
+ </conditions>
</device-state>
<device-state>
<identifier>2</identifier>
diff --git a/shared/sepolicy/vendor/cuttlefish_rotate.te b/shared/sepolicy/vendor/cuttlefish_rotate.te
deleted file mode 100644
index 7d8a9a1..0000000
--- a/shared/sepolicy/vendor/cuttlefish_rotate.te
+++ /dev/null
@@ -1,15 +0,0 @@
-type cuttlefish_rotate, domain;
-type cuttlefish_rotate_exec, exec_type, vendor_file_type, file_type;
-
-# Switch to cuttlefish_rotate domain when executing from shell.
-domain_auto_trans(shell, cuttlefish_rotate_exec, cuttlefish_rotate)
-allow cuttlefish_rotate shell:fd use;
-
-# Allow cuttlefish_rotate to communicate over adb connection.
-allow cuttlefish_rotate adbd:fd use;
-allow cuttlefish_rotate adbd:unix_stream_socket { read write };
-# Needed to run the binary directly via adb socket.
-allow cuttlefish_rotate devpts:chr_file { read write };
-
-# Grant cuttlefish_rotate access to the ISensors HAL.
-hal_client_domain(cuttlefish_rotate, hal_sensors)
diff --git a/shared/sepolicy/vendor/cuttlefish_sensor_injection.te b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
new file mode 100644
index 0000000..9e7aca5
--- /dev/null
+++ b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
@@ -0,0 +1,15 @@
+type cuttlefish_sensor_injection, domain;
+type cuttlefish_sensor_injection_exec, exec_type, vendor_file_type, file_type;
+
+# Switch to cuttlefish_sensor_injection domain when executing from shell.
+domain_auto_trans(shell, cuttlefish_sensor_injection_exec, cuttlefish_sensor_injection)
+allow cuttlefish_sensor_injection shell:fd use;
+
+# Allow cuttlefish_sensor_injection to communicate over adb connection.
+allow cuttlefish_sensor_injection adbd:fd use;
+allow cuttlefish_sensor_injection adbd:unix_stream_socket { read write };
+# Needed to run the binary directly via adb socket.
+allow cuttlefish_sensor_injection devpts:chr_file { read write };
+
+# Grant cuttlefish_sensor_injection access to the ISensors HAL.
+hal_client_domain(cuttlefish_sensor_injection, hal_sensors)
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 20c3341..f41d86e 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -55,7 +55,7 @@
#############################
# Vendor files
#
-/vendor/bin/cuttlefish_rotate u:object_r:cuttlefish_rotate_exec:s0
+/vendor/bin/cuttlefish_sensor_injection u:object_r:cuttlefish_sensor_injection_exec:s0
/vendor/bin/socket_vsock_proxy u:object_r:socket_vsock_proxy_exec:s0
/vendor/bin/vsoc_input_service u:object_r:vsoc_input_service_exec:s0
/vendor/bin/rename_netiface u:object_r:rename_netiface_exec:s0
diff --git a/shared/sepolicy/vendor/shell.te b/shared/sepolicy/vendor/shell.te
index 60d15fa..cc26032 100644
--- a/shared/sepolicy/vendor/shell.te
+++ b/shared/sepolicy/vendor/shell.te
@@ -1,5 +1,5 @@
allow shell serial_device:chr_file { getattr ioctl read write };
-allow shell cuttlefish_rotate_exec:file rx_file_perms;
+allow shell cuttlefish_sensor_injection_exec:file rx_file_perms;
# TODO(b/130668487): Label the vsock sockets.
allow shell adbd:{ socket vsock_socket } rw_socket_perms_no_ioctl;