Loading include/input/MotionPredictor.h +7 −0 Original line number Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <android-base/thread_annotations.h> #include <android/sysprop/InputProperties.sysprop.h> #include <input/Input.h> #include <input/MotionPredictorMetricsManager.h> #include <input/TfLiteMotionPredictor.h> #include <utils/Timers.h> // for nsecs_t namespace android { Loading Loading @@ -69,6 +71,7 @@ public: */ MotionPredictor(nsecs_t predictionTimestampOffsetNanos, std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled); /** * Record the actual motion received by the view. This event will be used for calculating the * predictions. Loading @@ -77,7 +80,9 @@ public: * consistent with the previously recorded events. */ android::base::Result<void> record(const MotionEvent& event); std::unique_ptr<MotionEvent> predict(nsecs_t timestamp); bool isPredictionAvailable(int32_t deviceId, int32_t source); private: Loading @@ -88,6 +93,8 @@ private: std::unique_ptr<TfLiteMotionPredictorBuffers> mBuffers; std::optional<MotionEvent> mLastEvent; std::optional<MotionPredictorMetricsManager> mMetricsManager; }; } // namespace android include/input/MotionPredictorMetricsManager.h 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <utils/Timers.h> namespace android { /** * Class to handle computing and reporting metrics for MotionPredictor. * * Currently an empty implementation, containing only the API. */ class MotionPredictorMetricsManager { public: // Note: the MetricsManager assumes that the input interval equals the prediction interval. MotionPredictorMetricsManager(nsecs_t /*predictionInterval*/, size_t /*maxNumPredictions*/) {} void onRecord(const MotionEvent& /*inputEvent*/) {} void onPredict(const MotionEvent& /*predictionEvent*/) {} }; } // namespace android libs/input/MotionPredictor.cpp +26 −9 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ MotionPredictor::MotionPredictor(nsecs_t predictionTimestampOffsetNanos, android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { if (mLastEvent && mLastEvent->getDeviceId() != event.getDeviceId()) { // We still have an active gesture for another device. The provided MotionEvent is not // consistent the previous gesture. // consistent with the previous gesture. LOG(ERROR) << "Inconsistent event stream: last event is " << *mLastEvent << ", but " << __func__ << " is called with " << event; return android::base::Error() Loading @@ -83,9 +83,10 @@ android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { // Initialise the model now that it's likely to be used. if (!mModel) { mModel = TfLiteMotionPredictorModel::create(); LOG_ALWAYS_FATAL_IF(!mModel); } if (mBuffers == nullptr) { if (!mBuffers) { mBuffers = std::make_unique<TfLiteMotionPredictorBuffers>(mModel->inputLength()); } Loading Loading @@ -133,6 +134,15 @@ android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { mLastEvent = MotionEvent(); } mLastEvent->copyFrom(&event, /*keepHistory=*/false); // Pass input event to the MetricsManager. if (!mMetricsManager) { mMetricsManager = std::make_optional<MotionPredictorMetricsManager>(mModel->predictionInterval(), mModel->outputLength()); } mMetricsManager->onRecord(event); return {}; } Loading Loading @@ -174,16 +184,17 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { const TfLiteMotionPredictorSample::Point point = // TODO(b/266747654): Stop predictions if confidence and/or predicted pressure are below // some thresholds. const TfLiteMotionPredictorSample::Point predictedPoint = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); // TODO(b/266747654): Stop predictions if confidence is < some threshold. ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, point.x, point.y); ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, predictedPoint.x, predictedPoint.y); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, point.x); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, point.y); // TODO(b/266747654): Stop predictions if predicted pressure is < some threshold. coords.setAxisValue(AMOTION_EVENT_AXIS_X, predictedPoint.x); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, predictedPoint.y); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, predictedPressure[i]); predictionTime += mModel->predictionInterval(); Loading @@ -203,11 +214,17 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { } axisFrom = axisTo; axisTo = point; axisTo = predictedPoint; } if (!hasPredictions) { return nullptr; } // Pass predictions to the MetricsManager. LOG_ALWAYS_FATAL_IF(!mMetricsManager); mMetricsManager->onPredict(*prediction); return prediction; } Loading Loading
include/input/MotionPredictor.h +7 −0 Original line number Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <android-base/thread_annotations.h> #include <android/sysprop/InputProperties.sysprop.h> #include <input/Input.h> #include <input/MotionPredictorMetricsManager.h> #include <input/TfLiteMotionPredictor.h> #include <utils/Timers.h> // for nsecs_t namespace android { Loading Loading @@ -69,6 +71,7 @@ public: */ MotionPredictor(nsecs_t predictionTimestampOffsetNanos, std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled); /** * Record the actual motion received by the view. This event will be used for calculating the * predictions. Loading @@ -77,7 +80,9 @@ public: * consistent with the previously recorded events. */ android::base::Result<void> record(const MotionEvent& event); std::unique_ptr<MotionEvent> predict(nsecs_t timestamp); bool isPredictionAvailable(int32_t deviceId, int32_t source); private: Loading @@ -88,6 +93,8 @@ private: std::unique_ptr<TfLiteMotionPredictorBuffers> mBuffers; std::optional<MotionEvent> mLastEvent; std::optional<MotionPredictorMetricsManager> mMetricsManager; }; } // namespace android
include/input/MotionPredictorMetricsManager.h 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 <utils/Timers.h> namespace android { /** * Class to handle computing and reporting metrics for MotionPredictor. * * Currently an empty implementation, containing only the API. */ class MotionPredictorMetricsManager { public: // Note: the MetricsManager assumes that the input interval equals the prediction interval. MotionPredictorMetricsManager(nsecs_t /*predictionInterval*/, size_t /*maxNumPredictions*/) {} void onRecord(const MotionEvent& /*inputEvent*/) {} void onPredict(const MotionEvent& /*predictionEvent*/) {} }; } // namespace android
libs/input/MotionPredictor.cpp +26 −9 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ MotionPredictor::MotionPredictor(nsecs_t predictionTimestampOffsetNanos, android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { if (mLastEvent && mLastEvent->getDeviceId() != event.getDeviceId()) { // We still have an active gesture for another device. The provided MotionEvent is not // consistent the previous gesture. // consistent with the previous gesture. LOG(ERROR) << "Inconsistent event stream: last event is " << *mLastEvent << ", but " << __func__ << " is called with " << event; return android::base::Error() Loading @@ -83,9 +83,10 @@ android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { // Initialise the model now that it's likely to be used. if (!mModel) { mModel = TfLiteMotionPredictorModel::create(); LOG_ALWAYS_FATAL_IF(!mModel); } if (mBuffers == nullptr) { if (!mBuffers) { mBuffers = std::make_unique<TfLiteMotionPredictorBuffers>(mModel->inputLength()); } Loading Loading @@ -133,6 +134,15 @@ android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { mLastEvent = MotionEvent(); } mLastEvent->copyFrom(&event, /*keepHistory=*/false); // Pass input event to the MetricsManager. if (!mMetricsManager) { mMetricsManager = std::make_optional<MotionPredictorMetricsManager>(mModel->predictionInterval(), mModel->outputLength()); } mMetricsManager->onRecord(event); return {}; } Loading Loading @@ -174,16 +184,17 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { const TfLiteMotionPredictorSample::Point point = // TODO(b/266747654): Stop predictions if confidence and/or predicted pressure are below // some thresholds. const TfLiteMotionPredictorSample::Point predictedPoint = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); // TODO(b/266747654): Stop predictions if confidence is < some threshold. ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, point.x, point.y); ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, predictedPoint.x, predictedPoint.y); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, point.x); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, point.y); // TODO(b/266747654): Stop predictions if predicted pressure is < some threshold. coords.setAxisValue(AMOTION_EVENT_AXIS_X, predictedPoint.x); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, predictedPoint.y); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, predictedPressure[i]); predictionTime += mModel->predictionInterval(); Loading @@ -203,11 +214,17 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { } axisFrom = axisTo; axisTo = point; axisTo = predictedPoint; } if (!hasPredictions) { return nullptr; } // Pass predictions to the MetricsManager. LOG_ALWAYS_FATAL_IF(!mMetricsManager); mMetricsManager->onPredict(*prediction); return prediction; } Loading