Add amount of prediction to the predict call

This is an internal change for the MotionPrediction API. Instead of having
a fixed amount of prediction, the Kalman library consumer will be able to
specify the desired amount of prediction.

Bug: 232941452
Test: tested on sample app, confirmed that prediction works as expected
Change-Id: I8f887ebca3288d4b4dbe21e2f0b4dcaf918f8de7
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanMotionEventPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanMotionEventPredictor.java
index 91bec15..7a7ab0f 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanMotionEventPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanMotionEventPredictor.java
@@ -32,11 +32,6 @@
     private MultiPointerPredictor mMultiPointerPredictor = new MultiPointerPredictor();
 
     public KalmanMotionEventPredictor() {
-        // 1 may seem arbitrary, but this basically tells the predictor to
-        // just predict the next MotionEvent.
-        // This will need to change as we want to build a prediction depending
-        // on the expected time that the frame will arrive to the screen.
-        mMultiPointerPredictor.setPredictionTarget(1);
     }
 
     @Override
@@ -53,7 +48,7 @@
         if (mMultiPointerPredictor == null) {
             return null;
         }
-        return mMultiPointerPredictor.predict();
+        return mMultiPointerPredictor.predict(1);
     }
 
     @Override
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanPredictor.java
index 87a35e6..3a8ff60 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/KalmanPredictor.java
@@ -30,13 +30,6 @@
  */
 @RestrictTo(LIBRARY)
 public interface KalmanPredictor {
-
-    /** Gets the current prediction target */
-    int getPredictionTarget();
-
-    /** Sets the current prediction target */
-    void setPredictionTarget(int predictionTargetMillis);
-
     /** Sets the report rate */
     void setReportRate(int reportRateMs);
 
@@ -45,5 +38,5 @@
 
     /** @return null if not possible to make a prediction. */
     @Nullable
-    MotionEvent predict();
+    MotionEvent predict(int predictionTargetMillis);
 }
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
index cb6c3a9..3f02764 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/MultiPointerPredictor.java
@@ -36,29 +36,11 @@
     private static final boolean DEBUG_PREDICTION = Log.isLoggable(TAG, Log.DEBUG);
 
     private final SparseArray<SinglePointerPredictor> mPredictorMap = new SparseArray<>();
-    private int mPredictionTargetMs = 0;
     private int mReportRateMs = 0;
 
     public MultiPointerPredictor() {}
 
     @Override
-    public int getPredictionTarget() {
-        return mPredictionTargetMs;
-    }
-
-    @Override
-    public void setPredictionTarget(int predictionTargetMillis) {
-        if (predictionTargetMillis < 0) {
-            predictionTargetMillis = 0;
-        }
-        mPredictionTargetMs = predictionTargetMillis;
-
-        for (int i = 0; i < mPredictorMap.size(); ++i) {
-            mPredictorMap.valueAt(i).setPredictionTarget(predictionTargetMillis);
-        }
-    }
-
-    @Override
     public void setReportRate(int reportRateMs) {
         if (reportRateMs <= 0) {
             throw new IllegalArgumentException(
@@ -78,7 +60,6 @@
         int pointerId = event.getPointerId(actionIndex);
         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
             SinglePointerPredictor predictor = new SinglePointerPredictor();
-            predictor.setPredictionTarget(mPredictionTargetMs);
             if (mReportRateMs > 0) {
                 predictor.setReportRate(mReportRateMs);
             }
@@ -113,7 +94,7 @@
 
     /** Support eventTime */
     @Override
-    public @Nullable MotionEvent predict() {
+    public @Nullable MotionEvent predict(int predictionTargetMs) {
         final int pointerCount = mPredictorMap.size();
         // Shortcut for likely case where only zero or one pointer is on the screen
         // this logic exists only to make sure logic when one pointer is on screen then
@@ -128,7 +109,7 @@
         }
         if (pointerCount == 1) {
             SinglePointerPredictor predictor = mPredictorMap.valueAt(0);
-            MotionEvent predictedEv = predictor.predict();
+            MotionEvent predictedEv = predictor.predict(predictionTargetMs);
             if (DEBUG_PREDICTION) {
                 Log.d(TAG, "predict() -> MotionEvent: " + predictedEv);
             }
@@ -141,7 +122,7 @@
         for (int i = 0; i < pointerCount; ++i) {
             pointerIds[i] = mPredictorMap.keyAt(i);
             SinglePointerPredictor predictor = mPredictorMap.valueAt(i);
-            singlePointerEvents[i] = predictor.predict();
+            singlePointerEvents[i] = predictor.predict(predictionTargetMs);
             // If predictor consumer expect more sample, generate sample where position and
             // pressure are constant
             singlePointerEvents[i] = predictor.appendPredictedEvent(singlePointerEvents[i]);
diff --git a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
index 0ba5bc6..74dfc7c 100644
--- a/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
+++ b/input/input-motionprediction/src/main/java/androidx/input/motionprediction/kalman/SinglePointerPredictor.java
@@ -60,9 +60,6 @@
     // Minimum number of Kalman filter samples needed for predicting the next point
     private static final int MIN_KALMAN_FILTER_ITERATIONS = 4;
 
-    // Target time in milliseconds to predict.
-    private float mPredictionTargetMs = 0.0f;
-
     // The Kalman filter is tuned to smooth noise while maintaining fast reaction to direction
     // changes. The stronger the filter, the smoother the prediction result will be, at the
     // cost of possible prediction errors.
@@ -148,23 +145,6 @@
     }
 
     @Override
-    public int getPredictionTarget() {
-        // Prediction target should always be an int, so no precision lost in the cast
-        return (int) mPredictionTargetMs;
-    }
-
-    @Override
-    public void setPredictionTarget(int predictionTargetMillis) {
-        if (predictionTargetMillis < 0) {
-            predictionTargetMillis = 0;
-        }
-        mPredictionTargetMs = predictionTargetMillis;
-        if (mReportRates == null) {
-            mExpectedPredictionSampleSize = (int) Math.ceil(mPredictionTargetMs / mReportRateMs);
-        }
-    }
-
-    @Override
     public void setReportRate(int reportRateMs) {
         if (reportRateMs <= 0) {
             throw new IllegalArgumentException(
@@ -172,8 +152,6 @@
         }
         mReportRateMs = reportRateMs;
         mReportRates = null;
-
-        mExpectedPredictionSampleSize = (int) Math.ceil(mPredictionTargetMs / mReportRateMs);
     }
 
     @Override
@@ -205,7 +183,11 @@
     }
 
     @Override
-    public @Nullable MotionEvent predict() {
+    public @Nullable MotionEvent predict(int predictionTargetMs) {
+        if (mReportRates == null) {
+            mExpectedPredictionSampleSize = (int) Math.ceil(predictionTargetMs / mReportRateMs);
+        }
+
         if (mExpectedPredictionSampleSize == -1
                 && mKalman.getNumIterations() < MIN_KALMAN_FILTER_ITERATIONS) {
             return null;
@@ -236,7 +218,7 @@
 
         // Project physical state of the pen into the future.
         int predictionTargetInSamples =
-                (int) Math.ceil(mPredictionTargetMs / mReportRateMs * confidenceFactor);
+                (int) Math.ceil(predictionTargetMs / mReportRateMs * confidenceFactor);
 
         // Normally this should always be false as confidenceFactor should be less than 1.0
         if (mExpectedPredictionSampleSize != -1