Fix setting night mode and change test crashes EKS

Add AsyncTask to refresh Car*Manager. Ensure all properties will
be checked when we use unregister a listener.

Bug: 110043754, 110437786
Test: 1) Start EKS, Select "Sensors" test.
      2) Use vhal_emulator.py to set night model state to 1.
      3) Switch to "hvac" test, set nigth model state to 0.

Change-Id: I48ce210c45cf2da2db90178aa909e5f10eada8f6
Merged-In: I48ce210c45cf2da2db90178aa909e5f10eada8f6
(cherry picked from commit cf3387bd4c90ee09eeff2dc0878c26a399e5ff23)
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index ff8c4db..373c23a 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -178,8 +178,12 @@
      */
     public void unregisterListener(CarPropertyEventListener listener) {
         synchronized (mActivePropertyListener) {
+            int [] propertyIds = new int[mActivePropertyListener.size()];
             for (int i = 0; i < mActivePropertyListener.size(); i++) {
-                doUnregisterListenerLocked(listener, mActivePropertyListener.keyAt(i));
+                propertyIds[i] = mActivePropertyListener.keyAt(i);
+            }
+            for (int prop : propertyIds) {
+                doUnregisterListenerLocked(listener, prop);
             }
         }
     }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index 7837f2e..8f6d92a 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -23,7 +23,9 @@
 import android.car.hardware.property.CarPropertyManager;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.car.Car;
 import android.support.car.CarAppFocusManager;
 import android.support.car.CarConnectionCallback;
@@ -183,6 +185,7 @@
     private CarPropertyManager mPropertyManager;
     private CarSensorManager mSensorManager;
     private CarAppFocusManager mCarAppFocusManager;
+    private Object mPropertyManagerReady = new Object();
 
     public CarHvacManager getHvacManager() {
         return mHvacManager;
@@ -212,12 +215,20 @@
         setMainContent(R.layout.kitchen_content);
         // Connection to Car Service does not work for non-automotive yet.
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-            mCarApi = Car.createCar(this, mCarConnectionCallback);
-            mCarApi.connect();
+            initCarApi();
         }
         Log.i(TAG, "onCreate");
     }
 
+    private void initCarApi() {
+        if (mCarApi != null && mCarApi.isConnected()) {
+            mCarApi.disconnect();
+            mCarApi = null;
+        }
+        mCarApi = Car.createCar(this, mCarConnectionCallback);
+        mCarApi.connect();
+    }
+
     @Override
     protected void onStart() {
         super.onStart();
@@ -268,18 +279,22 @@
         @Override
         public void onConnected(Car car) {
             Log.d(TAG, "Connected to Car Service");
-            try {
-                mHvacManager = (CarHvacManager) mCarApi.getCarManager(android.car.Car.HVAC_SERVICE);
-                mPowerManager = (CarPowerManager) mCarApi.getCarManager(
-                    android.car.Car.POWER_SERVICE);
-                mPropertyManager = (CarPropertyManager) mCarApi.getCarManager(
-                    android.car.Car.PROPERTY_SERVICE);
-                mSensorManager = (CarSensorManager) mCarApi.getCarManager(
-                    android.car.Car.SENSOR_SERVICE);
-                mCarAppFocusManager =
-                        (CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE);
-            } catch (CarNotConnectedException e) {
-                Log.e(TAG, "Car is not connected!", e);
+            synchronized (mPropertyManagerReady) {
+                try {
+                    mHvacManager = (CarHvacManager) mCarApi.getCarManager(
+                            android.car.Car.HVAC_SERVICE);
+                    mPowerManager = (CarPowerManager) mCarApi.getCarManager(
+                            android.car.Car.POWER_SERVICE);
+                    mPropertyManager = (CarPropertyManager) mCarApi.getCarManager(
+                            android.car.Car.PROPERTY_SERVICE);
+                    mSensorManager = (CarSensorManager) mCarApi.getCarManager(
+                            android.car.Car.SENSOR_SERVICE);
+                    mCarAppFocusManager =
+                            (CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE);
+                    mPropertyManagerReady.notifyAll();
+                } catch (CarNotConnectedException e) {
+                    Log.e(TAG, "Car is not connected!", e);
+                }
             }
         }
 
@@ -322,4 +337,29 @@
             getDrawerController().closeDrawer();
         }
     }
+
+    // Use AsyncTask to refresh Car*Manager after car service connected
+    public void requestRefreshManager(final Runnable r, final Handler h) {
+        final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                synchronized (mPropertyManagerReady) {
+                    while (!mCarApi.isConnected()) {
+                        try {
+                            mPropertyManagerReady.wait();
+                        } catch (InterruptedException e) {
+                            return null;
+                        }
+                    }
+                }
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void unused) {
+                h.post(r);
+            }
+        };
+        task.execute();
+    }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
index a1f8e1d..c7b80e8 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/hvac/HvacTestFragment.java
@@ -25,6 +25,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
 import android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v4.app.Fragment;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -76,6 +77,8 @@
     private int mZoneForSetTempP;
     private int mZoneForFanSpeed;
     private int mZoneForFanPosition;
