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 <cmath>
18 #include <thread>
19
20 #include <android-base/chrono_utils.h>
21 #include <android-base/logging.h>
22 #include <android/binder_manager.h>
23 #include <android-base/parsedouble.h>
24 #include <android-base/parseint.h>
25 #include <utils/SystemClock.h>
26 #include <aidl/android/hardware/sensors/BnSensors.h>
27
28 using aidl::android::hardware::sensors::Event;
29 using aidl::android::hardware::sensors::ISensors;
30 using aidl::android::hardware::sensors::SensorInfo;
31 using aidl::android::hardware::sensors::SensorStatus;
32 using aidl::android::hardware::sensors::SensorType;
33
startSensorInjection()34 std::shared_ptr<ISensors> startSensorInjection() {
35 auto sensors = ISensors::fromBinder(ndk::SpAIBinder(
36 AServiceManager_getService("android.hardware.sensors.ISensors/default")));
37 CHECK(sensors != nullptr) << "Unable to get ISensors.";
38
39 // Place the ISensors HAL into DATA_INJECTION mode so that we can
40 // inject events.
41 auto result =
42 sensors->setOperationMode(ISensors::OperationMode::DATA_INJECTION);
43 CHECK(result.isOk())
44 << "Unable to set ISensors operation mode to DATA_INJECTION: "
45 << result.getDescription();
46
47 return sensors;
48 }
49
getSensorHandle(SensorType type,const std::shared_ptr<ISensors> sensors)50 int getSensorHandle(SensorType type, const std::shared_ptr<ISensors> sensors) {
51 // Find the first available sensor of the given type.
52 int handle = -1;
53 std::vector<SensorInfo> sensors_list;
54 auto result = sensors->getSensorsList(&sensors_list);
55 CHECK(result.isOk()) << "Unable to get ISensors sensors list: "
56 << result.getDescription();
57 for (const SensorInfo& sensor : sensors_list) {
58 if (sensor.type == type) {
59 handle = sensor.sensorHandle;
60 break;
61 }
62 }
63 CHECK(handle != -1) << "Unable to find sensor.";
64 return handle;
65 }
66
endSensorInjection(const std::shared_ptr<ISensors> sensors)67 void endSensorInjection(const std::shared_ptr<ISensors> sensors) {
68 // Return the ISensors HAL back to NORMAL mode.
69 auto result = sensors->setOperationMode(ISensors::OperationMode::NORMAL);
70 CHECK(result.isOk()) << "Unable to set sensors operation mode to NORMAL: "
71 << result.getDescription();
72 }
73
74 // Inject ACCELEROMETER events to corresponding to a given physical
75 // device position.
InjectOrientation(int rotationDeg)76 void InjectOrientation(int rotationDeg) {
77 auto rad = M_PI * rotationDeg / 180.0;
78 auto sensors = startSensorInjection();
79 int handle = getSensorHandle(SensorType::ACCELEROMETER, sensors);
80
81 // Create a base ISensors accelerometer event.
82 Event event;
83 event.sensorHandle = handle;
84 event.sensorType = SensorType::ACCELEROMETER;
85 Event::EventPayload::Vec3 vec3;
86 // (x^2 + y^2 + z^2)^1/2 = ~9.8 = 1G
87 vec3.x = 9.2 * std::sin(rad);
88 vec3.y = 9.2 * std::cos(rad);
89 // z is fixed at 3.5, meaning the device is positioned vertically with a
90 // slight inclination backwards.
91 vec3.z = 3.5;
92 vec3.status = SensorStatus::ACCURACY_HIGH;
93 event.payload.set<Event::EventPayload::Tag::vec3>(vec3);
94
95 // Repeatedly inject accelerometer events. The WindowManager orientation
96 // listener responds to sustained accelerometer data, not just a single event.
97 android::base::Timer timer;
98 while (timer.duration() < 1s) {
99 event.timestamp = android::elapsedRealtimeNano();
100 auto result = sensors->injectSensorData(event);
101 CHECK(result.isOk()) << "Unable to inject ISensors accelerometer event: "
102 << result.getDescription();
103 std::this_thread::sleep_for(10ms);
104 }
105
106 endSensorInjection(sensors);
107 }
108
109 // Inject accelerometer event based on rotation in device position.
InjectAccelerometer(double x,double y,double z)110 void InjectAccelerometer(double x, double y, double z) {
111 auto sensors = startSensorInjection();
112 int handle = getSensorHandle(SensorType::ACCELEROMETER, sensors);
113 Event event;
114 event.sensorHandle = handle;
115 event.sensorType = SensorType::ACCELEROMETER;
116
117 Event::EventPayload::Vec3 vec3;
118 vec3.x = x;
119 vec3.y = y;
120 vec3.z = z;
121 vec3.status = SensorStatus::ACCURACY_HIGH;
122 event.payload.set<Event::EventPayload::Tag::vec3>(vec3);
123 event.timestamp = android::elapsedRealtimeNano();
124 auto result = sensors->injectSensorData(event);
125 CHECK(result.isOk()) << "Unable to inject ISensors accelerometer event: "
126 << result.getDescription();
127 }
128
129 // Inject Magnetometer event based on rotation in device position.
InjectMagnetometer(double x,double y,double z)130 void InjectMagnetometer(double x, double y, double z) {
131 auto sensors = startSensorInjection();
132 int handle = getSensorHandle(SensorType::MAGNETIC_FIELD, sensors);
133 Event event;
134 event.sensorHandle = handle;
135 event.sensorType = SensorType::MAGNETIC_FIELD;
136
137 Event::EventPayload::Vec3 vec3;
138 vec3.x = x;
139 vec3.y = y;
140 vec3.z = z;
141 vec3.status = SensorStatus::ACCURACY_HIGH;
142 event.payload.set<Event::EventPayload::Tag::vec3>(vec3);
143 event.timestamp = android::elapsedRealtimeNano();
144 auto result = sensors->injectSensorData(event);
145 CHECK(result.isOk()) << "Unable to inject ISensors magnetometer event: "
146 << result.getDescription();
147 }
148
149 // Inject Gyroscope event based on rotation in device position.
InjectGyroscope(double x,double y,double z)150 void InjectGyroscope(double x, double y, double z){
151 auto sensors = startSensorInjection();
152 int handle = getSensorHandle(SensorType::GYROSCOPE, sensors);
153 Event event;
154 event.sensorHandle = handle;
155 event.sensorType = SensorType::GYROSCOPE;
156
157 Event::EventPayload::Vec3 vec3;
158 vec3.x = x;
159 vec3.y = y;
160 vec3.z = z;
161 vec3.status = SensorStatus::ACCURACY_HIGH;
162 event.payload.set<Event::EventPayload::Tag::vec3>(vec3);
163 event.timestamp = android::elapsedRealtimeNano();
164 auto result = sensors->injectSensorData(event);
165 CHECK(result.isOk()) << "Unable to inject ISensors gyroscope event: "
166 << result.getDescription();
167 }
168
169 // Inject a single HINGE_ANGLE event at the given angle.
InjectHingeAngle(int angle)170 void InjectHingeAngle(int angle) {
171 auto sensors = startSensorInjection();
172 int handle = getSensorHandle(SensorType::HINGE_ANGLE, sensors);
173
174 // Create a base ISensors hinge_angle event.
175 Event event;
176 event.sensorHandle = handle;
177 event.sensorType = SensorType::HINGE_ANGLE;
178 event.payload.set<Event::EventPayload::Tag::scalar>((float)angle);
179 event.timestamp = android::elapsedRealtimeNano();
180
181 auto result = sensors->injectSensorData(event);
182 CHECK(result.isOk()) << "Unable to inject HINGE_ANGLE data"
183 << result.getDescription();
184
185 endSensorInjection(sensors);
186 }
187
main(int argc,char ** argv)188 int main(int argc, char** argv) {
189 ::android::base::InitLogging(
190 argv, android::base::LogdLogger(android::base::SYSTEM));
191 CHECK(argc == 3 || argc == 11)
192 << "Expected command line args 'rotate <angle>', 'hinge_angle <value>', or 'motion " <<
193 "<acc_x> <acc_y> <acc_z> <mgn_x> <mgn_y> <mgn_z> <gyro_x> <gyro_y> <gyro_z>'";
194 if (!strcmp(argv[1], "rotate")) {
195 int rotationDeg;
196 CHECK(android::base::ParseInt(argv[2], &rotationDeg))
197 << "Rotation angle must be an integer";
198 InjectOrientation(rotationDeg);
199 } else if (!strcmp(argv[1], "hinge_angle")) {
200 int angle;
201 CHECK(android::base::ParseInt(argv[2], &angle))
202 << "Hinge angle must be an integer";
203 CHECK(angle >= 0 && angle <= 360) << "Bad hinge_angle value: " << argv[2];
204 InjectHingeAngle(angle);
205 } else if (!strcmp(argv[1], "motion")) {
206 double acc_x, acc_y, acc_z, mgn_x, mgn_y, mgn_z, gyro_x, gyro_y, gyro_z;
207 CHECK(android::base::ParseDouble(argv[2], &acc_x)) << "Accelerometer x value must be a double";
208 CHECK(android::base::ParseDouble(argv[3], &acc_y)) << "Accelerometer x value must be a double";
209 CHECK(android::base::ParseDouble(argv[4], &acc_z)) << "Accelerometer x value must be a double";
210 CHECK(android::base::ParseDouble(argv[5], &mgn_x)) << "Magnetometer x value must be a double";
211 CHECK(android::base::ParseDouble(argv[6], &mgn_y)) << "Magnetometer y value must be a double";
212 CHECK(android::base::ParseDouble(argv[7], &mgn_z)) << "Magnetometer z value must be a double";
213 CHECK(android::base::ParseDouble(argv[8], &gyro_x)) << "Gyroscope x value must be a double";
214 CHECK(android::base::ParseDouble(argv[9], &gyro_y)) << "Gyroscope y value must be a double";
215 CHECK(android::base::ParseDouble(argv[10], &gyro_z)) << "Gyroscope z value must be a double";
216 InjectAccelerometer(acc_x, acc_y, acc_z);
217 InjectMagnetometer(mgn_x, mgn_y, mgn_z);
218 InjectGyroscope(gyro_x, gyro_y, gyro_z);
219 } else {
220 LOG(FATAL) << "Unknown arg: " << argv[1];
221 }
222 }
223