Add vehicle HAL mocking with carsystem and carsystemtest API

- System API and system test API for testing only added. Client
  should link only one of them.
- vehicle HAL mocking allows mocking vehicle HAL completely.
- Once mocking is started, for now, all previous states are forgotton,
  so stopping mocking does not return to original state. It is
  better to simply restart framework after test.
- Added skeleton code for audio focus handling. Detailed implementaiton
  will be added later.

bug: 24874617

Change-Id: I6e60daab3dc96769a94acc09a695f8f49dbb8536
(cherry picked from commit a32e24f50d5895a94d3a13d6ec2233af6e43dac5)
diff --git a/service/src/com/android/car/CarAudioService.java b/service/src/com/android/car/CarAudioService.java
index e730ee8..881b2c5 100644
--- a/service/src/com/android/car/CarAudioService.java
+++ b/service/src/com/android/car/CarAudioService.java
@@ -177,6 +177,7 @@
     }
 
     private void doHandleSystemAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
+        //TODO distinguish car service's own focus request from others
         if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
             mFocusInfos[0] = afi;
             sendCarAudioFocusRequestIfNecessary();
@@ -229,6 +230,16 @@
         }
     }
 
+    /**
+     * Focus listener to take focus away from android apps.
+     */
+    private class AndroidFocusListener implements AudioManager.OnAudioFocusChangeListener {
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            // nothing to do as system focus listener will get all necessary information.
+        }
+    }
+
     private class CarAudioChangeHandler extends Handler {
         private static final int MSG_FOCUS_CHANGE = 0;
         private static final int MSG_STREAM_STATE_CHANGE = 1;
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index fe24354..e6ddc9e 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -23,4 +23,5 @@
     public static final String TAG_HAL = "CAR.HAL";
     public static final String TAG_INFO = "CAR.INFO";
     public static final String TAG_AUDIO = "CAR.AUDIO";
+    public static final String TAG_TEST = "CAR.TEST";
 }
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
index e230f25..cffb37e 100644
--- a/service/src/com/android/car/CarSensorService.java
+++ b/service/src/com/android/car/CarSensorService.java
@@ -71,14 +71,6 @@
 
         /** Sensor service is ready and all vehicle sensors are available. */
         public abstract void onSensorServiceReady();
-
-        /**
-         * Provide default sensor value. This value should be always provided after {@link #init()}
-         * call. Default value for safety related sensor should be giving safe state.
-         * @param sensorType
-         * @return
-         */
-        public abstract CarSensorEvent getDefaultValue(int sensorType);
     }
 
     /**
@@ -144,19 +136,20 @@
             mSupportedSensors = refreshSupportedSensorsLocked();
             if (mUseDefaultDrivingPolicy) {
                 mDrivingStatePolicy.init();
-                addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
-                        mDrivingStatePolicy.getDefaultValue(
-                                CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
                 mDrivingStatePolicy.registerSensorListener(this);
             }
+            // always populate default value
+            addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
+                    DrivingStatePolicy.getDefaultValue(
+                            CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
             if (mUseDefaultDayNightModePolicy) {
                 mDayNightModePolicy.init();
-                addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
-                        mDrivingStatePolicy.getDefaultValue(
-                                CarSensorManager.SENSOR_TYPE_NIGHT));
                 mDayNightModePolicy.registerSensorListener(this);
             }
-
+            // always populate default value
+            addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
+                    DayNightModePolicy.getDefaultValue(
+                            CarSensorManager.SENSOR_TYPE_NIGHT));
         } finally {
             mSensorLock.unlock();
         }
@@ -171,7 +164,9 @@
 
     @Override
     public void release() {
-        mHandlerThread.quit();
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+        }
         tryHoldSensorLock();
         try {
             if (mUseDefaultDrivingPolicy) {
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
new file mode 100644
index 0000000..26a1b7d
--- /dev/null
+++ b/service/src/com/android/car/CarTestService.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package com.android.car;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.car.hal.VehicleHal;
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+import java.io.PrintWriter;
+
+/**
+ * Service to allow testing / mocking vehicle HAL.
+ * This service uses Vehicle HAL APIs directly (one exception) as vehicle HAL mocking anyway
+ * requires accessing that level directly.
+ */
+public class CarTestService extends ICarTest.Stub implements CarServiceBase {
+    private static final int VERSION = 1;
+
+    private final Context mContext;
+    private final VehicleNetwork mVehicleNetwork;
+    private final ICarImpl mICarImpl;
+
+    public CarTestService(Context context, ICarImpl carImpl) {
+        mContext = context;
+        mICarImpl = carImpl;
+        mVehicleNetwork = VehicleHal.getInstance().getVehicleNetwork();
+    }
+
+    @Override
+    public void init() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void release() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public int getVersion() {
+        return VERSION;
+    }
+
+    @Override
+    public void injectEvent(VehiclePropValueParcelable value) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.injectEvent(value.value);
+    }
+
+    @Override
+    public void startMocking(IVehicleNetworkHalMock mock) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.startMocking(mock);
+        VehicleHal.getInstance().startMocking();
+        mICarImpl.startMocking();
+    }
+
+    @Override
+    public void stopMocking(IVehicleNetworkHalMock mock) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.stopMocking(mock);
+        VehicleHal.getInstance().stopMocking();
+        mICarImpl.stopMocking();
+    }
+}
diff --git a/service/src/com/android/car/DayNightModePolicy.java b/service/src/com/android/car/DayNightModePolicy.java
index 23f36d9..892c077 100644
--- a/service/src/com/android/car/DayNightModePolicy.java
+++ b/service/src/com/android/car/DayNightModePolicy.java
@@ -17,6 +17,7 @@
 package com.android.car;
 
 import android.content.Context;