+    private List<CarPropertyConfig> mCarPropertyConfigs;
+    private View mHvacView;
 
     private final CarHvacManager.CarHvacEventCallback mHvacCallback =
             new CarHvacManager.CarHvacEventCallback () {
@@ -171,13 +174,9 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        mCarHvacManager = ((KitchenSinkActivity)getActivity()).getHvacManager();
+
         super.onCreate(savedInstanceState);
-        try {
-            mCarHvacManager.registerCallback(mHvacCallback);
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Car is not connected!");
-        }
+
     }
 
     @Override
@@ -188,77 +187,85 @@
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
-        View v = inflater.inflate(R.layout.hvac_test, container, false);
+        mHvacView = inflater.inflate(R.layout.hvac_test, container, false);
+        final Runnable r = () -> {
+            mCarHvacManager = ((KitchenSinkActivity) getActivity()).getHvacManager();
+            try {
+                mCarHvacManager.registerCallback(mHvacCallback);
+            } catch (CarNotConnectedException e) {
+                Log.e(TAG, "Car is not connected!");
+            }
+            try {
+                mCarPropertyConfigs = mCarHvacManager.getPropertyList();
+            } catch (CarNotConnectedException e) {
+                Log.e(TAG, "Failed to get list of properties", e);
+                mCarPropertyConfigs = new ArrayList<>();
+            }
+            for (CarPropertyConfig prop : mCarPropertyConfigs) {
+                int propId = prop.getPropertyId();
 
-        List<CarPropertyConfig> props;
-        try {
-            props = mCarHvacManager.getPropertyList();
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Failed to get list of properties", e);
-            props = new ArrayList<>();
-        }
+                if (DBG) {
+                    Log.d(TAG, prop.toString());
+                }
 
-        for(CarPropertyConfig prop : props) {
-            int propId = prop.getPropertyId();
-
-            if(DBG) {
-                Log.d(TAG, prop.toString());
+                switch(propId) {
+                    case CarHvacManager.ID_OUTSIDE_AIR_TEMP:
+                        configureOutsideTemp(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_DUAL_ZONE_ON:
+                        configureDualOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_AC_ON:
+                        configureAcOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_FAN_DIRECTION:
+                        configureFanPosition(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT:
+                        configureFanSpeed(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_TEMP_SETPOINT:
+                        configureTempSetpoint(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON:
+                        configureAutoModeOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON:
+                        configureRecircOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_MAX_AC_ON:
+                        configureMaxAcOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_ZONED_MAX_DEFROST_ON:
+                        configureMaxDefrostOn(mHvacView, prop);
+                        break;
+                    case CarHvacManager.ID_WINDOW_DEFROSTER_ON:
+                        configureDefrosterOn(mHvacView, prop);
+                        break;
+                    default:
+                        Log.w(TAG, "propertyId " + propId + " is not handled");
+                        break;
+                }
             }
 
-            switch(propId) {
-                case CarHvacManager.ID_OUTSIDE_AIR_TEMP:
-                    configureOutsideTemp(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_DUAL_ZONE_ON:
-                    configureDualOn(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_AC_ON:
-                    configureAcOn(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_FAN_DIRECTION:
-                    configureFanPosition(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT:
-                    configureFanSpeed(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_TEMP_SETPOINT:
-                    configureTempSetpoint(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON:
-                    configureAutoModeOn(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON:
-                    configureRecircOn(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_MAX_AC_ON:
-                    configureMaxAcOn(v, prop);
-                    break;
-                case CarHvacManager.ID_ZONED_MAX_DEFROST_ON:
-                    configureMaxDefrostOn(v, prop);
-                    break;
-                case CarHvacManager.ID_WINDOW_DEFROSTER_ON:
-                    configureDefrosterOn(v, prop);
-                    break;
-                default:
-                    Log.w(TAG, "propertyId " + propId + " is not handled");
-                    break;
-            }
-        }
+            mTvFanSpeed = (TextView) mHvacView.findViewById(R.id.tvFanSpeed);
+            mTvFanSpeed.setText(String.valueOf(mCurFanSpeed));
+            mTvDTemp = (TextView) mHvacView.findViewById(R.id.tvDTemp);
+            mTvDTemp.setText(String.valueOf(mCurDTemp));
+            mTvPTemp = (TextView) mHvacView.findViewById(R.id.tvPTemp);
+            mTvPTemp.setText(String.valueOf(mCurPTemp));
+            mTvOutsideTemp = (TextView) mHvacView.findViewById(R.id.tvOutsideTemp);
+            mTvOutsideTemp.setText("N/A");
+        };
 
-        mTvFanSpeed = (TextView) v.findViewById(R.id.tvFanSpeed);
-        mTvFanSpeed.setText(String.valueOf(mCurFanSpeed));
-        mTvDTemp = (TextView) v.findViewById(R.id.tvDTemp);
-        mTvDTemp.setText(String.valueOf(mCurDTemp));
-        mTvPTemp = (TextView) v.findViewById(R.id.tvPTemp);
-        mTvPTemp.setText(String.valueOf(mCurPTemp));
-        mTvOutsideTemp = (TextView) v.findViewById(R.id.tvOutsideTemp);
-        mTvOutsideTemp.setText("N/A");
+        ((KitchenSinkActivity) getActivity()).requestRefreshManager(r,
+                new Handler(getContext().getMainLooper()));
 
         if(DBG) {
             Log.d(TAG, "Starting HvacTestFragment");
         }
 
-        return v;
+        return mHvacView;
     }
 
     private void configureOutsideTemp(View v, CarPropertyConfig prop) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
index fed1fbd..9a6c2b9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/power/PowerTestFragment.java
@@ -20,6 +20,7 @@
 import android.car.hardware.power.CarPowerManager;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.support.v4.app.Fragment;
@@ -58,16 +59,20 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        mCarPowerManager = ((KitchenSinkActivity)getActivity()).getPowerManager();
-        mExecutor = new ThreadPerTaskExecutor();
+        final Runnable r = () -> {
+            mCarPowerManager = ((KitchenSinkActivity) getActivity()).getPowerManager();
+            mExecutor = new ThreadPerTaskExecutor();
+            try {
+                mCarPowerManager.setListener(mPowerListener, mExecutor);
+            } catch (CarNotConnectedException e) {
+                Log.e(TAG, "Car is not connected!");
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "CarPowerManager listener was not cleared");
+            }
+        };
+        ((KitchenSinkActivity) getActivity()).requestRefreshManager(r,
+                new Handler(getContext().getMainLooper()));
         super.onCreate(savedInstanceState);
-        try {
-            mCarPowerManager.setListener(mPowerListener, mExecutor);
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Car is not connected!");
-        } catch (IllegalStateException e) {
-            Log.e(TAG, "CarPowerManager listener was not cleared");
-        }
     }
 
     @Override
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
index fc6621a..ff1c402 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
@@ -26,6 +26,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v4.app.Fragment;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -85,20 +86,23 @@
         mPropertyId = view.findViewById(R.id.sPropertyId);
         mScrollView = view.findViewById(R.id.svEventLog);
         mSetValue = view.findViewById(R.id.etSetPropertyValue);
+        mActivity = (KitchenSinkActivity) getActivity();
 
-        populateConfigList();
-        mListView.setAdapter(new PropertyListAdapter(mPropInfo, mMgr, mEventLog, mScrollView,
-                                                     mActivity));
+        final Runnable r = () -> {
+            mMgr = mActivity.getPropertyManager();
+            populateConfigList();
+            mListView.setAdapter(new PropertyListAdapter(mPropInfo, mMgr, mEventLog, mScrollView,
+                    mActivity));
 
-        // Configure dropdown menu for propertyId spinner
-        ArrayAdapter<PropertyInfo> adapter =
-                new ArrayAdapter<PropertyInfo>(mActivity, android.R.layout.simple_spinner_item,
-                                               mPropInfo);
-        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mPropertyId.setAdapter(adapter);
-        mPropertyId.setOnItemSelectedListener(this);
-
-
+            // Configure dropdown menu for propertyId spinner
+            ArrayAdapter<PropertyInfo> adapter =
+                    new ArrayAdapter<PropertyInfo>(mActivity, android.R.layout.simple_spinner_item,
+                            mPropInfo);
+            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            mPropertyId.setAdapter(adapter);
+            mPropertyId.setOnItemSelectedListener(this);
+        };
+        mActivity.requestRefreshManager(r, new Handler(getContext().getMainLooper()));
 
         // Configure listeners for buttons
         Button b = view.findViewById(R.id.bGetProperty);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
index a6cc5ac..1440ff0 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
@@ -99,17 +99,19 @@
 
         View view = inflater.inflate(R.layout.sensors, container, false);
         mActivity = (KitchenSinkActivity) getHost();
-
         mSensorInfo = (TextView) view.findViewById(R.id.sensor_info);
         mNaString = getContext().getString(R.string.sensor_na);
-
         return view;
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        initPermissions();
+        final Runnable r = () -> {
+            initPermissions();
+        };
+        ((KitchenSinkActivity) getActivity()).requestRefreshManager(r,
+                new Handler(getContext().getMainLooper()));
     }
 
     @Override