blob: bd8af04fafb30923ef734f3142419245e4d874ba [file] [log] [blame]
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -07001/*
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 <media/SensorPoseProvider.h>
18
19#define LOG_TAG "SensorPoseProvider"
20
Shunkai Yao51379452022-08-30 03:14:50 +000021#include <algorithm>
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070022#include <future>
Shunkai Yao51379452022-08-30 03:14:50 +000023#include <inttypes.h>
24#include <limits>
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070025#include <map>
26#include <thread>
27
Shunkai Yao5a251df2022-07-22 18:42:27 +000028#include <android-base/stringprintf.h>
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -070029#include <android-base/thread_annotations.h>
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070030#include <log/log_main.h>
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070031#include <sensor/SensorEventQueue.h>
32#include <sensor/SensorManager.h>
33#include <utils/Looper.h>
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070034
Ytai Ben-Tsvi54f07582021-09-13 12:09:42 -070035#include "QuaternionUtil.h"
36
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070037namespace android {
38namespace media {
39namespace {
40
Shunkai Yao5a251df2022-07-22 18:42:27 +000041using android::base::StringAppendF;
42
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070043// Identifier to use for our event queue on the loop.
44// The number 19 is arbitrary, only useful if using multiple objects on the same looper.
45constexpr int kIdent = 19;
46
47static inline Looper* ALooper_to_Looper(ALooper* alooper) {
48 return reinterpret_cast<Looper*>(alooper);
49}
50
51static inline ALooper* Looper_to_ALooper(Looper* looper) {
52 return reinterpret_cast<ALooper*>(looper);
53}
54
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070055/**
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070056 * RAII-wrapper around SensorEventQueue, which unregisters it on destruction.
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070057 */
58class EventQueueGuard {
59 public:
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070060 EventQueueGuard(const sp<SensorEventQueue>& queue, Looper* looper) : mQueue(queue) {
61 mQueue->looper = Looper_to_ALooper(looper);
62 mQueue->requestAdditionalInfo = false;
63 looper->addFd(mQueue->getFd(), kIdent, ALOOPER_EVENT_INPUT, nullptr, nullptr);
64 }
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070065
66 ~EventQueueGuard() {
67 if (mQueue) {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070068 ALooper_to_Looper(mQueue->looper)->removeFd(mQueue->getFd());
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070069 }
70 }
71
72 EventQueueGuard(const EventQueueGuard&) = delete;
73 EventQueueGuard& operator=(const EventQueueGuard&) = delete;
74
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070075 [[nodiscard]] SensorEventQueue* get() const { return mQueue.get(); }
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070076
77 private:
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070078 sp<SensorEventQueue> mQueue;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070079};
80
81/**
82 * RAII-wrapper around an enabled sensor, which disables it upon destruction.
83 */
84class SensorEnableGuard {
85 public:
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070086 SensorEnableGuard(const sp<SensorEventQueue>& queue, int32_t sensor)
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070087 : mQueue(queue), mSensor(sensor) {}
88
89 ~SensorEnableGuard() {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070090 if (mSensor != SensorPoseProvider::INVALID_HANDLE) {
91 int ret = mQueue->disableSensor(mSensor);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070092 if (ret) {
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -070093 ALOGE("Failed to disable sensor: %s", strerror(ret));
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -070094 }
95 }
96 }
97
98 SensorEnableGuard(const SensorEnableGuard&) = delete;
99 SensorEnableGuard& operator=(const SensorEnableGuard&) = delete;
100
101 // Enable moving.
102 SensorEnableGuard(SensorEnableGuard&& other) : mQueue(other.mQueue), mSensor(other.mSensor) {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700103 other.mSensor = SensorPoseProvider::INVALID_HANDLE;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700104 }
105
106 private:
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700107 sp<SensorEventQueue> const mQueue;
108 int32_t mSensor;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700109};
110
111/**
112 * Streams the required events to a PoseListener, based on events originating from the Sensor stack.
113 */
114class SensorPoseProviderImpl : public SensorPoseProvider {
115 public:
116 static std::unique_ptr<SensorPoseProvider> create(const char* packageName, Listener* listener) {
117 std::unique_ptr<SensorPoseProviderImpl> result(
118 new SensorPoseProviderImpl(packageName, listener));
119 return result->waitInitFinished() ? std::move(result) : nullptr;
120 }
121
122 ~SensorPoseProviderImpl() override {
Ytai Ben-Tsvic29bad62021-09-09 10:22:52 -0700123 // Disable all active sensors.
124 mEnabledSensors.clear();
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700125 mLooper->wake();
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700126 mThread.join();
127 }
128
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700129 bool startSensor(int32_t sensor, std::chrono::microseconds samplingPeriod) override {
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700130 // Figure out the sensor's data format.
131 DataFormat format = getSensorFormat(sensor);
132 if (format == DataFormat::kUnknown) {
133 ALOGE("Unknown format for sensor %" PRId32, sensor);
134 return false;
135 }
136
137 {
138 std::lock_guard lock(mMutex);
Shunkai Yao51379452022-08-30 03:14:50 +0000139 mEnabledSensorsExtra.emplace(
140 sensor,
141 SensorExtra{.format = format,
142 .samplingPeriod = static_cast<int32_t>(samplingPeriod.count())});
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700143 }
144
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700145 // Enable the sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700146 if (mQueue->enableSensor(sensor, samplingPeriod.count(), 0, 0)) {
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700147 ALOGE("Failed to enable sensor");
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700148 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800149 mEnabledSensorsExtra.erase(sensor);
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700150 return false;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700151 }
152
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700153 mEnabledSensors.emplace(sensor, SensorEnableGuard(mQueue.get(), sensor));
154 return true;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700155 }
156
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700157 void stopSensor(int handle) override {
158 mEnabledSensors.erase(handle);
159 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800160 mEnabledSensorsExtra.erase(handle);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700161 }
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700162
Shunkai Yao5a251df2022-07-22 18:42:27 +0000163 std::string toString(unsigned level) override {
164 std::string prefixSpace(level, ' ');
165 std::string ss = prefixSpace + "SensorPoseProvider:\n";
166 bool needUnlock = false;
167
168 prefixSpace += " ";
169 auto now = std::chrono::steady_clock::now();
170 if (!mMutex.try_lock_until(now + media::kSpatializerDumpSysTimeOutInSecond)) {
171 ss.append(prefixSpace).append("try_lock failed, dumpsys below maybe INACCURATE!\n");
172 } else {
173 needUnlock = true;
174 }
175
176 // Enabled sensor information
177 StringAppendF(&ss, "%sSensors total number %zu:\n", prefixSpace.c_str(),
178 mEnabledSensorsExtra.size());
179 for (auto sensor : mEnabledSensorsExtra) {
Shunkai Yao51379452022-08-30 03:14:50 +0000180 StringAppendF(&ss,
181 "%s[Handle: 0x%08x, Format %s Period (set %d max %0.4f min %0.4f) ms",
182 prefixSpace.c_str(), sensor.first, toString(sensor.second.format).c_str(),
183 sensor.second.samplingPeriod, media::nsToFloatMs(sensor.second.maxPeriod),
184 media::nsToFloatMs(sensor.second.minPeriod));
Shunkai Yao5a251df2022-07-22 18:42:27 +0000185 if (sensor.second.discontinuityCount.has_value()) {
186 StringAppendF(&ss, ", DiscontinuityCount: %d",
187 sensor.second.discontinuityCount.value());
188 }
189 ss += "]\n";
190 }
191
192 if (needUnlock) {
193 mMutex.unlock();
194 }
195 return ss;
196 }
197
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700198 private:
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700199 enum DataFormat {
200 kUnknown,
201 kQuaternion,
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800202 kRotationVectorsAndDiscontinuityCount,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700203 };
204
205 struct PoseEvent {
206 Pose3f pose;
207 std::optional<Twist3f> twist;
208 bool isNewReference;
209 };
210
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800211 struct SensorExtra {
Shunkai Yao51379452022-08-30 03:14:50 +0000212 DataFormat format = DataFormat::kUnknown;
213 int32_t samplingPeriod = 0;
214 int64_t latestTimestamp = 0;
215 int64_t maxPeriod = 0;
216 int64_t minPeriod = std::numeric_limits<int64_t>::max();
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800217 std::optional<int32_t> discontinuityCount;
218 };
219
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700220 sp<Looper> mLooper;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700221 Listener* const mListener;
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700222 SensorManager* const mSensorManager;
Shunkai Yao5a251df2022-07-22 18:42:27 +0000223 std::timed_mutex mMutex;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700224 std::map<int32_t, SensorEnableGuard> mEnabledSensors;
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800225 std::map<int32_t, SensorExtra> mEnabledSensorsExtra GUARDED_BY(mMutex);
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700226 sp<SensorEventQueue> mQueue;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700227
228 // We must do some of the initialization operations on the worker thread, because the API relies
229 // on the thread-local looper. In addition, as a matter of convenience, we store some of the
230 // state on the stack.
231 // For that reason, we use a two-step initialization approach, where the ctor mostly just starts
232 // the worker thread and that thread would notify, via the promise below whenever initialization
233 // is finished, and whether it was successful.
234 std::promise<bool> mInitPromise;
Keith Mok674f7352022-06-06 21:40:11 +0000235 std::thread mThread;
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700236
237 SensorPoseProviderImpl(const char* packageName, Listener* listener)
238 : mListener(listener),
Keith Mok674f7352022-06-06 21:40:11 +0000239 mSensorManager(&SensorManager::getInstanceForPackage(String16(packageName))) {
240 mThread = std::thread([this] { threadFunc(); });
241 }
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700242 void initFinished(bool success) { mInitPromise.set_value(success); }
243
244 bool waitInitFinished() { return mInitPromise.get_future().get(); }
245
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700246 void threadFunc() {
Ytai Ben-Tsvid9125692021-08-24 08:53:38 -0700247 // Obtain looper.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700248 mLooper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700249
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700250 // Create event queue.
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700251 mQueue = mSensorManager->createEventQueue();
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700252
Ytai Ben-Tsvic29bad62021-09-09 10:22:52 -0700253 if (mQueue == nullptr) {
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700254 ALOGE("Failed to create a sensor event queue");
255 initFinished(false);
256 return;
257 }
258
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700259 EventQueueGuard eventQueueGuard(mQueue, mLooper.get());
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700260
261 initFinished(true);
262
263 while (true) {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700264 int ret = mLooper->pollOnce(-1 /* no timeout */, nullptr, nullptr, nullptr);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700265
266 switch (ret) {
267 case ALOOPER_POLL_WAKE:
268 // Normal way to exit.
269 return;
270
271 case kIdent:
272 // Possible events on our queue.
273 break;
274
275 default:
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700276 ALOGE("Unexpected status out of Looper::pollOnce: %d", ret);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700277 }
278
279 // Process an event.
280 ASensorEvent event;
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700281 ssize_t actual = mQueue->read(&event, 1);
282 if (actual > 0) {
283 mQueue->sendAck(&event, actual);
284 }
285 ssize_t size = mQueue->filterEvents(&event, actual);
286
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700287 if (size < 0 || size > 1) {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700288 ALOGE("Unexpected return value from SensorEventQueue::filterEvents: %zd", size);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700289 break;
290 }
291 if (size == 0) {
292 // No events.
293 continue;
294 }
295
296 handleEvent(event);
297 }
298 }
299
300 void handleEvent(const ASensorEvent& event) {
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800301 PoseEvent value;
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700302 {
303 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800304 auto iter = mEnabledSensorsExtra.find(event.sensor);
305 if (iter == mEnabledSensorsExtra.end()) {
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700306 // This can happen if we have any pending events shortly after stopping.
307 return;
308 }
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800309 value = parseEvent(event, iter->second.format, &iter->second.discontinuityCount);
Shunkai Yao51379452022-08-30 03:14:50 +0000310 updateEventTimestamp(event, iter->second);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700311 }
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700312 mListener->onPose(event.timestamp, event.sensor, value.pose, value.twist,
313 value.isNewReference);
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700314 }
315
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700316 DataFormat getSensorFormat(int32_t handle) {
317 std::optional<const Sensor> sensor = getSensorByHandle(handle);
318 if (!sensor) {
319 ALOGE("Sensor not found: %d", handle);
320 return DataFormat::kUnknown;
321 }
322 if (sensor->getType() == ASENSOR_TYPE_ROTATION_VECTOR ||
323 sensor->getType() == ASENSOR_TYPE_GAME_ROTATION_VECTOR) {
324 return DataFormat::kQuaternion;
325 }
326
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800327 if (sensor->getType() == ASENSOR_TYPE_HEAD_TRACKER) {
328 return DataFormat::kRotationVectorsAndDiscontinuityCount;
329 }
330
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700331 return DataFormat::kUnknown;
332 }
333
Andy Hunga461a002022-05-17 10:36:02 -0700334 std::optional<const Sensor> getSensorByHandle(int32_t handle) override {
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700335 const Sensor* const* list;
336 ssize_t size;
337
338 // Search static sensor list.
339 size = mSensorManager->getSensorList(&list);
340 if (size < 0) {
341 ALOGE("getSensorList failed with error code %zd", size);
342 return std::nullopt;
343 }
344 for (size_t i = 0; i < size; ++i) {
345 if (list[i]->getHandle() == handle) {
346 return *list[i];
347 }
348 }
349
350 // Search dynamic sensor list.
351 Vector<Sensor> dynList;
352 size = mSensorManager->getDynamicSensorList(dynList);
353 if (size < 0) {
354 ALOGE("getDynamicSensorList failed with error code %zd", size);
355 return std::nullopt;
356 }
357 for (size_t i = 0; i < size; ++i) {
358 if (dynList[i].getHandle() == handle) {
359 return dynList[i];
360 }
361 }
362
363 return std::nullopt;
364 }
365
Shunkai Yao51379452022-08-30 03:14:50 +0000366 void updateEventTimestamp(const ASensorEvent& event, SensorExtra& extra) {
367 if (extra.latestTimestamp != 0) {
368 int64_t gap = event.timestamp - extra.latestTimestamp;
369 extra.maxPeriod = std::max(gap, extra.maxPeriod);
370 extra.minPeriod = std::min(gap, extra.minPeriod);
371 }
372 extra.latestTimestamp = event.timestamp;
373 }
374
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800375 static PoseEvent parseEvent(const ASensorEvent& event, DataFormat format,
376 std::optional<int32_t>* discontinutyCount) {
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700377 switch (format) {
378 case DataFormat::kQuaternion: {
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700379 Eigen::Quaternionf quat(event.data[3], event.data[0], event.data[1], event.data[2]);
Ytai Ben-Tsvi54f07582021-09-13 12:09:42 -0700380 // Adapt to different frame convention.
381 quat *= rotateX(-M_PI_2);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700382 return PoseEvent{Pose3f(quat), std::optional<Twist3f>(), false};
383 }
384
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800385 case DataFormat::kRotationVectorsAndDiscontinuityCount: {
386 Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
387 event.head_tracker.rz};
388 Eigen::Vector3f twist = {event.head_tracker.vx, event.head_tracker.vy,
Ytai Ben-Tsvi27bbea32022-01-28 18:01:06 -0800389 event.head_tracker.vz};
Ytai Ben-Tsvi87b06212022-01-20 16:52:03 -0800390 Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
391 bool isNewReference =
392 !discontinutyCount->has_value() ||
393 discontinutyCount->value() != event.head_tracker.discontinuity_count;
394 *discontinutyCount = event.head_tracker.discontinuity_count;
395
396 return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
397 isNewReference};
398 }
399
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700400 default:
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700401 LOG_ALWAYS_FATAL("Unexpected sensor type: %d", static_cast<int>(format));
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700402 }
403 }
Shunkai Yao5a251df2022-07-22 18:42:27 +0000404
Shunkai Yao51379452022-08-30 03:14:50 +0000405 const static std::string toString(DataFormat format) {
Shunkai Yao5a251df2022-07-22 18:42:27 +0000406 switch (format) {
407 case DataFormat::kUnknown:
408 return "kUnknown";
409 case DataFormat::kQuaternion:
410 return "kQuaternion";
411 case DataFormat::kRotationVectorsAndDiscontinuityCount:
412 return "kRotationVectorsAndDiscontinuityCount";
413 default:
414 return "NotImplemented";
415 }
416 }
Ytai Ben-Tsvi779d1ee2021-07-27 05:56:22 -0700417};
418
419} // namespace
420
421std::unique_ptr<SensorPoseProvider> SensorPoseProvider::create(const char* packageName,
422 Listener* listener) {
423 return SensorPoseProviderImpl::create(packageName, listener);
424}
425
426} // namespace media
427} // namespace android