+import android.os.SystemClock;
 import android.support.car.Car;
 import android.support.car.CarSensorEvent;
 import android.support.car.CarSensorManager;
@@ -47,10 +48,8 @@
         // TODO Auto-generated method stub
     }
 
-    @Override
-    public synchronized CarSensorEvent getDefaultValue(int sensorType) {
-        // TODO Auto-generated method stub
-        return null;
+    public static CarSensorEvent getDefaultValue(int sensorType) {
+        return createEvent(true /* isNight */);
     }
 
     @Override
@@ -89,6 +88,13 @@
         // TODO Auto-generated method stub
     }
 
+    private static CarSensorEvent createEvent(boolean isNight) {
+        CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT,
+                SystemClock.elapsedRealtimeNanos(), 0, 1);
+        event.intValues[0] = isNight ? 1 : 0;
+        return event;
+    }
+
     @Override
     public synchronized void dump(PrintWriter writer) {
         // TODO Auto-generated method stub
diff --git a/service/src/com/android/car/DrivingStatePolicy.java b/service/src/com/android/car/DrivingStatePolicy.java
index e1eed18..11fad66 100644
--- a/service/src/com/android/car/DrivingStatePolicy.java
+++ b/service/src/com/android/car/DrivingStatePolicy.java
@@ -91,14 +91,13 @@
         // TODO Auto-generated method stub
     }
 
