Merge "Update default guest restrictions" into qt-dev
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
index 4ca54a7..5806aa4 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
@@ -826,6 +826,9 @@
 
             public SpeedRange(@FloatRange(from = 0.0) float minSpeed,
                     @FloatRange(from = 0.0) float maxSpeed) {
+                if (Float.compare(minSpeed, 0) < 0 || Float.compare(maxSpeed, 0) < 0) {
+                    throw new IllegalArgumentException("Speed cannot be negative.");
+                }
                 if (minSpeed == MAX_SPEED) {
                     throw new IllegalArgumentException("Min speed cannot be MAX_SPEED.");
                 }
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index 4848e99..6ba3f97 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -30,6 +30,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -78,10 +80,10 @@
     private final Context mContext;
     private final ICarUxRestrictionsManager mUxRService;
     private final EventCallbackHandler mEventCallbackHandler;
+    @GuardedBy("this")
     private OnUxRestrictionsChangedListener mUxRListener;
     private CarUxRestrictionsChangeListenerToService mListenerToService;
 
-
     /** @hide */
     public CarUxRestrictionsManager(IBinder service, Context context, Handler handler) {
         mContext = context;
@@ -91,9 +93,11 @@
 
     /** @hide */
     @Override
-    public synchronized void onCarDisconnected() {
+    public void onCarDisconnected() {
         mListenerToService = null;
-        mUxRListener = null;
+        synchronized (this) {
+            mUxRListener = null;
+        }
     }
 
     /**
@@ -118,21 +122,18 @@
      *
      * @param listener {@link OnUxRestrictionsChangedListener}
      */
-    public synchronized void registerListener(@NonNull OnUxRestrictionsChangedListener listener) {
-        if (listener == null) {
-            if (VDBG) {
-                Log.v(TAG, "registerListener(): null listener");
+    public void registerListener(@NonNull OnUxRestrictionsChangedListener listener) {
+        synchronized (this) {
+            // Check if the listener has been already registered.
+            if (mUxRListener != null) {
+                if (DBG) {
+                    Log.d(TAG, "Listener already registered listener");
+                }
+                return;
             }
-            throw new IllegalArgumentException("Listener is null");
+            mUxRListener = listener;
         }
-        // Check if the listener has been already registered.
-        if (mUxRListener != null) {
-            if (DBG) {
-                Log.d(TAG, "Listener already registered listener");
-            }
-            return;
-        }
-        mUxRListener = listener;
+
         try {
             if (mListenerToService == null) {
                 mListenerToService = new CarUxRestrictionsChangeListenerToService(this);
@@ -147,16 +148,18 @@
     /**
      * Unregister the registered {@link OnUxRestrictionsChangedListener}
      */
-    public synchronized void unregisterListener() {
-        if (mUxRListener == null) {
-            if (DBG) {
-                Log.d(TAG, "Listener was not previously registered");
+    public void unregisterListener() {
+        synchronized (this) {
+            if (mUxRListener == null) {
+                if (DBG) {
+                    Log.d(TAG, "Listener was not previously registered");
+                }
+                return;
             }
-            return;
+            mUxRListener = null;
         }
         try {
             mUxRService.unregisterUxRestrictionsChangeListener(mListenerToService);
-            mUxRListener = null;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -220,7 +223,7 @@
      * @hide
      */
     @RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
-    public synchronized boolean saveUxRestrictionsConfigurationForNextBoot(
+    public boolean saveUxRestrictionsConfigurationForNextBoot(
             CarUxRestrictionsConfiguration config) {
         try {
             return mUxRService.saveUxRestrictionsConfigurationForNextBoot(config);
@@ -240,7 +243,7 @@
      */
     @Nullable
     @RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
-    public synchronized CarUxRestrictionsConfiguration getStagedConfig() {
+    public CarUxRestrictionsConfiguration getStagedConfig() {
         try {
             return mUxRService.getStagedConfig();
         } catch (RemoteException e) {
@@ -256,7 +259,7 @@
      * @hide
      */
     @RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
-    public synchronized CarUxRestrictionsConfiguration getConfig() {
+    public CarUxRestrictionsConfiguration getConfig() {
         try {
             return mUxRService.getConfig();
         } catch (RemoteException e) {
@@ -331,7 +334,6 @@
                 mgr.dispatchUxRChangeToClient((CarUxRestrictions) msg.obj);
             }
         }
-
     }
 
     /**
@@ -344,12 +346,10 @@
         if (restrictionInfo == null) {
             return;
         }
-        OnUxRestrictionsChangedListener listener;
         synchronized (this) {
-            listener = mUxRListener;
-        }
-        if (listener != null) {
-            listener.onUxRestrictionsChanged(restrictionInfo);
+            if (mUxRListener != null) {
+                mUxRListener.onUxRestrictionsChanged(restrictionInfo);
+            }
         }
     }
 }
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index e271fd5..87c4b46 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -308,7 +308,7 @@
      */
     @Nullable
     public T getMinValue() {
-        AreaConfig<T> area = mSupportedAreas.valueAt(0);
+        AreaConfig<T> area = mSupportedAreas.get(0);
         return area == null ? null : area.getMinValue();
     }
 
@@ -318,7 +318,7 @@
      */
     @Nullable
     public T getMaxValue() {
-        AreaConfig<T> area = mSupportedAreas.valueAt(0);
+        AreaConfig<T> area = mSupportedAreas.get(0);
         return area == null ? null : area.getMaxValue();
     }
 
diff --git a/service/Android.mk b/service/Android.mk
index a9d0e0b..f16877e 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -53,6 +53,7 @@
     car-frameworks-service \
     car-systemtest \
     com.android.car.procfsinspector-client \
+    blestream-protos \
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SettingsLib \
@@ -88,6 +89,7 @@
     vehicle-hal-support-lib \
     car-systemtest \
     com.android.car.procfsinspector-client \
+    blestream-protos \
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SettingsLib \
diff --git a/service/proto/Android.bp b/service/proto/Android.bp
index 1f0a344..8d500ea 100644
--- a/service/proto/Android.bp
+++ b/service/proto/Android.bp
@@ -4,9 +4,8 @@
     proto: {
         type: "lite",
     },
-    srcs: ["src/**/*.proto"],
+    srcs: ["*.proto"],
     no_framework_libs: true,
     jarjar_rules: "jarjar-rules.txt",
     sdk_version: "28",
-    java_version: "1.8",
 }
diff --git a/service/proto/BLEHandshake.proto b/service/proto/BLEHandshake.proto
new file mode 100644
index 0000000..26f5783
--- /dev/null
+++ b/service/proto/BLEHandshake.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+
+package com.android.car.trust.BLEHandshake;
+
+option java_package = "com.android.car.trust";
+option java_outer_classname = "BLEHandshake";
+
+message VersionExchange {
+  // Required.
+  int32 minSupportedVersion = 1;
+
+  // Required.
+  int32 maxSupportedVersion = 2;
+}
\ No newline at end of file
diff --git a/service/proto/src/BLEMessage.proto b/service/proto/BLEStream.proto
similarity index 100%
rename from service/proto/src/BLEMessage.proto
rename to service/proto/BLEStream.proto
diff --git a/service/res/values/attrs.xml b/service/res/values/attrs.xml
index be20c0f..483c7e1 100644
--- a/service/res/values/attrs.xml
+++ b/service/res/values/attrs.xml
@@ -92,6 +92,14 @@
             <flag name="no_voice_transcription" value="256"/>
             <flag name="fully_restricted" value="511"/>
         </attr>
+        <!-- UX restrictions service supports returning different sets of UX restrictions for
+        the same driving state, through configurations for each "mode". -->
+        <attr name="mode">
+            <!-- Default mode. -->
+            <flag name="baseline" value="0"/>
+            <!-- Mode for passenger to interact with system. -->
+            <flag name="passenger" value="1"/>
+        </attr>
     </declare-styleable>
 
     <!-- 2. Some of UX restrictions can be parametrized. -->
diff --git a/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java b/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
index 95bcb2c..eec55c5 100644
--- a/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
+++ b/service/src/com/android/car/CarUxRestrictionsConfigurationXmlParser.java
@@ -16,17 +16,20 @@
 
 package com.android.car;
 
+import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
+
 import android.annotation.Nullable;
 import android.annotation.XmlRes;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsConfiguration;
+import android.car.drivingstate.CarUxRestrictionsConfiguration.Builder;
+import android.car.drivingstate.CarUxRestrictionsConfiguration.DrivingStateRestrictions;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -160,19 +163,12 @@
                 // 1. Get the driving state attributes: driving state and speed range
                 TypedArray a = mContext.getResources().obtainAttributes(attrs,
                         R.styleable.UxRestrictions_DrivingState);
-                int drivingState = a
-                        .getInt(R.styleable.UxRestrictions_DrivingState_state,
-                                CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
-                float minSpeed = a
-                        .getFloat(
-                                R.styleable
-                                        .UxRestrictions_DrivingState_minSpeed,
-                                INVALID_SPEED);
-                float maxSpeed = a
-                        .getFloat(
-                                R.styleable
-                                        .UxRestrictions_DrivingState_maxSpeed,
-                                INVALID_SPEED);
+                int drivingState = a.getInt(R.styleable.UxRestrictions_DrivingState_state,
+                        CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
+                float minSpeed = a.getFloat(R.styleable.UxRestrictions_DrivingState_minSpeed,
+                        INVALID_SPEED);
+                float maxSpeed = a.getFloat(R.styleable.UxRestrictions_DrivingState_maxSpeed,
+                        Builder.SpeedRange.MAX_SPEED);
                 a.recycle();
 
                 // 2. Traverse to the <Restrictions> tag
@@ -182,7 +178,42 @@
                 }
 
                 // 3. Parse the restrictions for this driving state
-                Pair<Boolean, Integer> restrictions = parseRestrictions(parser, attrs);
+                Builder.SpeedRange speedRange = parseSpeedRange(minSpeed, maxSpeed);
+                if (!parseAllRestrictions(parser, attrs, drivingState, speedRange)) {
+                    Log.e(TAG, "Could not parse restrictions for driving state:" + drivingState);
+                    return false;
+                }
+            }
+            parser.next();
+        }
+        return true;
+    }
+
+    /**
+     * Parses all <restrictions> tags nested with <drivingState> tag.
+     */
+    private boolean parseAllRestrictions(XmlResourceParser parser, AttributeSet attrs,
+            int drivingState, Builder.SpeedRange speedRange)
+            throws IOException, XmlPullParserException {
+        if (parser == null || attrs == null) {
+            Log.e(TAG, "Invalid arguments");
+            return false;
+        }
+        // The parser should be at the <Restrictions> tag at this point.
+        if (!RESTRICTIONS.equals(parser.getName())) {
+            Log.e(TAG, "Parser not at Restrictions element: " + parser.getName());
+            return false;
+        }
+        while (RESTRICTIONS.equals(parser.getName())) {
+            if (parser.getEventType() == XmlResourceParser.START_TAG) {
+                // Parse one restrictions tag.
+                DrivingStateRestrictions restrictions = parseRestrictions(parser, attrs);
+                if (restrictions == null) {
+                    Log.e(TAG, "");
+                    return false;
+                }
+                restrictions.setSpeedRange(speedRange);
+
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     Log.d(TAG, "Map " + drivingState + " : " + restrictions);
                 }
@@ -190,8 +221,8 @@
                 // Update the builder if the driving state and restrictions info are valid.
                 if (drivingState != CarDrivingStateEvent.DRIVING_STATE_UNKNOWN
                         && restrictions != null) {
-                    addToRestrictions(drivingState, minSpeed, maxSpeed, restrictions.first,
-                            restrictions.second);
+
+                    mConfigBuilder.setUxRestrictions(drivingState, restrictions);
                 }
             }
             parser.next();
@@ -204,15 +235,16 @@
      * for the enclosing driving state.
      */
     @Nullable
-    private Pair<Boolean, Integer> parseRestrictions(XmlResourceParser parser, AttributeSet attrs)
+    private DrivingStateRestrictions parseRestrictions(XmlResourceParser parser, AttributeSet attrs)
             throws IOException, XmlPullParserException {
-        int restrictions = UX_RESTRICTIONS_UNKNOWN;
-        boolean requiresOpt = true;
         if (parser == null || attrs == null) {
             Log.e(TAG, "Invalid Arguments");
             return null;
         }
 
+        int restrictions = UX_RESTRICTIONS_UNKNOWN;
+        int restrictionMode = UX_RESTRICTION_MODE_BASELINE;
+        boolean requiresOpt = true;
         while (RESTRICTIONS.equals(parser.getName())
                 && parser.getEventType() == XmlResourceParser.START_TAG) {
             TypedArray a = mContext.getResources().obtainAttributes(attrs,
@@ -222,23 +254,24 @@
                     CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
             requiresOpt = a.getBoolean(
                     R.styleable.UxRestrictions_Restrictions_requiresDistractionOptimization, true);
+            restrictionMode = a.getInt(
+                    R.styleable.UxRestrictions_Restrictions_mode, UX_RESTRICTION_MODE_BASELINE);
+
             a.recycle();
             parser.next();
         }
-        return new Pair<>(requiresOpt, restrictions);
+        return new DrivingStateRestrictions()
+                .setDistractionOptimizationRequired(requiresOpt)
+                .setRestrictions(restrictions)
+                .setMode(restrictionMode);
     }
 
-    private void addToRestrictions(int drivingState, float minSpeed, float maxSpeed,
-            boolean requiresOpt, int restrictions) {
-        CarUxRestrictionsConfiguration.Builder.SpeedRange speedRange = null;
-        if (Float.compare(minSpeed, INVALID_SPEED) != 0) {
-            if (Float.compare(maxSpeed, INVALID_SPEED) == 0) {
-                // Setting min speed but not max implies MAX_SPEED.
-                maxSpeed = CarUxRestrictionsConfiguration.Builder.SpeedRange.MAX_SPEED;
-            }
-            speedRange = new CarUxRestrictionsConfiguration.Builder.SpeedRange(minSpeed, maxSpeed);
+    @Nullable
+    private Builder.SpeedRange parseSpeedRange(float minSpeed, float maxSpeed) {
+        if (Float.compare(minSpeed, 0) < 0 || Float.compare(maxSpeed, 0) < 0) {
+            return null;
         }
-        mConfigBuilder.setUxRestrictions(drivingState, speedRange, requiresOpt, restrictions);
+        return new CarUxRestrictionsConfiguration.Builder.SpeedRange(minSpeed, maxSpeed);
     }
 
     private boolean traverseToTag(XmlResourceParser parser, String tag)
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
index 5b991a9..155970d 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUxRestrictionsConfigurationTest.java
@@ -247,7 +247,15 @@
         new Builder.SpeedRange(0f, MAX_SPEED);
     }
 
-    public void testSpeedRange_NegativeMax() {
+    public void testSpeedRange_NoNegativeMin() {
+        try {
+            new Builder.SpeedRange(-2f, 1f);
+        } catch (Exception e) {
+            // Expected exception.
+        }
+    }
+
+    public void testSpeedRange_NoNegativeMax() {
         try {
             new Builder.SpeedRange(2f, -1f);
         } catch (Exception e) {
@@ -255,6 +263,14 @@
         }
     }
 
+    public void testSpeedRange_MinCannotBeMaxSpeed() {
+        try {
+            new Builder.SpeedRange(MAX_SPEED, 1f);
+        } catch (Exception e) {
+            // Expected exception.
+        }
+    }
+
     public void testSpeedRange_MinGreaterThanMax() {
         try {
             new Builder.SpeedRange(5f, 2f);
diff --git a/tests/carservice_test/res/xml/ux_restrictions_passenger_mode.xml b/tests/carservice_test/res/xml/ux_restrictions_passenger_mode.xml
new file mode 100644
index 0000000..6a5dd07
--- /dev/null
+++ b/tests/carservice_test/res/xml/ux_restrictions_passenger_mode.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+This xml contains UX restrictions configuration for testing.
+-->
+<UxRestrictions xmlns:car="http://schemas.android.com/apk/res-auto">
+    <RestrictionMapping>
+        <DrivingState car:state="parked">
+            <Restrictions car:mode="passenger"
+                car:requiresDistractionOptimization="false" car:uxr="baseline"/>
+            <Restrictions
+              car:requiresDistractionOptimization="true" car:uxr="no_video"/>
+        </DrivingState>
+        <DrivingState car:state="idling">
+            <Restrictions car:mode="passenger"
+                car:requiresDistractionOptimization="false" car:uxr="baseline"/>
+            <Restrictions
+                car:requiresDistractionOptimization="true" car:uxr="no_video"/>
+        </DrivingState>
+        <!-- Verify parsing multiple DrivingState tags also works.-->
+        <DrivingState car:state="moving">
+            <Restrictions car:mode="passenger"
+                car:requiresDistractionOptimization="false" car:uxr="baseline"/>
+        </DrivingState>
+        <DrivingState car:state="moving">
+            <Restrictions
+                car:requiresDistractionOptimization="true" car:uxr="no_video"/>
+        </DrivingState>
+    </RestrictionMapping>
+</UxRestrictions>
diff --git a/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java b/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
index cad210e..3a0dc4a 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
+++ b/tests/carservice_test/src/com/android/car/CarUxRestrictionsConfigurationXmlParserTest.java
@@ -18,6 +18,8 @@
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_IDLING;
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_MOVING;
 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_PARKED;
+import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
+import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_PASSENGER;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -108,4 +110,44 @@
         assertTrue(fast.isRequiresDistractionOptimization());
         assertEquals(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO, fast.getActiveRestrictions());
     }
+
+    @Test
+    public void testParsingPassengerState() throws IOException, XmlPullParserException {
+        CarUxRestrictionsConfiguration config = CarUxRestrictionsConfigurationXmlParser.parse(
+                getContext(), R.xml.ux_restrictions_passenger_mode);
+
+        CarUxRestrictions moving = config.getUxRestrictions(
+                DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_PASSENGER);
+        assertFalse(moving.isRequiresDistractionOptimization());
+
+        CarUxRestrictions idling = config.getUxRestrictions(
+                DRIVING_STATE_IDLING, 0f, UX_RESTRICTION_MODE_PASSENGER);
+        assertFalse(idling.isRequiresDistractionOptimization());
+
+        CarUxRestrictions parked = config.getUxRestrictions(
+                DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_PASSENGER);
+        assertFalse(parked.isRequiresDistractionOptimization());
+    }
+
+    @Test
+    public void testParsingPassengerMode_ValuesInBaselineAreNotAffected()
+            throws IOException, XmlPullParserException {
+        CarUxRestrictionsConfiguration config = CarUxRestrictionsConfigurationXmlParser.parse(
+                getContext(), R.xml.ux_restrictions_passenger_mode);
+
+        CarUxRestrictions moving = config.getUxRestrictions(
+                DRIVING_STATE_MOVING, 1f, UX_RESTRICTION_MODE_BASELINE);
+        assertTrue(moving.isRequiresDistractionOptimization());
+        assertEquals(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO, moving.getActiveRestrictions());
+
+        CarUxRestrictions idling = config.getUxRestrictions(
+                DRIVING_STATE_IDLING, 0f, UX_RESTRICTION_MODE_BASELINE);
+        assertTrue(idling.isRequiresDistractionOptimization());
+        assertEquals(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO, idling.getActiveRestrictions());
+
+        CarUxRestrictions parked = config.getUxRestrictions(
+                DRIVING_STATE_PARKED, 0f, UX_RESTRICTION_MODE_BASELINE);
+        assertTrue(parked.isRequiresDistractionOptimization());
+        assertEquals(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO, parked.getActiveRestrictions());
+    }
 }