Merge "Add @TestApi to inject driving state." into qt-dev
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index d6b162e..515bd93 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -7,6 +7,14 @@
 
 }
 
+package android.car.drivingstate {
+
+  public final class CarDrivingStateManager {
+    method public void injectDrivingState(int);
+  }
+
+}
+
 package android.car.media {
 
   public final class CarAudioManager {
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
index 896534a..9b0626f 100644
--- a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.Context;
 import android.os.Handler;
@@ -26,15 +28,18 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
 
 /**
  * API to register and get driving state related information in a car.
+ *
  * @hide
  */
 @SystemApi
+@TestApi
 public final class CarDrivingStateManager implements CarManagerBase {
     private static final String TAG = "CarDrivingStateMgr";
     private static final boolean DBG = false;
@@ -64,7 +69,10 @@
 
     /**
      * Listener Interface for clients to implement to get updated on driving state changes.
+     *
+     * @hide
      */
+    @SystemApi
     public interface CarDrivingStateEventListener {
         /**
          * Called when the car's driving state changes.
@@ -77,7 +85,10 @@
      * Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
      *
      * @param listener  {@link CarDrivingStateEventListener}
+     *
+     * @hide
      */
+    @SystemApi
     public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener) {
         if (listener == null) {
             if (VDBG) {
@@ -107,7 +118,10 @@
     /**
      * Unregister the registered {@link CarDrivingStateEventListener} for the given driving event
      * type.
+     *
+     * @hide
      */
+    @SystemApi
     public synchronized void unregisterListener() {
         if (mDrvStateEventListener == null) {
             if (DBG) {
@@ -128,8 +142,11 @@
      * Get the current value of the car's driving state.
      *
      * @return {@link CarDrivingStateEvent} corresponding to the given eventType
+     *
+     * @hide
      */
     @Nullable
+    @SystemApi
     public CarDrivingStateEvent getCurrentCarDrivingState() {
         try {
             return mDrivingService.getCurrentDrivingState();
@@ -139,6 +156,27 @@
     }
 
     /**
+     * Notify registered driving state change listener about injected event.
+     *
+     * @param drivingState Value in {@link CarDrivingStateEvent.CarDrivingState}.
+     *
+     * Requires Permission:
+     * {@link Car#PERMISSION_CONTROL_APP_BLOCKING}
+     *
+     * @hide
+     */
+    @TestApi
+    public void injectDrivingState(int drivingState) {
+        CarDrivingStateEvent event = new CarDrivingStateEvent(
+                drivingState, SystemClock.elapsedRealtimeNanos());
+        try {
+            mDrivingService.injectDrivingState(event);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Class that implements the listener interface and gets called back from the
      * {@link com.android.car.CarDrivingStateService} across the binder interface.
      */
diff --git a/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
index 30f1542..23c5d03 100644
--- a/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
@@ -31,4 +31,5 @@
     void registerDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 0;
     void unregisterDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 1;
     CarDrivingStateEvent getCurrentDrivingState() = 2;
+    void injectDrivingState(in CarDrivingStateEvent event) = 3;
 }
diff --git a/service/src/com/android/car/CarDrivingStateService.java b/service/src/com/android/car/CarDrivingStateService.java
index bc0fbc1..48840b7 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -17,6 +17,7 @@
 package com.android.car;
 
 import android.annotation.Nullable;
+import android.car.Car;
 import android.car.VehicleAreaType;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarDrivingStateEvent.CarDrivingState;
@@ -220,6 +221,15 @@
         return mCurrentDrivingState;
     }
 
+    @Override
+    public synchronized void injectDrivingState(CarDrivingStateEvent event) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_CONTROL_APP_BLOCKING);
+
+        for (DrivingStateClient client : mDrivingStateClients) {
+            client.dispatchEventToClients(event);
+        }
+    }
+
     /**
      * Class that holds onto client related information - listener interface, process that hosts the
      * binder object etc.