-    @Override
-    public synchronized CarSensorEvent getDefaultValue(int sensorType) {
+    public static CarSensorEvent getDefaultValue(int sensorType) {
         if (sensorType != CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
-            Log.w(CarLog.TAG_SENSOR, "getCurrentValue to DrivingStatePolicy with sensorType:" +
+            Log.w(CarLog.TAG_SENSOR, "getDefaultValue to DrivingStatePolicy with sensorType:" +
                     sensorType);
             return null;
         }
-        return createEvent(mDringState);
+        return createEvent(CarSensorEvent.DRIVE_STATUS_FULLY_RESTRICTED);
     }
 
     @Override
@@ -202,7 +201,7 @@
         return gear == CarSensorEvent.GEAR_PARK;
     }
 
-    private CarSensorEvent createEvent(int drivingState) {
+    private static CarSensorEvent createEvent(int drivingState) {
         CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
                 SystemClock.elapsedRealtimeNanos(), 0, 1);
         event.intValues[0] = drivingState;
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index b02bce6..779a48f 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.support.car.Car;
 import android.support.car.ICar;
@@ -41,6 +42,9 @@
     private final CarSensorService mCarSensorService;
     private final CarInfoService mCarInfoService;
     private final CarAudioService mCarAudioService;
+    /** Test only service. Populate it only when necessary. */
+    @GuardedBy("this")
+    private CarTestService mCarTestService;
     private final CarServiceBase[] mAllServices;
 
     public synchronized static ICarImpl getInstance(Context serviceContext) {
@@ -86,6 +90,23 @@
         VehicleHal.releaseInstance();
     }
 
+    public void startMocking() {
+        reinitServices();
+    }
+
+    public void stopMocking() {
+        reinitServices();
+    }
+
+    private void reinitServices() {
+        for (int i = mAllServices.length - 1; i >= 0; i--) {
+            mAllServices[i].release();
+        }
+        for (CarServiceBase service: mAllServices) {
+            service.init();
+        }
+    }
+
     @Override
     public int getVersion() {
         return VERSION;
@@ -98,6 +119,15 @@
                 return mCarSensorService;
             case Car.INFO_SERVICE:
                 return mCarInfoService;
+            case CarSystemTest.TEST_SERVICE: {
+                assertVehicleHalMockPermission(mContext);
+                synchronized (this) {
+                    if (mCarTestService == null) {
+                        mCarTestService = new CarTestService(mContext, this);
+                    }
+                    return mCarTestService;
+                }
+            }
             default:
                 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
                 return null;
@@ -130,10 +160,21 @@
         return false;
     }
 
+    public static void assertVehicleHalMockPermission(Context context) {
+        if (context.checkCallingOrSelfPermission(CarSystemTest.PERMISSION_MOCK_VEHICLE_HAL)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
+        }
+    }
+
     void dump(PrintWriter writer) {
         writer.println("*Dump all services*");
         for (CarServiceBase service: mAllServices) {
             service.dump(writer);
         }
+        CarTestService testService = mCarTestService;
+        if (testService != null) {
+            testService.dump(writer);
+        }
     }
 }
diff --git a/service/src/com/android/car/hal/AudioHalService.java b/service/src/com/android/car/hal/AudioHalService.java
index 59fb6c8..e83cfe9 100644
--- a/service/src/com/android/car/hal/AudioHalService.java
+++ b/service/src/com/android/car/hal/AudioHalService.java
@@ -16,8 +16,8 @@
 package com.android.car.hal;
 
 import com.android.car.vehiclenetwork.VehicleNetworkConsts;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequestType;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusStateType;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
@@ -29,33 +29,33 @@
 public class AudioHalService extends HalServiceBase {
 
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
 
     public static String audioFocusRequestToString(int request) {
-        return VehicleAudioFocusRequestType.enumToString(request);
+        return VehicleAudioFocusRequest.enumToString(request);
     }
 
     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
 
     public static String audioFocusStateToString(int state) {
-        return VehicleAudioFocusStateType.enumToString(state);
+        return VehicleAudioFocusState.enumToString(state);
     }
 
     public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
@@ -115,10 +115,12 @@
                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
             mVehicleHal.unsubscribeProperty(this,
                     VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE);
+            mFocusSupported = false;
         }
         if (mVolumeSupported) {
             mVehicleHal.unsubscribeProperty(this,
                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
+            mVolumeSupported = false;
         }
     }
 
diff --git a/service/src/com/android/car/hal/SensorHalService.java b/service/src/com/android/car/hal/SensorHalService.java
index 4fb8398..e7fb8f4 100644
--- a/service/src/com/android/car/hal/SensorHalService.java
+++ b/service/src/com/android/car/hal/SensorHalService.java
@@ -38,7 +38,7 @@
  */
 public class SensorHalService extends SensorHalServiceBase {
 
-    private static final boolean DBG_EVENTS = true;
+    private static final boolean DBG_EVENTS = false;
 
     private static final int SENSOR_TYPE_INVALD = -1;
 
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index d41def1..4652324 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -147,6 +147,19 @@
         // keep the looper thread as should be kept for the whole life cycle.
     }
 
+    public void startMocking() {
+        reinitHals();
+    }
+
+    public void stopMocking() {
+        reinitHals();
+    }
+
+    private void reinitHals() {
+        release();
+        doInit();
+    }
+
     public SensorHalService getSensorHal() {
         return mSensorHal;
     }
@@ -159,18 +172,6 @@
         return mAudioHal;
     }
 
-    /**
-     * Start mocking HAL with given mock. Actual H/W will be stop functioning until mocking is
-     * stopped. The call will be blocked until all pending events are delivered to upper layer.
-     */
-    public void startHalMocking(HalMock mock) {
-        //TODO
-    }
-
-    public void stopHalMocking() {
-        //TODO
-    }
-
     private void assertServiceOwner(HalServiceBase service, int property) {
         if (service != mPropertyHandlers.get(property)) {
             throw new IllegalArgumentException("not owned");