Merge Android Pie into master

Bug: 112104996
Change-Id: Ie760d204144a01ad1ad2495c2b9edad71d3ccd37
diff --git a/Android.mk b/Android.mk
index b33eecc..04f8004 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,7 +17,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-CAR_CURRENT_SDK_VERSION := 23
 CAR_API_CHECK := $(LOCAL_PATH)/apicheck.mk
 api_check_current_msg_file := $(LOCAL_PATH)/apicheck_msg_current.txt
 api_check_last_msg_file := $(LOCAL_PATH)/apicheck_msg_last.txt
@@ -28,7 +27,6 @@
 include $(call all-makefiles-under,$(LOCAL_PATH))
 
 # Clear out variables
-CAR_CURRENT_SDK_VERSION :=
 CAR_API_CHECK :=
 api_check_current_msg_file :=
 api_check_last_msg_file :=
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d828faa..67d5bef 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -57,6 +57,9 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.car_intermediates/src/android/car/hardware/ICarDiagnostic*.java)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.car7_intermediates/src/android/car/hardware/ICarDiagnostic*.java)
 
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.car7_intermediates/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.car_intermediates/)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..38f9800
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,7 @@
+[Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
+
+[Builtin Hooks]
+commit_msg_changeid_field = true
+commit_msg_test_field = true
diff --git a/TrustAgent/Android.mk b/TrustAgent/Android.mk
index 4308a1d..5d9ff98 100644
--- a/TrustAgent/Android.mk
+++ b/TrustAgent/Android.mk
@@ -18,7 +18,9 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LIBRARIES += android.car
 LOCAL_USE_AAPT2 := true
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -36,8 +38,6 @@
 
 LOCAL_DEX_PREOPT := false
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
-
 include $(BUILD_PACKAGE)
 
 endif
diff --git a/TrustAgent/AndroidManifest.xml b/TrustAgent/AndroidManifest.xml
index 1f5e6e6..69e501c 100644
--- a/TrustAgent/AndroidManifest.xml
+++ b/TrustAgent/AndroidManifest.xml
@@ -19,7 +19,7 @@
     <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23"/>
 
     <!-- Need Bluetooth LE -->
-    <uses-feature android:name="android.hardware.bluetooth_le"  android:required="true" />
+    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
 
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -28,6 +28,8 @@
 
     <!-- Needed to unlock user -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <!-- TODO(b/77717079) INTERACT_ACROSS_USERS_FULL should have granted INTERACT_ACROSS_USERS -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
@@ -36,10 +38,10 @@
     <application android:label="@string/app_name">
         <service
                 android:name=".CarBleTrustAgent"
-                android:label="@string/app_name"
                 android:permission="android.permission.BIND_TRUST_AGENT"
                 android:directBootAware="true"
-                android:exported="true">
+                android:exported="true"
+                android:singleUser="true">
             <intent-filter>
                 <action android:name="android.service.trust.TrustAgentService" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -51,10 +53,12 @@
                        android:resource="@xml/car_sample_trust_agent"/>
         </service>
 
-        <!-- CarUnlockService needs to be direct boot aware, since the trust agent
+        <!-- CarTrustAgentBleService needs to be direct boot aware, since the trust agent
              binds to it during direct boot.-->
-        <service android:name=".CarUnlockService"
-                 android:directBootAware="true">
+        <service
+                android:name=".CarTrustAgentBleService"
+                android:directBootAware="true"
+                android:singleUser="true">
             <!-- Warning: the meta data must be included if the service is direct boot aware.
                  If not included, the device will crash before boot completes. Rendering the device
                  unusable. -->
@@ -62,10 +66,8 @@
                        android:resource="@xml/car_sample_trust_agent"/>
         </service>
 
-        <service android:name=".CarEnrolmentService"/>
-
         <activity
-                android:name=".MainActivity"
+                android:name=".CarEnrolmentActivity"
                 android:label="@string/app_name"
                 android:exported="true"
                 android:launchMode="singleInstance">
@@ -75,13 +77,5 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".CarEnrolmentActivity"
-            android:exported="false" />
-
-        <activity android:name=".PhoneEnrolmentActivity"
-            android:exported="false" />
-
-        <activity android:name=".PhoneUnlockActivity"
-            android:exported="false" />
     </application>
 </manifest>
diff --git a/TrustAgent/res/layout/car_client.xml b/TrustAgent/res/layout/car_enrolment_activity.xml
similarity index 100%
rename from TrustAgent/res/layout/car_client.xml
rename to TrustAgent/res/layout/car_enrolment_activity.xml
diff --git a/TrustAgent/res/layout/main_app.xml b/TrustAgent/res/layout/main_app.xml
deleted file mode 100644
index 5153ca8..0000000
--- a/TrustAgent/res/layout/main_app.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:weightSum="1">
-
-    <Button android:id="@+id/car_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="0.20"
-        android:text="@string/car"/>
-    <Button android:id="@+id/phone_enrolment_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="0.20"
-        android:text="@string/enrollment_client"/>
-    <Button android:id="@+id/phone_unlock_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="0.20"
-        android:text="@string/unlock_client"/>
-</LinearLayout>
diff --git a/TrustAgent/res/layout/phone_client.xml b/TrustAgent/res/layout/phone_client.xml
deleted file mode 100644
index 41ead63..0000000
--- a/TrustAgent/res/layout/phone_client.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:weightSum="1">
-    <ScrollView
-        android:id="@+id/scroll"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:scrollbars="vertical"
-        android:layout_weight="0.60"
-        android:fillViewport="true">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:id="@+id/output"/>
-    </ScrollView>
-    <Button
-        android:id="@+id/ble_scan_btn"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/start_scanning"
-        android:layout_weight="0.20"/>
-    <Button
-        android:id="@+id/action_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="0.20"/>
-</LinearLayout>
diff --git a/TrustAgent/res/values/strings.xml b/TrustAgent/res/values/strings.xml
index d23a4b3..d077262 100644
--- a/TrustAgent/res/values/strings.xml
+++ b/TrustAgent/res/values/strings.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <string name="app_name">CarBleTrustAgent</string>
+    <string name="app_name">CarTrustAgentService</string>
     <string name="trust_granted_explanation">Unlock via escrow token, now granting trust</string>
 
     <!-- service/characteristics uuid for unlocking a device -->
@@ -36,8 +36,4 @@
     <string name="start_advertising">Start Advertising</string>
     <string name="revoke_trust">Revoke Trust</string>
 
-    <string name="car">Car</string>
-    <string name="enrollment_client">Phone Enrolment Client</string>
-    <string name="unlock_client">Phone Unlock Client</string>
-    <string name="start_scanning">Start Scanning</string>
 </resources>
diff --git a/TrustAgent/src/com/android/car/trust/CarBleTrustAgent.java b/TrustAgent/src/com/android/car/trust/CarBleTrustAgent.java
index 997f028..227ea89 100644
--- a/TrustAgent/src/com/android/car/trust/CarBleTrustAgent.java
+++ b/TrustAgent/src/com/android/car/trust/CarBleTrustAgent.java
@@ -20,25 +20,25 @@
 import android.bluetooth.BluetoothGattServer;
 import android.bluetooth.BluetoothGattServerCallback;
 import android.bluetooth.BluetoothManager;
-import android.content.BroadcastReceiver;
+import android.car.trust.ICarTrustAgentBleService;
+import android.car.trust.ICarTrustAgentTokenRequestDelegate;
+import android.car.trust.ICarTrustAgentUnlockCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.trust.TrustAgentService;
-import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
-import com.android.car.trust.comms.SimpleBleServer;
 
 import java.util.concurrent.TimeUnit;
 
 /**
- * A sample trust agent that demonstrates how to use the escrow token unlock APIs. </p>
+ * A BluetoothLE (BLE) based {@link TrustAgentService} that uses the escrow token unlock APIs. </p>
  *
  * This trust agent runs during direct boot and binds to a BLE service that listens for remote
  * devices to trigger an unlock. <p/>
@@ -46,86 +46,108 @@
  * The permissions for this agent must be enabled as priv-app permissions for it to start.
  */
 public class CarBleTrustAgent extends TrustAgentService {
-    public static final String ACTION_REVOKE_TRUST = "revoke-trust-action";
-    public static final String ACTION_ADD_TOKEN = "add-token-action";
-    public static final String ACTION_IS_TOKEN_ACTIVE = "is-token-active-action";
-    public static final String ACTION_REMOVE_TOKEN = "remove-token-action";
-    public static final String ACTION_UNLOCK_DEVICE = "unlock-device-action";
 
-    public static final String ACTION_TOKEN_STATUS_RESULT = "token-status-result-action";
-    public static final String ACTION_ADD_TOKEN_RESULT = "add-token-result-action";
-
-    public static final String INTENT_EXTRA_ESCROW_TOKEN = "extra-escrow-token";
-    public static final String INTENT_EXTRA_TOKEN_HANDLE = "extra-token-handle";
-    public static final String INTENT_EXTRA_TOKEN_STATUS = "extra-token-status";
-
-
-    private static final String TAG = "CarBleTrustAgent";
+    private static final String TAG = CarBleTrustAgent.class.getSimpleName();
 
     private static final long TRUST_DURATION_MS = TimeUnit.MINUTES.toMicros(5);
     private static final long BLE_RETRY_MS = TimeUnit.SECONDS.toMillis(1);
 
-    private CarUnlockService mCarUnlockService;
-    private LocalBroadcastManager mLocalBroadcastManager;
+    private Handler mHandler;
+    private BluetoothManager mBluetoothManager;
+    private ICarTrustAgentBleService mCarTrustAgentBleService;
+    private boolean mCarTrustAgentBleServiceBound;
 
-    private boolean mBleServiceBound;
-
-    // We cannot directly bind to TrustAgentService since the onBind method is final.
-    // As a result, we communicate with the various UI components using a LocalBroadcastManager.
-    private final BroadcastReceiver mTrustEventReceiver = new BroadcastReceiver() {
+    private final ICarTrustAgentUnlockCallback mUnlockCallback =
+            new ICarTrustAgentUnlockCallback.Stub() {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Received broadcast: " + action);
+        public void onUnlockDataReceived(byte[] token, long handle) {
+            UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
+            // TODO(b/77854782): get the actual user to unlock by token
+            UserHandle userHandle = getForegroundUserHandle();
+
+            Log.d(TAG, "About to unlock user. Handle: " + handle
+                    + " Time: " + System.currentTimeMillis());
+            unlockUserWithToken(handle, token, userHandle);
+
+            Log.d(TAG, "Attempted to unlock user, is user unlocked: "
+                    + um.isUserUnlocked(userHandle)
+                    + " Time: " + System.currentTimeMillis());
+            setManagingTrust(true);
+
+            if (um.isUserUnlocked(userHandle)) {
+                Log.d(TAG, getString(R.string.trust_granted_explanation));
+                grantTrust("Granting trust from escrow token",
+                        TRUST_DURATION_MS, FLAG_GRANT_TRUST_DISMISS_KEYGUARD);
             }
-            if (ACTION_REVOKE_TRUST.equals(action)) {
-                revokeTrust();
-            } else if (ACTION_ADD_TOKEN.equals(action)) {
-                byte[] token = intent.getByteArrayExtra(INTENT_EXTRA_ESCROW_TOKEN);
-                addEscrowToken(token, getCurrentUserHandle());
-            } else if (ACTION_IS_TOKEN_ACTIVE.equals(action)) {
-                long handle = intent.getLongExtra(INTENT_EXTRA_TOKEN_HANDLE, -1);
-                isEscrowTokenActive(handle, getCurrentUserHandle());
-            } else if (ACTION_REMOVE_TOKEN.equals(action)) {
-                long handle = intent.getLongExtra(INTENT_EXTRA_TOKEN_HANDLE, -1);
-                removeEscrowToken(handle, getCurrentUserHandle());
+        }
+    };
+
+    private final ICarTrustAgentTokenRequestDelegate mTokenRequestDelegate =
+            new ICarTrustAgentTokenRequestDelegate.Stub() {
+        @Override
+        public void revokeTrust() {
+            CarBleTrustAgent.this.revokeTrust();
+        }
+
+        @Override
+        public void addEscrowToken(byte[] token, int uid) {
+            CarBleTrustAgent.this.addEscrowToken(token, UserHandle.of(uid));
+        }
+
+        @Override
+        public void removeEscrowToken(long handle, int uid) {
+            CarBleTrustAgent.this.removeEscrowToken(handle, UserHandle.of(uid));
+        }
+
+        @Override
+        public void isEscrowTokenActive(long handle, int uid) {
+            CarBleTrustAgent.this.isEscrowTokenActive(handle, UserHandle.of(uid));
+        }
+    };
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.d(TAG, "CarTrustAgentBleService connected");
+            mCarTrustAgentBleServiceBound = true;
+            mCarTrustAgentBleService = ICarTrustAgentBleService.Stub.asInterface(service);
+            try {
+                mCarTrustAgentBleService.registerUnlockCallback(mUnlockCallback);
+                mCarTrustAgentBleService.setTokenRequestDelegate(mTokenRequestDelegate);
+                maybeStartBleUnlockService();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error registerUnlockCallback", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (mCarTrustAgentBleService != null) {
+                try {
+                    mCarTrustAgentBleService.unregisterUnlockCallback(mUnlockCallback);
+                    mCarTrustAgentBleService.setTokenRequestDelegate(null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error unregisterUnlockCallback", e);
+                }
+                mCarTrustAgentBleService = null;
+                mCarTrustAgentBleServiceBound = false;
             }
         }
     };
 
     @Override
-    public void onTrustTimeout() {
-        super.onTrustTimeout();
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onTrustTimeout(): timeout expired");
-        }
-    }
-
-    @Override
     public void onCreate() {
         super.onCreate();
 
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Bluetooth trust agent starting up");
-        }
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_REVOKE_TRUST);
-        filter.addAction(ACTION_ADD_TOKEN);
-        filter.addAction(ACTION_IS_TOKEN_ACTIVE);
-        filter.addAction(ACTION_REMOVE_TOKEN);
-
-        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this /* context */);
-        mLocalBroadcastManager.registerReceiver(mTrustEventReceiver, filter);
+        Log.d(TAG, "Bluetooth trust agent starting up");
+        mHandler = new Handler();
+        mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
 
         // If the user is already unlocked, don't bother starting the BLE service.
         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
-        if (!um.isUserUnlocked()) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "User locked, will now bind CarUnlockService");
-            }
-            Intent intent = new Intent(this, CarUnlockService.class);
-
+        if (!um.isUserUnlocked(getForegroundUserHandle())) {
+            Log.d(TAG, "User locked, will now bind CarTrustAgentBleService");
+            Intent intent = new Intent(this, CarTrustAgentBleService.class);
             bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
         } else {
             setManagingTrust(true);
@@ -134,81 +156,48 @@
 
     @Override
     public void onDestroy() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Car Trust agent shutting down");
-        }
-        mLocalBroadcastManager.unregisterReceiver(mTrustEventReceiver);
+        Log.d(TAG, "Car Trust agent shutting down");
+        mHandler.removeCallbacks(null);
 
         // Unbind the service to avoid leaks from BLE stack.
-        if (mBleServiceBound) {
+        if (mCarTrustAgentBleServiceBound) {
             unbindService(mServiceConnection);
         }
         super.onDestroy();
     }
 
-    private SimpleBleServer.ConnectionListener mConnectionListener
-            = new SimpleBleServer.ConnectionListener() {
-        @Override
-        public void onServerStarted() {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "BLE server started");
+    @Override
+    public void onDeviceLocked() {
+        super.onDeviceLocked();
+        if (mCarTrustAgentBleServiceBound) {
+            try {
+                // Only one BLE advertising is allowed, ensure enrolment advertising is stopped
+                // before start unlock advertising.
+                mCarTrustAgentBleService.stopEnrolmentAdvertising();
+                mCarTrustAgentBleService.startUnlockAdvertising();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error startUnlockAdvertising", e);
             }
         }
+    }
 
-        @Override
-        public void onServerStartFailed(int errorCode) {
-            Log.w(TAG, "BLE server failed to start. Error Code: " + errorCode);
-        }
-
-        @Override
-        public void onDeviceConnected(BluetoothDevice device) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "BLE device connected. Name: " + device.getName()
-                        + " Address: " + device.getAddress());
+    @Override
+    public void onDeviceUnlocked() {
+        super.onDeviceUnlocked();
+        if (mCarTrustAgentBleServiceBound) {
+            try {
+                // Only one BLE advertising is allowed, ensure unlock advertising is stopped.
+                mCarTrustAgentBleService.stopUnlockAdvertising();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error stopUnlockAdvertising", e);
             }
         }
-    };
-
-    private CarUnlockService.UnlockServiceCallback mUnlockCallback
-            = new CarUnlockService.UnlockServiceCallback() {
-        @Override
-        public void unlockDevice(byte[] token, long handle) {
-            unlock(token, handle);
-        }
-    };
-
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
-
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "CarUnlockService connected");
-            }
-
-            mBleServiceBound = true;
-            CarUnlockService.UnlockServiceBinder binder
-                    = (CarUnlockService.UnlockServiceBinder) service;
-            mCarUnlockService = binder.getService();
-            mCarUnlockService.addUnlockServiceCallback(mUnlockCallback);
-            mCarUnlockService.addConnectionListener(mConnectionListener);
-            maybeStartBleUnlockService();
-        }
-
-        public void onServiceDisconnected(ComponentName arg0) {
-            mCarUnlockService = null;
-            mBleServiceBound = false;
-        }
-
-    };
+    }
 
     private void maybeStartBleUnlockService() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Trying to open a Ble GATT server");
-        }
-
-        BluetoothManager btManager =
-                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
-        BluetoothGattServer mGattServer
-                = btManager.openGattServer(this, new BluetoothGattServerCallback() {
+        Log.d(TAG, "Trying to open a Ble GATT server");
+        BluetoothGattServer gattServer = mBluetoothManager.openGattServer(
+                this, new BluetoothGattServerCallback() {
             @Override
             public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
                 super.onConnectionStateChange(device, status, newState);
@@ -218,87 +207,64 @@
         // The BLE stack is started up before the trust agent service, however Gatt capabilities
         // might not be ready just yet. Keep trying until a GattServer can open up before proceeding
         // to start the rest of the BLE services.
-        if (mGattServer == null) {
+        if (gattServer == null) {
             Log.e(TAG, "Gatt not available, will try again...in " + BLE_RETRY_MS + "ms");
-
-            Handler handler = new Handler();
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    maybeStartBleUnlockService();
-                }
-            }, BLE_RETRY_MS);
+            mHandler.postDelayed(this::maybeStartBleUnlockService, BLE_RETRY_MS);
         } else {
-            mGattServer.close();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "GATT available, starting up UnlockService");
+            mHandler.removeCallbacks(null);
+            gattServer.close();
+            Log.d(TAG, "GATT available, starting up UnlockService");
+            try {
+                mCarTrustAgentBleService.startUnlockAdvertising();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error startUnlockAdvertising", e);
             }
-            mCarUnlockService.start();
-        }
-    }
-
-    private void unlock(byte[] token, long handle) {
-        UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "About to unlock user. Current handle: " + handle
-                    + " Time: " + System.currentTimeMillis());
-        }
-        unlockUserWithToken(handle, token, getCurrentUserHandle());
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Attempted to unlock user, is user unlocked? " + um.isUserUnlocked()
-                    + " Time: " + System.currentTimeMillis());
-        }
-        setManagingTrust(true);
-
-        if (um.isUserUnlocked()) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, getString(R.string.trust_granted_explanation));
-            }
-            grantTrust("Granting trust from escrow token",
-                    TRUST_DURATION_MS, FLAG_GRANT_TRUST_DISMISS_KEYGUARD);
-            // Trust has been granted, disable the BLE server. This trust agent service does
-            // not need to receive additional BLE data.
-            unbindService(mServiceConnection);
         }
     }
 
     @Override
     public void onEscrowTokenRemoved(long handle, boolean successful) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onEscrowTokenRemoved. Handle: " + handle + " successful? " + successful);
+        if (mCarTrustAgentBleServiceBound) {
+            try {
+                mCarTrustAgentBleService.onEscrowTokenRemoved(handle, successful);
+                Log.v(TAG, "Callback onEscrowTokenRemoved");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onEscrowTokenRemoved", e);
+            }
         }
     }
 
     @Override
     public void onEscrowTokenStateReceived(long handle, int tokenState) {
         boolean isActive = tokenState == TOKEN_STATE_ACTIVE;
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Token handle: " + handle + " isActive: " + isActive);
+        if (mCarTrustAgentBleServiceBound) {
+            try {
+                mCarTrustAgentBleService.onEscrowTokenActiveStateChanged(handle, isActive);
+                Log.v(TAG, "Callback onEscrowTokenActiveStateChanged");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onEscrowTokenActiveStateChanged", e);
+            }
         }
-
-        Intent intent = new Intent();
-        intent.setAction(ACTION_TOKEN_STATUS_RESULT);
-        intent.putExtra(INTENT_EXTRA_TOKEN_STATUS, isActive);
-
-        mLocalBroadcastManager.sendBroadcast(intent);
     }
 
     @Override
     public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onEscrowTokenAdded, handle: " + handle);
+        if (mCarTrustAgentBleServiceBound) {
+            try {
+                mCarTrustAgentBleService.onEscrowTokenAdded(token, handle, user.getIdentifier());
+                Log.v(TAG, "Callback onEscrowTokenAdded");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onEscrowTokenAdded", e);
+            }
         }
-
-        Intent intent = new Intent();
-        intent.setAction(ACTION_ADD_TOKEN_RESULT);
-        intent.putExtra(INTENT_EXTRA_TOKEN_HANDLE, handle);
-
-        mLocalBroadcastManager.sendBroadcast(intent);
     }
 
-    private UserHandle getCurrentUserHandle() {
+    /**
+     * TODO(b/77854782): return the {@link UserHandle} of foreground user.
+     * CarBleTrustAgent itself runs as user-0
+     */
+    private UserHandle getForegroundUserHandle() {
+        Log.d(TAG, "getForegroundUserHandle for " + UserHandle.myUserId());
         return UserHandle.of(UserHandle.myUserId());
     }
 }
diff --git a/TrustAgent/src/com/android/car/trust/CarEnrolmentActivity.java b/TrustAgent/src/com/android/car/trust/CarEnrolmentActivity.java
index 89e68fe..d7160e3 100644
--- a/TrustAgent/src/com/android/car/trust/CarEnrolmentActivity.java
+++ b/TrustAgent/src/com/android/car/trust/CarEnrolmentActivity.java
@@ -15,232 +15,226 @@
  */
 package com.android.car.trust;
 
+import android.Manifest;
 import android.app.Activity;
 import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentBleService;
+import android.car.trust.ICarTrustAgentEnrolmentCallback;
+import android.car.trust.ICarTrustAgentTokenResponseCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.preference.PreferenceManager;
-import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
-import android.view.View;
-import android.widget.Button;
 import android.widget.TextView;
-import com.android.car.trust.CarEnrolmentService.EnrolmentCallback;
-import com.android.car.trust.comms.SimpleBleServer.ConnectionListener;
-
-import static com.android.car.trust.CarBleTrustAgent.ACTION_ADD_TOKEN_RESULT;
-import static com.android.car.trust.CarBleTrustAgent.ACTION_TOKEN_STATUS_RESULT;
-import static com.android.car.trust.CarBleTrustAgent.INTENT_EXTRA_TOKEN_HANDLE;
-import static com.android.car.trust.CarBleTrustAgent.INTENT_EXTRA_TOKEN_STATUS;
 
 /**
- * Setup activity that binds {@link CarEnrolmentService} and starts the enrolment process.
+ * Setup activity that binds {@link CarTrustAgentBleService} and starts the enrolment process.
  */
 public class CarEnrolmentActivity extends Activity {
-    private static String TAG = "CarEnrolment";
-    private static String SP_HANDLE_KEY = "sp-test";
 
-    private TextView mOutputText;
-    private TextView mStartButton;
+    private static final String TAG = CarEnrolmentActivity.class.getSimpleName();
 
-    private long mHandle;
+    private static final String SP_HANDLE_KEY = "sp-test";
+    private static final int FINE_LOCATION_REQUEST_CODE = 42;
 
-    private CarEnrolmentService mEnrolmentService;
-
-    private BluetoothDevice mDevice;
-
-    private boolean mServiceBound;
-
-    private LocalBroadcastManager mLocalBroadcastManager;
-
-    private SharedPreferences mPrefs;
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    private final ICarTrustAgentTokenResponseCallback mCarTrustAgentTokenResponseCallback =
+            new ICarTrustAgentTokenResponseCallback.Stub() {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            intent.getPackage();
+        public void onEscrowTokenAdded(byte[] token, long handle, int uid) {
+            runOnUiThread(() -> {
+                mPrefs.edit().putLong(SP_HANDLE_KEY, handle).apply();
+                Log.d(TAG, "stored new handle");
+            });
 
-            String action = intent.getAction();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Received broadcast: " + action);
+            if (mBluetoothDevice == null) {
+                Log.e(TAG, "No active bluetooth found to add escrow token");
+                return;
             }
 
-            if (ACTION_TOKEN_STATUS_RESULT.equals(action)) {
-                boolean tokenActive = intent.getBooleanExtra(INTENT_EXTRA_TOKEN_STATUS, false);
-                appendOutputText("Is token active? " + tokenActive + " handle: " + mHandle);
-            } else if (ACTION_ADD_TOKEN_RESULT.equals(action)) {
-                final long handle = intent.getLongExtra(INTENT_EXTRA_TOKEN_HANDLE, -1);
+            try {
+                // Notify the enrolment client that escrow token has been added
+                mCarTrustAgentBleService.sendEnrolmentHandle(mBluetoothDevice, handle);
+                appendOutputText("Escrow Token Added. Handle: " + handle);
+                appendOutputText("Lock and unlock the device to activate token");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sendEnrolmentHandle", e);
+            }
+        }
 
-                runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mPrefs.edit().putLong(SP_HANDLE_KEY, handle).apply();
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
-                            Log.d(TAG, "stored new handle");
-                        }
-                    }
-                });
+        @Override
+        public void onEscrowTokenRemoved(long handle, boolean successful) {
+            appendOutputText("Escrow token Removed. Handle: " + handle);
+        }
 
-                mEnrolmentService.sendHandle(handle, mDevice);
-                appendOutputText("Escrow Token Added. Handle: " + handle
-                        + "\nLock and unlock the device to activate token");
+        @Override
+        public void onEscrowTokenActiveStateChanged(long handle, boolean active) {
+            appendOutputText("Is token active? " + active + " handle: " + handle);
+        }
+    };
+
+    private final ICarTrustAgentBleCallback mBleConnectionCallback =
+            new ICarTrustAgentBleCallback.Stub() {
+        @Override
+        public void onBleServerStartSuccess() {
+            appendOutputText("Server started");
+        }
+
+        @Override
+        public void onBleServerStartFailure(int errorCode) {
+            appendOutputText("Server failed to start, error code: " + errorCode);
+        }
+
+        @Override
+        public void onBleDeviceConnected(BluetoothDevice device) {
+            mBluetoothDevice = device;
+            appendOutputText("Device connected: " + device.getName()
+                    + " address: " + device.getAddress());
+        }
+
+        @Override
+        public void onBleDeviceDisconnected(BluetoothDevice device) {
+            mBluetoothDevice = null;
+            appendOutputText("Device disconnected: " + device.getName()
+                    + " address: " + device.getAddress());
+        }
+    };
+
+    private final ICarTrustAgentEnrolmentCallback mEnrolmentCallback =
+            new ICarTrustAgentEnrolmentCallback.Stub() {
+        @Override
+        public void onEnrolmentDataReceived(byte[] token) {
+            appendOutputText("Enrolment data received ");
+            try {
+                addEscrowToken(token);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error addEscrowToken", e);
             }
         }
     };
 
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mCarTrustAgentBleServiceBound = true;
+            mCarTrustAgentBleService = ICarTrustAgentBleService.Stub.asInterface(service);
+            try {
+                mCarTrustAgentBleService.registerBleCallback(mBleConnectionCallback);
+                mCarTrustAgentBleService.registerEnrolmentCallback(mEnrolmentCallback);
+                mCarTrustAgentBleService.setTokenResponseCallback(
+                        mCarTrustAgentTokenResponseCallback);
+                mCarTrustAgentBleService.startEnrolmentAdvertising();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error startEnrolmentAdvertising", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (mCarTrustAgentBleService != null) {
+                try {
+                    mCarTrustAgentBleService.unregisterBleCallback(mBleConnectionCallback);
+                    mCarTrustAgentBleService.unregisterEnrolmentCallback(mEnrolmentCallback);
+                    mCarTrustAgentBleService.setTokenResponseCallback(null);
+                    mCarTrustAgentBleService.stopEnrolmentAdvertising();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error unregister callbacks", e);
+                }
+                mCarTrustAgentBleService = null;
+            }
+            mCarTrustAgentBleServiceBound = false;
+        }
+    };
+
+    private TextView mOutputText;
+    private BluetoothDevice mBluetoothDevice;
+    private ICarTrustAgentBleService mCarTrustAgentBleService;
+    private boolean mCarTrustAgentBleServiceBound;
+    private SharedPreferences mPrefs;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        setContentView(R.layout.car_client);
-        mOutputText = (TextView) findViewById(R.id.textfield);
-
-        final Intent intent = new Intent(this, CarEnrolmentService.class);
-
+        setContentView(R.layout.car_enrolment_activity);
+        mOutputText = findViewById(R.id.textfield);
         mPrefs = PreferenceManager.getDefaultSharedPreferences(this /* context */);
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_TOKEN_STATUS_RESULT);
-        filter.addAction(ACTION_ADD_TOKEN_RESULT);
-
-        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this /* context */);
-        mLocalBroadcastManager.registerReceiver(mReceiver, filter);
-
-        mStartButton = (Button) findViewById(R.id.start_button);
-        mStartButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // binding the service will start it if not started.
-                bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
-            }
+        findViewById(R.id.start_button).setOnClickListener((view) -> {
+            Intent bindIntent = new Intent(this, CarTrustAgentBleService.class);
+            bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
         });
 
-        Button revokeButton = (Button) findViewById(R.id.revoke_trust_button);
-        revokeButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Intent intent = new Intent(CarBleTrustAgent.ACTION_REVOKE_TRUST);
-                intent.setPackage(getPackageName());
-                sendBroadcast(intent);
+        findViewById(R.id.revoke_trust_button).setOnClickListener((view) -> {
+            if (mCarTrustAgentBleServiceBound) {
+                try {
+                    mCarTrustAgentBleService.revokeTrust();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error revokeTrust", e);
+                }
             }
         });
     }
 
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className,
-                IBinder service) {
-            mServiceBound = true;
-            CarEnrolmentService.EnrolmentServiceBinder binder
-                    = (CarEnrolmentService.EnrolmentServiceBinder) service;
-            mEnrolmentService = binder.getService();
-            mEnrolmentService.addEnrolmentCallback(mEnrolmentCallback);
-            mEnrolmentService.addConnectionListener(mConnectionListener);
-            mEnrolmentService.start();
-        }
-
-        public void onServiceDisconnected(ComponentName arg0) {
-            mEnrolmentService = null;
-            mServiceBound = false;
-        }
-    };
-
     @Override
-    public void onResume() {
+    protected void onResume() {
         super.onResume();
 
-        if (!mPrefs.contains(SP_HANDLE_KEY)) {
-            appendOutputText("No handles found.");
-            return;
-        }
-
-        try {
-            mHandle = mPrefs.getLong(SP_HANDLE_KEY, -1);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onResume, checking handle active: " + mHandle);
+        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) !=
+                PackageManager.PERMISSION_GRANTED) {
+            requestPermissions(
+                    new String[] { android.Manifest.permission.ACCESS_FINE_LOCATION },
+                    FINE_LOCATION_REQUEST_CODE);
+        } else {
+            long tokenHandle = getTokenHandle();
+            if (tokenHandle != -1) {
+                Log.d(TAG, "onResume, checking handle active: " + tokenHandle);
+                if (mCarTrustAgentBleServiceBound) {
+                    try {
+                        // Due to the asynchronous nature of isEscrowTokenActive in
+                        // TrustAgentService, query result will be delivered via
+                        // {@link #mCarTrustAgentTokenResponseCallback}
+                        mCarTrustAgentBleService.isEscrowTokenActive(tokenHandle,
+                                UserHandle.myUserId());
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error isEscrowTokenActive", e);
+                    }
+                }
+            } else {
+                appendOutputText("No handles found");
             }
-            isTokenActive(mHandle);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error checking if token is valid");
-            appendOutputText("Error checking if token is valid");
         }
     }
 
     @Override
-    public void onDestroy() {
-        if (mServiceBound) {
+    protected void onDestroy() {
+        if (mCarTrustAgentBleServiceBound) {
             unbindService(mServiceConnection);
         }
         super.onDestroy();
     }
 
     private void appendOutputText(final String text) {
-        runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mOutputText.append("\n" + text);
-            }
-        });
+        runOnUiThread(() -> mOutputText.append("\n" + text));
     }
 
-    private ConnectionListener mConnectionListener = new ConnectionListener() {
-        @Override
-        public void onServerStarted() {
-            appendOutputText("Server started");
+    private void addEscrowToken(byte[] token) throws RemoteException {
+        if (!mCarTrustAgentBleServiceBound) {
+            Log.e(TAG, "No CarTrustAgentBleService bounded");
+            return;
         }
-
-        @Override
-        public void onServerStartFailed(int errorCode) {
-            appendOutputText("Server failed to start, error code: " + errorCode);
-        }
-
-        @Override
-        public void onDeviceConnected(BluetoothDevice device) {
-            mDevice = device;
-            appendOutputText("Device connected: " + device.getName()
-                    + " addr: " + device.getAddress());
-        }
-    };
-
-    private EnrolmentCallback mEnrolmentCallback = new EnrolmentCallback() {
-        @Override
-        public void onEnrolmentDataReceived(byte[] token) {
-            appendOutputText("Enrolment data received ");
-            addEscrowToken(token);
-        }
-    };
-
-    private void isTokenActive(long handle) throws RemoteException {
-        Intent intent = new Intent();
-        intent.setAction(CarBleTrustAgent.ACTION_IS_TOKEN_ACTIVE);
-        intent.putExtra(CarBleTrustAgent.INTENT_EXTRA_TOKEN_HANDLE, handle);
-
-        mLocalBroadcastManager.sendBroadcast(intent);
+        mCarTrustAgentBleService.addEscrowToken(token, UserHandle.myUserId());
     }
 
-    private void addEscrowToken(byte[] token) {
-        long handle;
-
-        if (mPrefs.contains(SP_HANDLE_KEY)) {
-            handle = mPrefs.getLong(SP_HANDLE_KEY, -1);
-            appendOutputText("Removing old token, handle value: " + handle);
-            Intent intent = new Intent();
-            intent.setAction(CarBleTrustAgent.ACTION_REMOVE_TOKEN);
-            intent.putExtra(CarBleTrustAgent.INTENT_EXTRA_TOKEN_HANDLE, handle);
-            mLocalBroadcastManager.sendBroadcast(intent);
-        }
-
-        Intent intent = new Intent();
-        intent.setAction(CarBleTrustAgent.ACTION_ADD_TOKEN);
-        intent.putExtra(CarBleTrustAgent.INTENT_EXTRA_ESCROW_TOKEN, token);
-
-        mLocalBroadcastManager.sendBroadcast(intent);
+    private long getTokenHandle() {
+        return mPrefs.getLong(SP_HANDLE_KEY, -1);
     }
 }
diff --git a/TrustAgent/src/com/android/car/trust/CarEnrolmentService.java b/TrustAgent/src/com/android/car/trust/CarEnrolmentService.java
deleted file mode 100644
index e6bbee2..0000000
--- a/TrustAgent/src/com/android/car/trust/CarEnrolmentService.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.util.Log;
-import com.android.car.trust.comms.SimpleBleServer;
-
-import java.util.HashSet;
-import java.util.UUID;
-
-/**
- * A service that receives escrow token enrollment requests from remote devices.
- */
-public class CarEnrolmentService extends SimpleBleServer {
-    private static final String TAG = "CarEnrolmentService";
-
-    public interface EnrolmentCallback {
-        void onEnrolmentDataReceived(byte[] token);
-    }
-
-    private BluetoothGattService mEnrolmentService;
-    private BluetoothGattCharacteristic mEnrolmentEscrowToken;
-    private BluetoothGattCharacteristic mEnrolmentTokenHandle;
-
-    private HashSet<EnrolmentCallback> mCallbacks;
-
-    private final IBinder mBinder = new EnrolmentServiceBinder();
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mCallbacks = new HashSet<>();
-        setupEnrolmentService();
-    }
-
-    public void start() {
-        ParcelUuid uuid = new ParcelUuid(
-                UUID.fromString(getString(R.string.enrollment_service_uuid)));
-        start(uuid, mEnrolmentService);
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    @Override
-    public void onCharacteristicWrite(BluetoothDevice device,
-            int requestId, BluetoothGattCharacteristic characteristic,
-            boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
-        if (characteristic.getUuid().equals(mEnrolmentEscrowToken.getUuid())) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Enrolment token received, value: " + Utils.getLong(value));
-            }
-
-            for (EnrolmentCallback callback : mCallbacks) {
-                callback.onEnrolmentDataReceived(value);
-            }
-        }
-    }
-
-    @Override
-    public void onCharacteristicRead(BluetoothDevice device,
-            int requestId, int offset, BluetoothGattCharacteristic characteristic) {
-        //Enrolment service should not have any read requests.
-    }
-
-    public void addEnrolmentCallback(EnrolmentCallback callback) {
-        mCallbacks.add(callback);
-    }
-
-    public void sendHandle(long handle, BluetoothDevice device) {
-        mEnrolmentTokenHandle.setValue(Utils.getBytes(handle));
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Sending notification for EscrowToken Handle");
-        }
-        mGattServer.notifyCharacteristicChanged(device,
-                mEnrolmentTokenHandle, false /* confirm */);
-    }
-
-    public class EnrolmentServiceBinder extends Binder {
-        public CarEnrolmentService getService() {
-            return CarEnrolmentService.this;
-        }
-    }
-
-    // Create services and characteristics for enrolling new unlocking escrow tokens
-    private void setupEnrolmentService() {
-        mEnrolmentService = new BluetoothGattService(
-                UUID.fromString(getString(R.string.enrollment_service_uuid)),
-                BluetoothGattService.SERVICE_TYPE_PRIMARY);
-
-        // Characteristic to describe the escrow token being used for unlock
-        mEnrolmentEscrowToken = new BluetoothGattCharacteristic(
-                UUID.fromString(getString(R.string.enrollment_token_uuid)),
-                BluetoothGattCharacteristic.PROPERTY_WRITE,
-                BluetoothGattCharacteristic.PERMISSION_WRITE);
-
-        // Characteristic to describe the handle being used for this escrow token
-        mEnrolmentTokenHandle = new BluetoothGattCharacteristic(
-                UUID.fromString(getString(R.string.enrollment_handle_uuid)),
-                BluetoothGattCharacteristic.PROPERTY_NOTIFY,
-                BluetoothGattCharacteristic.PERMISSION_READ);
-
-        mEnrolmentService.addCharacteristic(mEnrolmentEscrowToken);
-        mEnrolmentService.addCharacteristic(mEnrolmentTokenHandle);
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/CarTrustAgentBleService.java b/TrustAgent/src/com/android/car/trust/CarTrustAgentBleService.java
new file mode 100644
index 0000000..f8ba90f
--- /dev/null
+++ b/TrustAgent/src/com/android/car/trust/CarTrustAgentBleService.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2018 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.trust;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattService;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentBleService;
+import android.car.trust.ICarTrustAgentEnrolmentCallback;
+import android.car.trust.ICarTrustAgentTokenRequestDelegate;
+import android.car.trust.ICarTrustAgentTokenResponseCallback;
+import android.car.trust.ICarTrustAgentUnlockCallback;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Abstracts enrolment and unlock token exchange via BluetoothLE (BLE).
+ * {@link CarBleTrustAgent} and any enrolment client should bind to
+ * {@link ICarTrustAgentBleService}.
+ */
+public class CarTrustAgentBleService extends SimpleBleServer {
+
+    private static final String TAG = CarTrustAgentBleService.class.getSimpleName();
+
+    private RemoteCallbackList<ICarTrustAgentBleCallback> mBleCallbacks;
+    private RemoteCallbackList<ICarTrustAgentEnrolmentCallback> mEnrolmentCallbacks;
+    private RemoteCallbackList<ICarTrustAgentUnlockCallback> mUnlockCallbacks;
+    private ICarTrustAgentTokenRequestDelegate mTokenRequestDelegate;
+    private ICarTrustAgentTokenResponseCallback mTokenResponseCallback;
+    private CarTrustAgentBleWrapper mCarTrustBleService;
+
+    private ParcelUuid mEnrolmentUuid;
+    private BluetoothGattCharacteristic mEnrolmentEscrowToken;
+    private BluetoothGattCharacteristic mEnrolmentTokenHandle;
+    private BluetoothGattService mEnrolmentGattServer;
+
+    private ParcelUuid mUnlockUuid;
+    private BluetoothGattCharacteristic mUnlockEscrowToken;
+    private BluetoothGattCharacteristic mUnlockTokenHandle;
+    private BluetoothGattService mUnlockGattServer;
+    private byte[] mCurrentUnlockToken;
+    private Long mCurrentUnlockHandle;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mBleCallbacks = new RemoteCallbackList<>();
+        mEnrolmentCallbacks = new RemoteCallbackList<>();
+        mUnlockCallbacks = new RemoteCallbackList<>();
+        mCarTrustBleService = new CarTrustAgentBleWrapper();
+
+        setupEnrolmentBleServer();
+        setupUnlockBleServer();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mCarTrustBleService;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // keep it alive.
+        return START_STICKY;
+    }
+
+    @Override
+    public void onCharacteristicWrite(final BluetoothDevice device, int requestId,
+            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
+            responseNeeded, int offset, byte[] value) {
+        UUID uuid = characteristic.getUuid();
+        Log.d(TAG, "onCharacteristicWrite received uuid: " + uuid);
+        if (uuid.equals(mEnrolmentEscrowToken.getUuid())) {
+            final int callbackCount = mEnrolmentCallbacks.beginBroadcast();
+            for (int i = 0; i < callbackCount; i++) {
+                try {
+                    mEnrolmentCallbacks.getBroadcastItem(i).onEnrolmentDataReceived(value);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error callback onEnrolmentDataReceived", e);
+                }
+            }
+            mEnrolmentCallbacks.finishBroadcast();
+        } else if (uuid.equals(mUnlockEscrowToken.getUuid())) {
+            mCurrentUnlockToken = value;
+            maybeSendUnlockToken();
+        } else if (uuid.equals(mUnlockTokenHandle.getUuid())) {
+            mCurrentUnlockHandle = getLong(value);
+            maybeSendUnlockToken();
+        }
+    }
+
+    @Override
+    public void onCharacteristicRead(BluetoothDevice device,
+            int requestId, int offset, final BluetoothGattCharacteristic characteristic) {
+        // Ignored read requests.
+    }
+
+    @Override
+    protected void onAdvertiseStartSuccess() {
+        final int callbackCount = mBleCallbacks.beginBroadcast();
+        for (int i = 0; i < callbackCount; i++) {
+            try {
+                mBleCallbacks.getBroadcastItem(i).onBleServerStartSuccess();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onBleServerStartSuccess", e);
+            }
+        }
+        mBleCallbacks.finishBroadcast();
+    }
+
+    @Override
+    protected void onAdvertiseStartFailure(int errorCode) {
+        final int callbackCount = mBleCallbacks.beginBroadcast();
+        for (int i = 0; i < callbackCount; i++) {
+            try {
+                mBleCallbacks.getBroadcastItem(i).onBleServerStartFailure(errorCode);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onBleServerStartFailure", e);
+            }
+        }
+        mBleCallbacks.finishBroadcast();
+    }
+
+    @Override
+    protected void onAdvertiseDeviceConnected(BluetoothDevice device) {
+        final int callbackCount = mBleCallbacks.beginBroadcast();
+        for (int i = 0; i < callbackCount; i++) {
+            try {
+                mBleCallbacks.getBroadcastItem(i).onBleDeviceConnected(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onBleDeviceConnected", e);
+            }
+        }
+        mBleCallbacks.finishBroadcast();
+    }
+
+    @Override
+    protected void onAdvertiseDeviceDisconnected(BluetoothDevice device) {
+        final int callbackCount = mBleCallbacks.beginBroadcast();
+        for (int i = 0; i < callbackCount; i++) {
+            try {
+                mBleCallbacks.getBroadcastItem(i).onBleDeviceDisconnected(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onBleDeviceDisconnected", e);
+            }
+        }
+        mBleCallbacks.finishBroadcast();
+    }
+
+    private void setupEnrolmentBleServer() {
+        mEnrolmentUuid = new ParcelUuid(
+                UUID.fromString(getString(R.string.enrollment_service_uuid)));
+        mEnrolmentGattServer = new BluetoothGattService(
+                UUID.fromString(getString(R.string.enrollment_service_uuid)),
+                BluetoothGattService.SERVICE_TYPE_PRIMARY);
+
+        // Characteristic to describe the escrow token being used for unlock
+        mEnrolmentEscrowToken = new BluetoothGattCharacteristic(
+                UUID.fromString(getString(R.string.enrollment_token_uuid)),
+                BluetoothGattCharacteristic.PROPERTY_WRITE,
+                BluetoothGattCharacteristic.PERMISSION_WRITE);
+
+        // Characteristic to describe the handle being used for this escrow token
+        mEnrolmentTokenHandle = new BluetoothGattCharacteristic(
+                UUID.fromString(getString(R.string.enrollment_handle_uuid)),
+                BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+                BluetoothGattCharacteristic.PERMISSION_READ);
+
+        mEnrolmentGattServer.addCharacteristic(mEnrolmentEscrowToken);
+        mEnrolmentGattServer.addCharacteristic(mEnrolmentTokenHandle);
+    }
+
+    private void setupUnlockBleServer() {
+        mUnlockUuid = new ParcelUuid(
+                UUID.fromString(getString(R.string.unlock_service_uuid)));
+        mUnlockGattServer = new BluetoothGattService(
+                UUID.fromString(getString(R.string.unlock_service_uuid)),
+                BluetoothGattService.SERVICE_TYPE_PRIMARY);
+
+        // Characteristic to describe the escrow token being used for unlock
+        mUnlockEscrowToken = new BluetoothGattCharacteristic(
+                UUID.fromString(getString(R.string.unlock_escrow_token_uiid)),
+                BluetoothGattCharacteristic.PROPERTY_WRITE,
+                BluetoothGattCharacteristic.PERMISSION_WRITE);
+
+        // Characteristic to describe the handle being used for this escrow token
+        mUnlockTokenHandle = new BluetoothGattCharacteristic(
+                UUID.fromString(getString(R.string.unlock_handle_uiid)),
+                BluetoothGattCharacteristic.PROPERTY_WRITE,
+                BluetoothGattCharacteristic.PERMISSION_WRITE);
+
+        mUnlockGattServer.addCharacteristic(mUnlockEscrowToken);
+        mUnlockGattServer.addCharacteristic(mUnlockTokenHandle);
+    }
+
+    private synchronized void maybeSendUnlockToken() {
+        if (mCurrentUnlockToken == null || mCurrentUnlockHandle == null) {
+            return;
+        }
+        Log.d(TAG, "Handle and token both received, requesting unlock. Time: "
+                + System.currentTimeMillis());
+        final int callbackCount = mUnlockCallbacks.beginBroadcast();
+        for (int i = 0; i < callbackCount; i++) {
+            try {
+                mUnlockCallbacks.getBroadcastItem(i).onUnlockDataReceived(
+                        mCurrentUnlockToken, mCurrentUnlockHandle);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error callback onUnlockDataReceived", e);
+            }
+        }
+        mUnlockCallbacks.finishBroadcast();
+        mCurrentUnlockHandle = null;
+        mCurrentUnlockToken = null;
+    }
+
+    private static byte[] getBytes(long primitive) {
+        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
+        buffer.putLong(0, primitive);
+        return buffer.array();
+    }
+
+    private static long getLong(byte[] bytes) {
+        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
+        buffer.put(bytes);
+        buffer.flip();
+        return buffer.getLong();
+    }
+
+    private final class CarTrustAgentBleWrapper extends ICarTrustAgentBleService.Stub {
+        @Override
+        public void registerBleCallback(ICarTrustAgentBleCallback callback) {
+            mBleCallbacks.register(callback);
+        }
+
+        @Override
+        public void unregisterBleCallback(ICarTrustAgentBleCallback callback) {
+            mBleCallbacks.unregister(callback);
+        }
+
+        @Override
+        public void startEnrolmentAdvertising() {
+            Log.d(TAG, "startEnrolmentAdvertising");
+            stopUnlockAdvertising();
+            startAdvertising(mEnrolmentUuid, mEnrolmentGattServer);
+        }
+
+        @Override
+        public void stopEnrolmentAdvertising() {
+            Log.d(TAG, "stopEnrolmentAdvertising");
+            stopAdvertising();
+        }
+
+        @Override
+        public void sendEnrolmentHandle(BluetoothDevice device, long handle) {
+            Log.d(TAG, "sendEnrolmentHandle: " + handle);
+            mEnrolmentTokenHandle.setValue(getBytes(handle));
+            notifyCharacteristicChanged(device, mEnrolmentTokenHandle, false);
+        }
+
+        @Override
+        public void registerEnrolmentCallback(ICarTrustAgentEnrolmentCallback callback) {
+            mEnrolmentCallbacks.register(callback);
+        }
+
+        @Override
+        public void unregisterEnrolmentCallback(ICarTrustAgentEnrolmentCallback callback) {
+            mEnrolmentCallbacks.unregister(callback);
+        }
+
+        @Override
+        public void startUnlockAdvertising() {
+            Log.d(TAG, "startUnlockAdvertising");
+            stopEnrolmentAdvertising();
+            startAdvertising(mUnlockUuid, mUnlockGattServer);
+        }
+
+        @Override
+        public void stopUnlockAdvertising() {
+            Log.d(TAG, "stopUnlockAdvertising");
+            stopAdvertising();
+        }
+
+        @Override
+        public void registerUnlockCallback(ICarTrustAgentUnlockCallback callback) {
+            mUnlockCallbacks.register(callback);
+        }
+
+        @Override
+        public void unregisterUnlockCallback(ICarTrustAgentUnlockCallback callback) {
+            mUnlockCallbacks.unregister(callback);
+        }
+
+        @Override
+        public void setTokenRequestDelegate(ICarTrustAgentTokenRequestDelegate delegate) {
+            mTokenRequestDelegate = delegate;
+        }
+
+        @Override
+        public void revokeTrust() throws RemoteException {
+            if (mTokenRequestDelegate != null) {
+                mTokenRequestDelegate.revokeTrust();
+            }
+        }
+
+        @Override
+        public void addEscrowToken(byte[] token, int uid) throws RemoteException {
+            if (mTokenRequestDelegate != null) {
+                mTokenRequestDelegate.addEscrowToken(token, uid);
+            }
+        }
+
+        @Override
+        public void removeEscrowToken(long handle, int uid) throws RemoteException {
+            if (mTokenRequestDelegate != null) {
+                mTokenRequestDelegate.removeEscrowToken(handle, uid);
+            }
+        }
+
+        @Override
+        public void isEscrowTokenActive(long handle, int uid) throws RemoteException {
+            if (mTokenRequestDelegate != null) {
+                mTokenRequestDelegate.isEscrowTokenActive(handle, uid);
+            }
+        }
+
+        @Override
+        public void setTokenResponseCallback(ICarTrustAgentTokenResponseCallback callback) {
+            mTokenResponseCallback = callback;
+        }
+
+        @Override
+        public void onEscrowTokenAdded(byte[] token, long handle, int uid)
+                throws RemoteException {
+            Log.d(TAG, "onEscrowTokenAdded handle:" + handle + " uid:" + uid);
+            if (mTokenResponseCallback != null) {
+                mTokenResponseCallback.onEscrowTokenAdded(token, handle, uid);
+            }
+        }
+
+        @Override
+        public void onEscrowTokenRemoved(long handle, boolean successful) throws RemoteException {
+            Log.d(TAG, "onEscrowTokenRemoved handle:" + handle);
+            if (mTokenResponseCallback != null) {
+                mTokenResponseCallback.onEscrowTokenRemoved(handle, successful);
+            }
+        }
+
+        @Override
+        public void onEscrowTokenActiveStateChanged(long handle, boolean active)
+                throws RemoteException {
+            if (mTokenResponseCallback != null) {
+                mTokenResponseCallback.onEscrowTokenActiveStateChanged(handle, active);
+            }
+        }
+    }
+}
diff --git a/TrustAgent/src/com/android/car/trust/CarUnlockService.java b/TrustAgent/src/com/android/car/trust/CarUnlockService.java
deleted file mode 100644
index 0c1bc89..0000000
--- a/TrustAgent/src/com/android/car/trust/CarUnlockService.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.util.Log;
-import com.android.car.trust.comms.SimpleBleServer;
-
-import java.util.UUID;
-
-/**
- * A service that receives unlock requests from remote devices.
- */
-public class CarUnlockService extends SimpleBleServer {
-    /**
-     * A callback to receives callback
-     */
-    public interface UnlockServiceCallback {
-        void unlockDevice(byte[] token, long handle);
-    }
-
-    private static final String TAG = "CarUnlockService";
-
-    private BluetoothGattService mUnlockService;
-    private BluetoothGattCharacteristic mUnlockEscrowToken;
-    private BluetoothGattCharacteristic mUnlockTokenHandle;
-
-    private UnlockServiceCallback mCallback;
-
-    private byte[] mCurrentToken;
-    private Long mCurrentHandle;
-
-    private final IBinder mBinder = new UnlockServiceBinder();
-
-    public class UnlockServiceBinder extends Binder {
-        public CarUnlockService getService() {
-            return CarUnlockService.this;
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "CarUnlockService starting up, creating BLE service");
-        }
-        setupUnlockService();
-    }
-
-    /**
-     * Start advertising the BLE unlock service
-     */
-    public void start() {
-        ParcelUuid uuid = new ParcelUuid(
-                UUID.fromString(getString(R.string.unlock_service_uuid)));
-        start(uuid, mUnlockService);
-    }
-
-    public void addUnlockServiceCallback(UnlockServiceCallback callback) {
-        mCallback = callback;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    @Override
-    public void onCharacteristicWrite(BluetoothDevice device,
-            int requestId, BluetoothGattCharacteristic characteristic,
-            boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
-        UUID uuid = characteristic.getUuid();
-
-        if (uuid.equals(mUnlockTokenHandle.getUuid())) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Unlock handle received, value: " + Utils.getLong(value));
-            }
-            mCurrentHandle = Utils.getLong(value);
-            unlockDataReceived();
-        } else if (uuid.equals(mUnlockEscrowToken.getUuid())) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Unlock escrow token received, value: " + Utils.getLong(value));
-            }
-            mCurrentToken = value;
-            unlockDataReceived();
-        }
-    }
-
-    @Override
-    public void onCharacteristicRead(BluetoothDevice device,
-            int requestId, int offset, BluetoothGattCharacteristic characteristic) {
-        // The BLE unlock service should not receive any read requests.
-    }
-
-    private synchronized void unlockDataReceived() {
-        // If any piece of the unlocking data is not received, then do not unlock.
-        if (mCurrentHandle == null || mCurrentToken == null) {
-            return;
-        }
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Handle and token both received, requesting unlock. Time: "
-                    + System.currentTimeMillis());
-        }
-        // Both the handle and token has been received, try to unlock the device.
-
-
-        mCallback.unlockDevice(mCurrentToken, mCurrentHandle);
-
-        // Once we've notified the client of the unlocking data, clear it out.
-        mCurrentToken = null;
-        mCurrentHandle = null;
-    }
-
-
-    // Create services and characteristics to receive tokens and handles for unlocking the device.
-    private void setupUnlockService() {
-        mUnlockService = new BluetoothGattService(
-                UUID.fromString(getString(R.string.unlock_service_uuid)),
-                BluetoothGattService.SERVICE_TYPE_PRIMARY);
-
-        // Characteristic to describe the escrow token being used for unlock
-        mUnlockEscrowToken = new BluetoothGattCharacteristic(
-                UUID.fromString(getString(R.string.unlock_escrow_token_uiid)),
-                BluetoothGattCharacteristic.PROPERTY_WRITE,
-                BluetoothGattCharacteristic.PERMISSION_WRITE);
-
-        // Characteristic to describe the handle being used for this escrow token
-        mUnlockTokenHandle = new BluetoothGattCharacteristic(
-                UUID.fromString(getString(R.string.unlock_handle_uiid)),
-                BluetoothGattCharacteristic.PROPERTY_WRITE,
-                BluetoothGattCharacteristic.PERMISSION_WRITE);
-
-        mUnlockService.addCharacteristic(mUnlockEscrowToken);
-        mUnlockService.addCharacteristic(mUnlockTokenHandle);
-    }
-
-}
diff --git a/TrustAgent/src/com/android/car/trust/MainActivity.java b/TrustAgent/src/com/android/car/trust/MainActivity.java
deleted file mode 100644
index 8c1348b..0000000
--- a/TrustAgent/src/com/android/car/trust/MainActivity.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-
-/**
- * Selects whether the device is started as the car or remote device.
- */
-public class MainActivity extends Activity {
-    private static final int FINE_LOCATION_REQUEST_CODE = 13;
-
-    private Button mCarEnrolmentButton;
-    private Button mPhoneEnrolmentButton;
-    private Button mPhoneUnlockButton;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main_app);
-        mCarEnrolmentButton = (Button) findViewById(R.id.car_button);
-        mPhoneEnrolmentButton = (Button) findViewById(R.id.phone_enrolment_button);
-        mPhoneUnlockButton = (Button) findViewById(R.id.phone_unlock_button);
-
-        mCarEnrolmentButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Intent intent = new Intent(MainActivity.this /* context */,
-                        CarEnrolmentActivity.class);
-                startActivity(intent);
-            }
-        });
-
-        mPhoneEnrolmentButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Intent intent = new Intent(MainActivity.this /* context */,
-                        PhoneEnrolmentActivity.class);
-                startActivity(intent);
-            }
-        });
-
-        mPhoneUnlockButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Intent intent = new Intent(MainActivity.this /* context */,
-                        PhoneUnlockActivity.class);
-                startActivity(intent);
-            }
-        });
-
-        if (!checkPermissionGranted()) {
-            requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
-                    FINE_LOCATION_REQUEST_CODE);
-            // If location access isn't granted, BLE scanning will fail.
-            mCarEnrolmentButton.setEnabled(false);
-            mPhoneEnrolmentButton.setEnabled(false);
-            mPhoneUnlockButton.setEnabled(false);
-        }
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode,
-            String permissions[], int[] grantResults) {
-        if (requestCode == FINE_LOCATION_REQUEST_CODE && checkPermissionGranted()) {
-            mCarEnrolmentButton.setEnabled(true);
-            mPhoneEnrolmentButton.setEnabled(true);
-            mPhoneUnlockButton.setEnabled(true);
-        }
-    }
-
-    private boolean checkPermissionGranted() {
-        return checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-}
\ No newline at end of file
diff --git a/TrustAgent/src/com/android/car/trust/PhoneEnrolmentActivity.java b/TrustAgent/src/com/android/car/trust/PhoneEnrolmentActivity.java
deleted file mode 100644
index 6e187e2..0000000
--- a/TrustAgent/src/com/android/car/trust/PhoneEnrolmentActivity.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity to allow the user to add an escrow token to a remote device. <p/>
- *
- * For this to work properly, the correct permissions must be set in the system config.  In AOSP,
- * this config is in frameworks/base/core/res/res/values/config.xml <p/>
- *
- * The config must set config_allowEscrowTokenForTrustAgent to true.  For the desired car
- * experience, the config should also set config_strongAuthRequiredOnBoot to false.
- */
-public class PhoneEnrolmentActivity extends Activity {
-    private Button mScanButton;
-    private Button mEnrollButton;
-
-    private TextView mTextOutput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.phone_client);
-
-        mScanButton = (Button) findViewById(R.id.ble_scan_btn);
-        mEnrollButton = (Button) findViewById(R.id.action_button);
-        mEnrollButton.setText(getString(R.string.enroll_button));
-
-        mTextOutput = (TextView) findViewById(R.id.output);
-
-        PhoneEnrolmentController controller = new PhoneEnrolmentController(this /* context */);
-        controller.bind(mTextOutput, mScanButton, mEnrollButton);
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/PhoneEnrolmentController.java b/TrustAgent/src/com/android/car/trust/PhoneEnrolmentController.java
deleted file mode 100644
index b887dc4..0000000
--- a/TrustAgent/src/com/android/car/trust/PhoneEnrolmentController.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.preference.PreferenceManager;
-import android.util.Base64;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-import com.android.car.trust.comms.SimpleBleClient;
-
-import java.nio.ByteBuffer;
-import java.util.Random;
-import java.util.UUID;
-
-/**
- * A controller that sets up a {@link SimpleBleClient} to connect to the BLE enrollment service.
- * It also binds the UI components to control the enrollment process.
- */
-public class PhoneEnrolmentController {
-    private static final String TAG = "PhoneEnrolmentCtlr";
-    private String mTokenHandleKey;
-    private String mEscrowTokenKey;
-
-    // BLE characteristics associated with the enrollment/add escrow token service.
-    private BluetoothGattCharacteristic mEnrolmentTokenHandle;
-    private BluetoothGattCharacteristic mEnrolmentEscrowToken;
-
-    private ParcelUuid mEnrolmentServiceUuid;
-
-    private SimpleBleClient mClient;
-    private Context mContext;
-
-    private TextView mTextView;
-    private Handler mHandler;
-
-    private Button mScanButton;
-    private Button mEnrolButton;
-
-    public PhoneEnrolmentController(Context context) {
-        mContext = context;
-
-        mTokenHandleKey = context.getString(R.string.pref_key_token_handle);
-        mEscrowTokenKey = context.getString(R.string.pref_key_escrow_token);
-
-        mClient = new SimpleBleClient(context);
-        mEnrolmentServiceUuid = new ParcelUuid(
-                UUID.fromString(mContext.getString(R.string.enrollment_service_uuid)));
-        mClient.addCallback(mCallback /* callback */);
-
-        mHandler = new Handler(mContext.getMainLooper());
-    }
-
-    /**
-     * Binds the views to the actions that can be performed by this controller.
-     *
-     * @param textView    A text view used to display results from various BLE actions
-     * @param scanButton  Button used to start scanning for available BLE devices.
-     * @param enrolButton Button used to send new escrow token to remote device.
-     */
-    public void bind(TextView textView, Button scanButton, Button enrolButton) {
-        mTextView = textView;
-        mScanButton = scanButton;
-        mEnrolButton = enrolButton;
-
-        mScanButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mClient.start(mEnrolmentServiceUuid);
-            }
-        });
-
-        mEnrolButton.setEnabled(false);
-        mEnrolButton.setAlpha(0.3f);
-        mEnrolButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                appendOutputText("Sending new escrow token to remote device");
-
-                byte[] token = generateEscrowToken();
-                sendEnrolmentRequest(token);
-
-                // WARNING: Store the token so it can be used later for unlocking. This token
-                // should NEVER be stored on the device that is being unlocked. It should
-                // always be securely stored on a remote device that will trigger the unlock.
-                storeToken(token);
-            }
-        });
-    }
-
-    /**
-     * @return A random byte array that is used as the escrow token for remote device unlock.
-     */
-    private byte[] generateEscrowToken() {
-        Random random = new Random();
-        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
-        buffer.putLong(0, random.nextLong());
-        return buffer.array();
-    }
-
-    private void sendEnrolmentRequest(byte[] token) {
-        mEnrolmentEscrowToken.setValue(token);
-        mClient.writeCharacteristic(mEnrolmentEscrowToken);
-        storeToken(token);
-    }
-
-    private SimpleBleClient.ClientCallback mCallback = new SimpleBleClient.ClientCallback() {
-        @Override
-        public void onDeviceConnected(BluetoothDevice device) {
-            appendOutputText("Device connected: " + device.getName()
-                    + " addr: " + device.getAddress());
-        }
-
-        @Override
-        public void onDeviceDisconnected() {
-            appendOutputText("Device disconnected");
-        }
-
-        @Override
-        public void onCharacteristicChanged(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic) {
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCharacteristicChanged: " + Utils.getLong(characteristic.getValue()));
-            }
-
-            if (characteristic.getUuid().equals(mEnrolmentTokenHandle.getUuid())) {
-                // Store the new token handle that the BLE server is sending us. This required
-                // to unlock the device.
-                long handle = Utils.getLong(characteristic.getValue());
-                storeHandle(handle);
-                appendOutputText("Token handle received: " + handle);
-            }
-        }
-
-        @Override
-        public void onServiceDiscovered(BluetoothGattService service) {
-            if (!service.getUuid().equals(mEnrolmentServiceUuid.getUuid())) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Service UUID: " + service.getUuid()
-                            + " does not match Enrolment UUID " + mEnrolmentServiceUuid.getUuid());
-                }
-                return;
-            }
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Enrolment Service # characteristics: "
-                        + service.getCharacteristics().size());
-            }
-            mEnrolmentEscrowToken
-                    = Utils.getCharacteristic(R.string.enrollment_token_uuid, service, mContext);
-            mEnrolmentTokenHandle
-                    = Utils.getCharacteristic(R.string.enrollment_handle_uuid, service, mContext);
-            mClient.setCharacteristicNotification(mEnrolmentTokenHandle, true /* enable */);
-            appendOutputText("Enrolment BLE client successfully connected");
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    // Services are now set up, allow users to enrol new escrow tokens.
-                    mEnrolButton.setEnabled(true);
-                    mEnrolButton.setAlpha(1.0f);
-                }
-            });
-        }
-    };
-
-    private void storeHandle(long handle) {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-        prefs.edit().putLong(mTokenHandleKey, handle).apply();
-    }
-
-    private void storeToken(byte[] token) {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-        String byteArray = Base64.encodeToString(token, Base64.DEFAULT);
-        prefs.edit().putString(mEscrowTokenKey, byteArray).apply();
-    }
-
-    private void appendOutputText(final String text) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.append("\n" + text);
-            }
-        });
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/PhoneUnlockActivity.java b/TrustAgent/src/com/android/car/trust/PhoneUnlockActivity.java
deleted file mode 100644
index 767e1c5..0000000
--- a/TrustAgent/src/com/android/car/trust/PhoneUnlockActivity.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity to allow the user to unlock a remote devices with the stored escrow token.
- */
-public class PhoneUnlockActivity extends Activity {
-    private Button mScannButton;
-    private Button mUnlockButton;
-
-    private TextView mTextOutput;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.phone_client);
-
-        mScannButton = (Button) findViewById(R.id.ble_scan_btn);
-        mUnlockButton = (Button) findViewById(R.id.action_button);
-        mUnlockButton.setText(getString(R.string.unlock_button));
-
-        mTextOutput = (TextView) findViewById(R.id.output);
-
-        PhoneUnlockController controller = new PhoneUnlockController(this /* context */);
-        controller.bind(mTextOutput, mScannButton, mUnlockButton);
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/PhoneUnlockController.java b/TrustAgent/src/com/android/car/trust/PhoneUnlockController.java
deleted file mode 100644
index c956333..0000000
--- a/TrustAgent/src/com/android/car/trust/PhoneUnlockController.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.preference.PreferenceManager;
-import android.util.Base64;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-import com.android.car.trust.comms.SimpleBleClient;
-
-import java.util.UUID;
-
-/**
- * A controller that sets up a {@link SimpleBleClient} to connect to the BLE unlock service.
- */
-public class PhoneUnlockController {
-    private static final String TAG = "PhoneUnlockController";
-
-    private String mTokenHandleKey;
-    private String mEscrowTokenKey;
-
-    // BLE characteristics associated with the enrolment/add escrow token service.
-    private BluetoothGattCharacteristic mUnlockTokenHandle;
-    private BluetoothGattCharacteristic mUnlockEscrowToken;
-
-    private ParcelUuid mUnlockServiceUuid;
-
-    private SimpleBleClient mClient;
-    private Context mContext;
-
-    private TextView mTextView;
-    private Handler mHandler;
-
-    private Button mScanButton;
-    private Button mUnlockButton;
-
-    public PhoneUnlockController(Context context) {
-        mContext = context;
-
-        mTokenHandleKey = context.getString(R.string.pref_key_token_handle);
-        mEscrowTokenKey = context.getString(R.string.pref_key_escrow_token);
-
-        mClient = new SimpleBleClient(context);
-        mUnlockServiceUuid = new ParcelUuid(
-                UUID.fromString(mContext.getString(R.string.unlock_service_uuid)));
-        mClient.addCallback(mCallback /* callback */);
-
-        mHandler = new Handler(mContext.getMainLooper());
-    }
-
-    /**
-     * Binds the views to the actions that can be performed by this controller.
-     *
-     * @param textView    A text view used to display results from various BLE actions
-     * @param scanButton  Button used to start scanning for available BLE devices.
-     * @param enrolButton Button used to send new escrow token to remote device.
-     */
-    public void bind(TextView textView, Button scanButton, Button enrolButton) {
-        mTextView = textView;
-        mScanButton = scanButton;
-        mUnlockButton = enrolButton;
-
-        mScanButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mClient.start(mUnlockServiceUuid);
-            }
-        });
-
-        mUnlockButton.setEnabled(false);
-        mUnlockButton.setAlpha(0.3f);
-        mUnlockButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                appendOutputText("Sending unlock token and handle to remote device");
-                sendUnlockRequest();
-            }
-        });
-    }
-
-    private void sendUnlockRequest() {
-        // Retrieve stored token and handle and write to remote device.
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
-        long handle = prefs.getLong(mTokenHandleKey, -1);
-        byte[] token = Base64.decode(prefs.getString(mEscrowTokenKey, null), Base64.DEFAULT);
-
-        mUnlockEscrowToken.setValue(token);
-        mUnlockTokenHandle.setValue(Utils.getBytes(handle));
-
-        mClient.writeCharacteristic(mUnlockEscrowToken);
-        mClient.writeCharacteristic(mUnlockTokenHandle);
-    }
-
-    private SimpleBleClient.ClientCallback mCallback = new SimpleBleClient.ClientCallback() {
-        @Override
-        public void onDeviceConnected(BluetoothDevice device) {
-            appendOutputText("Device connected: " + device.getName()
-                    + " addr: " + device.getAddress());
-        }
-
-        @Override
-        public void onDeviceDisconnected() {
-            appendOutputText("Device disconnected");
-        }
-
-        @Override
-        public void onCharacteristicChanged(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic) {
-            // Not expecting any characteristics changes for the unlocking client.
-        }
-
-        @Override
-        public void onServiceDiscovered(BluetoothGattService service) {
-            if (!service.getUuid().equals(mUnlockServiceUuid.getUuid())) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Service UUID: " + service.getUuid()
-                        + " does not match Enrolment UUID " + mUnlockServiceUuid.getUuid());
-                }
-                return;
-            }
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Unlock Service # characteristics: "
-                        + service.getCharacteristics().size());
-            }
-            mUnlockEscrowToken
-                    = Utils.getCharacteristic(R.string.unlock_escrow_token_uiid, service, mContext);
-            mUnlockTokenHandle
-                    = Utils.getCharacteristic(R.string.unlock_handle_uiid, service, mContext);
-            appendOutputText("Unlock BLE client successfully connected");
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    // Services are now set up, allow users to enrol new escrow tokens.
-                    mUnlockButton.setEnabled(true);
-                    mUnlockButton.setAlpha(1.0f);
-                }
-            });
-        }
-    };
-
-    private void appendOutputText(final String text) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.append("\n" + text);
-            }
-        });
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/SimpleBleServer.java b/TrustAgent/src/com/android/car/trust/SimpleBleServer.java
new file mode 100644
index 0000000..7fbf2fe
--- /dev/null
+++ b/TrustAgent/src/com/android/car/trust/SimpleBleServer.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2017 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.trust;
+
+import static android.bluetooth.BluetoothProfile.GATT_SERVER;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+/**
+ * A generic service to start a BLE
+ */
+public abstract class SimpleBleServer extends Service {
+
+    private static final String TAG = SimpleBleServer.class.getSimpleName();
+
+    private static final int BLE_RETRY_LIMIT = 5;
+    private static final int BLE_RETRY_INTERVAL_MS = 1000;
+
+    private final AdvertiseCallback mAdvertisingCallback = new AdvertiseCallback() {
+        @Override
+        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+            super.onStartSuccess(settingsInEffect);
+            Log.d(TAG, "Successfully started advertising service");
+            onAdvertiseStartSuccess();
+        }
+
+        @Override
+        public void onStartFailure(int errorCode) {
+            super.onStartFailure(errorCode);
+            Log.e(TAG, "Failed to advertise, errorCode: " + errorCode);
+            onAdvertiseStartFailure(errorCode);
+        }
+    };
+
+    private final BluetoothGattServerCallback mGattServerCallback =
+            new BluetoothGattServerCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothDevice device,
+                final int status, final int newState) {
+            Log.d(TAG, "GattServer connection change status: " + status
+                    + " newState: " + newState
+                    + " device name: " + device.getName());
+            switch (newState) {
+                case BluetoothProfile.STATE_CONNECTED:
+                    onAdvertiseDeviceConnected(device);
+                    break;
+                case BluetoothProfile.STATE_DISCONNECTED:
+                    onAdvertiseDeviceDisconnected(device);
+                    break;
+            }
+        }
+
+        @Override
+        public void onServiceAdded(final int status, BluetoothGattService service) {
+            Log.d(TAG, "Service added status: " + status + " uuid: " + service.getUuid());
+        }
+
+        @Override
+        public void onCharacteristicReadRequest(BluetoothDevice device,
+                int requestId, int offset, final BluetoothGattCharacteristic characteristic) {
+            Log.d(TAG, "Read request for characteristic: " + characteristic.getUuid());
+            mGattServer.sendResponse(device, requestId,
+                    BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
+            onCharacteristicRead(device, requestId, offset, characteristic);
+        }
+
+        @Override
+        public void onCharacteristicWriteRequest(final BluetoothDevice device, int requestId,
+                BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
+                responseNeeded, int offset, byte[] value) {
+            Log.d(TAG, "Write request for characteristic: " + characteristic.getUuid());
+            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+                    offset, value);
+            onCharacteristicWrite(device, requestId, characteristic,
+                    preparedWrite, responseNeeded, offset, value);
+        }
+    };
+
+    private final Handler mHandler = new Handler();
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothLeAdvertiser mAdvertiser;
+    private BluetoothGattServer mGattServer;
+    private int mAdvertiserStartCount;
+
+    /**
+     * Starts the GATT server with the given {@link BluetoothGattService} and begins
+     * advertising with the {@link ParcelUuid}.
+     * <p>It is possible that BLE service is still in TURNING_ON state when this method is invoked.
+     * Therefore, several retries will be made to ensure advertising is started.
+     *
+     * @param advertiseUuid Service Uuid used in the {@link AdvertiseData}
+     * @param service {@link BluetoothGattService} that will be discovered by clients
+     */
+    protected void startAdvertising(ParcelUuid advertiseUuid, BluetoothGattService service) {
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+            Log.e(TAG, "System does not support BLE");
+            return;
+        }
+
+        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback);
+        if (mGattServer == null) {
+            Log.e(TAG, "Gatt Server not created");
+            return;
+        }
+
+        // We only allow adding one service in this implementation. If multiple services need
+        // to be added, then they need to be queued up and added only after
+        // BluetoothGattServerCallback.onServiceAdded is called.
+        mGattServer.addService(service);
+
+        AdvertiseSettings settings = new AdvertiseSettings.Builder()
+                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
+                .setConnectable(true)
+                .build();
+
+        AdvertiseData data = new AdvertiseData.Builder()
+                .setIncludeDeviceName(true)
+                .addServiceUuid(advertiseUuid)
+                .build();
+
+        mAdvertiserStartCount = 0;
+        startAdvertisingInternally(settings, data);
+    }
+
+    private void startAdvertisingInternally(AdvertiseSettings settings, AdvertiseData data) {
+        mAdvertiserStartCount += 1;
+        mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
+        if (mAdvertiser == null && mAdvertiserStartCount < BLE_RETRY_LIMIT) {
+            mHandler.postDelayed(() -> startAdvertisingInternally(settings, data),
+                    BLE_RETRY_INTERVAL_MS);
+        } else {
+            mHandler.removeCallbacks(null);
+            mAdvertiser.startAdvertising(settings, data, mAdvertisingCallback);
+            mAdvertiserStartCount = 0;
+        }
+    }
+
+    protected void stopAdvertising() {
+        if (mAdvertiser != null) {
+            mAdvertiser.stopAdvertising(mAdvertisingCallback);
+        }
+    }
+
+    /**
+     * Notifies the characteristic change via {@link BluetoothGattServer}
+     */
+    protected void notifyCharacteristicChanged(BluetoothDevice device,
+            BluetoothGattCharacteristic characteristic, boolean confirm) {
+        if (mGattServer != null) {
+            mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        // Stops the advertiser and GATT server. This needs to be done to avoid leaks
+        if (mAdvertiser != null) {
+            mAdvertiser.stopAdvertising(mAdvertisingCallback);
+            mAdvertiser.cleanup();
+        }
+
+        if (mGattServer != null) {
+            mGattServer.clearServices();
+            try {
+                for (BluetoothDevice d : mBluetoothManager.getConnectedDevices(GATT_SERVER)) {
+                    mGattServer.cancelConnection(d);
+                }
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "Error getting connected devices", e);
+            } finally {
+                mGattServer.close();
+            }
+        }
+        super.onDestroy();
+    }
+
+    // Delegate to subclass
+    protected void onAdvertiseStartSuccess() { }
+    protected void onAdvertiseStartFailure(int errorCode) { }
+    protected void onAdvertiseDeviceConnected(BluetoothDevice device) { }
+    protected void onAdvertiseDeviceDisconnected(BluetoothDevice device) { }
+
+    /**
+     * Triggered when this BleService receives a write request from a remote
+     * device. Sub-classes should implement how to handle requests.
+     */
+    protected abstract void onCharacteristicWrite(BluetoothDevice device, int requestId,
+            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
+            responseNeeded, int offset, byte[] value);
+
+    /**
+     * Triggered when this BleService receives a read request from a remote device.
+     */
+    protected abstract void onCharacteristicRead(BluetoothDevice device,
+            int requestId, int offset, final BluetoothGattCharacteristic characteristic);
+
+}
diff --git a/TrustAgent/src/com/android/car/trust/Utils.java b/TrustAgent/src/com/android/car/trust/Utils.java
deleted file mode 100644
index 3e9181f..0000000
--- a/TrustAgent/src/com/android/car/trust/Utils.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust;
-
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.content.Context;
-
-import java.nio.ByteBuffer;
-import java.util.UUID;
-
-public class Utils {
-
-    public static byte[] getBytes(long l) {
-        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
-        buffer.putLong(0, l);
-        return buffer.array();
-    }
-
-    public static long getLong(byte[] bytes) {
-        ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
-        buffer.put(bytes);
-        buffer.flip();
-        return buffer.getLong();
-    }
-
-    public static BluetoothGattCharacteristic getCharacteristic(int uuidRes,
-            BluetoothGattService service, Context context) {
-        return service.getCharacteristic(UUID.fromString(context.getString(uuidRes)));
-    }
-}
diff --git a/TrustAgent/src/com/android/car/trust/comms/SimpleBleClient.java b/TrustAgent/src/com/android/car/trust/comms/SimpleBleClient.java
deleted file mode 100644
index 77bf2d3..0000000
--- a/TrustAgent/src/com/android/car/trust/comms/SimpleBleClient.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust.comms;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCallback;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattService;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.le.BluetoothLeScanner;
-import android.bluetooth.le.ScanCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
-import android.content.Context;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.support.annotation.NonNull;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * A simple client that supports the scanning and connecting to available BLE devices. Should be
- * used along with {@link SimpleBleServer}.
- */
-public class SimpleBleClient {
-    public interface ClientCallback {
-        /**
-         * Called when a device that has a matching service UUID is found.
-         **/
-        void onDeviceConnected(BluetoothDevice device);
-
-        void onDeviceDisconnected();
-
-        void onCharacteristicChanged(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic);
-
-        /**
-         * Called for each {@link BluetoothGattService} that is discovered on the
-         * {@link BluetoothDevice} after a matching scan result and connection.
-         *
-         * @param service {@link BluetoothGattService} that has been discovered.
-         */
-        void onServiceDiscovered(BluetoothGattService service);
-    }
-
-    /**
-     * Wrapper class to allow queuing of BLE actions. The BLE stack allows only one action to be
-     * executed at a time.
-     */
-    public static class BleAction {
-        public static final int ACTION_WRITE = 0;
-        public static final int ACTION_READ = 1;
-
-        private int mAction;
-        private BluetoothGattCharacteristic mCharacteristic;
-
-        public BleAction(BluetoothGattCharacteristic characteristic, int action) {
-            mAction = action;
-            mCharacteristic = characteristic;
-        }
-
-        public int getAction() {
-            return mAction;
-        }
-
-        public BluetoothGattCharacteristic getCharacteristic() {
-            return mCharacteristic;
-        }
-    }
-
-    private static final String TAG = "SimpleBleClient";
-    private static final long SCAN_TIME_MS = 10000;
-
-    private Queue<BleAction> mBleActionQueue = new ConcurrentLinkedQueue<BleAction>();
-
-    private BluetoothManager mBtManager;
-    private BluetoothLeScanner mScanner;
-
-    protected BluetoothGatt mBtGatt;
-
-    private List<ClientCallback> mCallbacks;
-    private ParcelUuid mServiceUuid;
-    private Context mContext;
-
-    public SimpleBleClient(@NonNull Context context) {
-        mContext = context;
-        mBtManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
-        mScanner = mBtManager.getAdapter().getBluetoothLeScanner();
-        mCallbacks = new ArrayList<>();
-    }
-
-    /**
-     * Start scanning for a BLE devices with the specified service uuid.
-     *
-     * @param parcelUuid {@link ParcelUuid} used to identify the device that should be used for
-     *                   this client. This uuid should be the same as the one that is set in the
-     *                   {@link android.bluetooth.le.AdvertiseData.Builder} by the advertising
-     *                   device.
-     */
-    public void start(ParcelUuid parcelUuid) {
-        mServiceUuid = parcelUuid;
-
-        // We only want to scan for devices that have the correct uuid set in its advertise data.
-        List<ScanFilter> filters = new ArrayList<ScanFilter>();
-        ScanFilter.Builder serviceFilter = new ScanFilter.Builder();
-        serviceFilter.setServiceUuid(mServiceUuid);
-        filters.add(serviceFilter.build());
-
-        ScanSettings.Builder settings = new ScanSettings.Builder();
-        settings.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Start scanning for uuid: " + mServiceUuid.getUuid());
-        }
-        mScanner.startScan(filters, settings.build(), mScanCallback);
-
-        Handler handler = new Handler();
-        handler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                mScanner.stopScan(mScanCallback);
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Stopping Scanner");
-                }
-            }
-        }, SCAN_TIME_MS);
-    }
-
-    private boolean hasServiceUuid(ScanResult result) {
-        if (result.getScanRecord() == null
-                || result.getScanRecord().getServiceUuids() == null
-                || result.getScanRecord().getServiceUuids().size() == 0) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Writes to a {@link BluetoothGattCharacteristic} if possible, or queues the action until
-     * other actions are complete.
-     *
-     * @param characteristic {@link BluetoothGattCharacteristic} to be written
-     */
-    public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
-        processAction(new BleAction(characteristic, BleAction.ACTION_WRITE));
-    }
-
-    /**
-     * Reads a {@link BluetoothGattCharacteristic} if possible, or queues the read action until
-     * other actions are complete.
-     *
-     * @param characteristic {@link BluetoothGattCharacteristic} to be read.
-     */
-    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
-        processAction(new BleAction(characteristic, BleAction.ACTION_READ));
-    }
-
-    /**
-     * Enable or disable notification for specified {@link BluetoothGattCharacteristic}.
-     *
-     * @param characteristic The {@link BluetoothGattCharacteristic} for which to enable
-     *                       notifications.
-     * @param enabled        True if notifications should be enabled, false otherwise.
-     */
-    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
-            boolean enabled) {
-        mBtGatt.setCharacteristicNotification(characteristic, enabled);
-    }
-
-    /**
-     * Add a {@link ClientCallback} to listen for updates from BLE components
-     */
-    public void addCallback(ClientCallback callback) {
-        mCallbacks.add(callback);
-    }
-
-    public void removeCallback(ClientCallback callback) {
-        mCallbacks.remove(callback);
-    }
-
-    private void processAction(BleAction action) {
-        // Only execute actions if the queue is empty.
-        if (mBleActionQueue.size() > 0) {
-            mBleActionQueue.add(action);
-            return;
-        }
-
-        mBleActionQueue.add(action);
-        executeAction(mBleActionQueue.peek());
-    }
-
-    private void processNextAction() {
-        mBleActionQueue.poll();
-        executeAction(mBleActionQueue.peek());
-    }
-
-    private void executeAction(BleAction action) {
-        if (action == null) {
-            return;
-        }
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Executing BLE Action type: " + action.getAction());
-        }
-
-        int actionType = action.getAction();
-        switch (actionType) {
-            case BleAction.ACTION_WRITE:
-                mBtGatt.writeCharacteristic(action.getCharacteristic());
-                break;
-            case BleAction.ACTION_READ:
-                mBtGatt.readCharacteristic(action.getCharacteristic());
-                break;
-            default:
-        }
-    }
-
-    private String getStatus(int status) {
-        switch (status) {
-            case BluetoothGatt.GATT_FAILURE:
-                return "Failure";
-            case BluetoothGatt.GATT_SUCCESS:
-                return "GATT_SUCCESS";
-            case BluetoothGatt.GATT_READ_NOT_PERMITTED:
-                return "GATT_READ_NOT_PERMITTED";
-            case BluetoothGatt.GATT_WRITE_NOT_PERMITTED:
-                return "GATT_WRITE_NOT_PERMITTED";
-            case BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION:
-                return "GATT_INSUFFICIENT_AUTHENTICATION";
-            case BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED:
-                return "GATT_REQUEST_NOT_SUPPORTED";
-            case BluetoothGatt.GATT_INVALID_OFFSET:
-                return "GATT_INVALID_OFFSET";
-            case BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH:
-                return "GATT_INVALID_ATTRIBUTE_LENGTH";
-            case BluetoothGatt.GATT_CONNECTION_CONGESTED:
-                return "GATT_CONNECTION_CONGESTED";
-            default:
-                return "unknown";
-        }
-    }
-
-    private ScanCallback mScanCallback = new ScanCallback() {
-        @Override
-        public void onScanResult(int callbackType, ScanResult result) {
-            BluetoothDevice device = result.getDevice();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Scan result found: " + result.getScanRecord().getServiceUuids());
-            }
-
-            if (!hasServiceUuid(result)) {
-                return;
-            }
-
-            for (ParcelUuid uuid : result.getScanRecord().getServiceUuids()) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Scan result UUID: " + uuid);
-                }
-                if (uuid.equals(mServiceUuid)) {
-                    // This client only supports connecting to one service.
-                    // Once we find one, stop scanning and open a GATT connection to the device.
-                    mScanner.stopScan(mScanCallback);
-                    mBtGatt = device.connectGatt(mContext, false /* autoConnect */, mGattCallback);
-                    return;
-                }
-            }
-        }
-
-        @Override
-        public void onBatchScanResults(List<ScanResult> results) {
-            for (ScanResult r : results) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Batch scanResult: " + r.getDevice().getName()
-                            + " " + r.getDevice().getAddress());
-                    }
-            }
-        }
-
-        @Override
-        public void onScanFailed(int errorCode) {
-            Log.w(TAG, "Scan failed: " + errorCode);
-        }
-    };
-
-    private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
-        @Override
-        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
-            super.onConnectionStateChange(gatt, status, newState);
-
-            String state = "";
-
-            if (newState == BluetoothProfile.STATE_CONNECTED) {
-                state = "Connected";
-                mBtGatt.discoverServices();
-                for (ClientCallback callback : mCallbacks) {
-                    callback.onDeviceConnected(gatt.getDevice());
-                }
-
-            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
-                state = "Disconnected";
-                for (ClientCallback callback : mCallbacks) {
-                    callback.onDeviceDisconnected();
-                }
-            }
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, " Gatt connection status: " + getStatus(status) + " newState: " + state);
-            }
-        }
-
-        @Override
-        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
-            super.onServicesDiscovered(gatt, status);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onServicesDiscovered: " + status);
-            }
-
-            List<BluetoothGattService> services = gatt.getServices();
-            if (services == null || services.size() <= 0) {
-                return;
-            }
-
-            // Notify clients of newly discovered services.
-            for (BluetoothGattService service : mBtGatt.getServices()) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Found service: " + service.getUuid() + " notifying clients");
-                }
-                for (ClientCallback callback : mCallbacks) {
-                    callback.onServiceDiscovered(service);
-                }
-            }
-        }
-
-        @Override
-        public void onCharacteristicWrite(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic, int status) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCharacteristicWrite: " + status);
-            }
-            processNextAction();
-        }
-
-        @Override
-        public void onCharacteristicRead(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic, int status) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCharacteristicRead:" + new String(characteristic.getValue()));
-            }
-            processNextAction();
-        }
-
-        @Override
-        public void onCharacteristicChanged(BluetoothGatt gatt,
-                BluetoothGattCharacteristic characteristic) {
-            for (ClientCallback callback : mCallbacks) {
-                callback.onCharacteristicChanged(gatt, characteristic);
-            }
-            processNextAction();
-        }
-    };
-}
diff --git a/TrustAgent/src/com/android/car/trust/comms/SimpleBleServer.java b/TrustAgent/src/com/android/car/trust/comms/SimpleBleServer.java
deleted file mode 100644
index da3f7ac..0000000
--- a/TrustAgent/src/com/android/car/trust/comms/SimpleBleServer.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2017 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.trust.comms;
-
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattServer;
-import android.bluetooth.BluetoothGattServerCallback;
-import android.bluetooth.BluetoothGattService;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.le.AdvertiseCallback;
-import android.bluetooth.le.AdvertiseData;
-import android.bluetooth.le.AdvertiseSettings;
-import android.bluetooth.le.BluetoothLeAdvertiser;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.util.Log;
-
-import java.util.HashSet;
-
-/**
- * A generic service to start a BLE
- */
-public abstract class SimpleBleServer extends Service {
-
-    /**
-     * Listener that is notified when the status of the BLE server changes.
-     */
-    public interface ConnectionListener {
-        /**
-         * Called when the GATT server is started and BLE is successfully advertising.
-         */
-        void onServerStarted();
-
-        /**
-         * Called when the BLE advertisement fails to start.
-         *
-         * @param errorCode Error code (see {@link AdvertiseCallback}#ADVERTISE_FAILED_* constants)
-         */
-        void onServerStartFailed(int errorCode);
-
-        /**
-         * Called when a device is connected.
-         * @param device
-         */
-        void onDeviceConnected(BluetoothDevice device);
-    }
-
-    private static final String TAG = "SimpleBleServer";
-
-    private BluetoothLeAdvertiser mAdvertiser;
-    protected BluetoothGattServer mGattServer;
-
-    private HashSet<ConnectionListener> mListeners = new HashSet<>();
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        // Override in child classes.
-        return null;
-    }
-
-    /**
-     * Starts the GATT server with the given {@link BluetoothGattService} and begins
-     * advertising with the {@link ParcelUuid}.
-     * @param advertiseUuid Service Uuid used in the {@link AdvertiseData}
-     * @param service {@link BluetoothGattService} that will be discovered by clients
-     */
-    protected void start(ParcelUuid advertiseUuid, BluetoothGattService service) {
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
-            Log.e(TAG, "System does not support BLE");
-            return;
-        }
-
-        BluetoothManager btManager =
-                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
-
-        mGattServer = btManager.openGattServer(this, mGattServerCallback);
-        if (mGattServer == null) {
-            Log.e(TAG, "Gatt Server not created");
-            return;
-        }
-
-        // We only allow adding one service in this implementation. If multiple services need
-        // to be added, then they need to be queued up and added only after
-        // BluetoothGattServerCallback.onServiceAdded is called.
-        mGattServer.addService(service);
-
-        AdvertiseSettings settings = new AdvertiseSettings.Builder()
-                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
-                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
-                .setConnectable(true)
-                .build();
-
-        AdvertiseData data = new AdvertiseData.Builder()
-                .setIncludeDeviceName(true)
-                .addServiceUuid(advertiseUuid)
-                .build();
-
-        mAdvertiser
-                = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
-
-        mAdvertiser.startAdvertising(settings, data, mAdvertisingCallback);
-    }
-
-    /**
-     * Stops the advertiser and GATT server. This needs to be done to avoid leaks
-     */
-    protected void stop() {
-        if (mAdvertiser != null) {
-            mAdvertiser.stopAdvertising(mAdvertisingCallback);
-            mAdvertiser.cleanup();
-        }
-
-        if (mGattServer != null) {
-            mGattServer.clearServices();
-            try {
-                for (BluetoothDevice d : mGattServer.getConnectedDevices()) {
-                    mGattServer.cancelConnection(d);
-                }
-            } catch (UnsupportedOperationException e) {
-                Log.e(TAG, "Error getting connected devices", e);
-            } finally {
-                mGattServer.close();
-            }
-        }
-
-        mListeners.clear();
-    }
-
-    @Override
-    public void onDestroy() {
-        stop();
-        super.onDestroy();
-    }
-
-    public void addConnectionListener(ConnectionListener listener) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Adding connection listener");
-        }
-        mListeners.add(listener);
-    }
-
-    /**
-     * Triggered when this BleService receives a write request from a remote
-     * device. Sub-classes should implement how to handle requests.
-     */
-    public abstract void onCharacteristicWrite(final BluetoothDevice device, int requestId,
-            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
-            responseNeeded, int offset, byte[] value);
-
-    /**
-     * Triggered when this BleService receives a read request from a remote device.
-     */
-    public abstract void onCharacteristicRead(BluetoothDevice device,
-            int requestId, int offset, final BluetoothGattCharacteristic characteristic);
-
-    private AdvertiseCallback mAdvertisingCallback = new AdvertiseCallback() {
-        @Override
-        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
-            super.onStartSuccess(settingsInEffect);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Successfully started advertising service");
-            }
-            for (ConnectionListener listener : mListeners) {
-                listener.onServerStarted();
-            }
-        }
-
-        @Override
-        public void onStartFailure(int errorCode) {
-            super.onStartFailure(errorCode);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Failed to advertise, errorCode: " + errorCode);
-            }
-            for (ConnectionListener listener : mListeners) {
-                listener.onServerStartFailed(errorCode);
-            }
-        }
-    };
-
-    private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
-        @Override
-        public void onConnectionStateChange(BluetoothDevice device,
-                final int status, final int newState) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "GattServer connection change status: "
-                        + newState + " newState: "
-                        + newState + " device name: " + device.getName());
-            }
-            if (newState == BluetoothProfile.STATE_CONNECTED) {
-                for (ConnectionListener listener : mListeners) {
-                    listener.onDeviceConnected(device);
-                }
-            }
-        }
-
-        @Override
-        public void onServiceAdded(final int status, BluetoothGattService service) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Service added status: " + status + " uuid: " + service.getUuid());
-            }
-        }
-
-        @Override
-        public void onCharacteristicReadRequest(BluetoothDevice device,
-                int requestId, int offset, final BluetoothGattCharacteristic characteristic) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Read request for characteristic: " + characteristic.getUuid());
-            }
-            mGattServer.sendResponse(device, requestId,
-                    BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
-            SimpleBleServer.
-                    this.onCharacteristicRead(device, requestId, offset, characteristic);
-        }
-
-        @Override
-        public void onCharacteristicWriteRequest(final BluetoothDevice device, int requestId,
-                BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
-                responseNeeded, int offset, byte[] value) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Write request for characteristic: " + characteristic.getUuid());
-            }
-            mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
-                    offset, value);
-
-            SimpleBleServer.
-                    this.onCharacteristicWrite(device, requestId, characteristic,
-                    preparedWrite, responseNeeded, offset, value);
-        }
-    };
-}
diff --git a/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java b/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java
index b6ed388..381b7ee 100644
--- a/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java
+++ b/car-cluster-logging-renderer/src/android/car/cluster/loggingrenderer/LoggingClusterRenderingService.java
@@ -43,34 +43,6 @@
                 return config;
             }
 
-
-            @Override
-            public void onStartNavigation() {
-                Log.i(TAG, "onStartNavigation");
-            }
-
-            @Override
-            public void onStopNavigation() {
-                Log.i(TAG, "onStopNavigation");
-            }
-
-            @Override
-            public void onNextTurnChanged(int event, CharSequence eventName, int turnAngle,
-                    int turnNumber, Bitmap image, int turnSide) {
-                Log.i(TAG, "event: " + event + ", eventName: " + eventName +
-                        ", turnAngle: " + turnAngle + ", turnNumber: " + turnNumber +
-                        ", image: " + image + ", turnSide: " + turnSide);
-            }
-
-            @Override
-            public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds,
-                    int displayDistanceMillis, int displayDistanceUnit) {
-                Log.i(TAG, "onNextTurnDistanceChanged, distanceMeters: " + distanceMeters
-                        + ", timeSeconds: " + timeSeconds
-                        + ", displayDistanceMillis: " + displayDistanceMillis
-                        + ", displayDistanceUnit: " + displayDistanceUnit);
-            }
-
             @Override
             public void onEvent(int eventType, Bundle bundle) {
                 Log.i(TAG, "onEvent, eventType: " + eventType + ", bundle: " + bundle);
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index 2ed9299..806121f 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -12,6 +12,41 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+cc_library {
+    name: "libcarpowermanager",
+
+    aidl: {
+        export_aidl_headers: true,
+        local_include_dirs: [
+            "src",
+        ],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+
+    include_dirs: [
+        "packages/services/Car/car-lib/native/include",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: [
+        "src/android/car/ICar.aidl",
+        "src/android/car/hardware/power/ICarPower.aidl",
+        "src/android/car/hardware/power/ICarPowerStateListener.aidl",
+        "native/CarPowerManager/CarPowerManager.cpp",
+    ],
+}
+
 java_library {
     name: "android.car",
     srcs: [
@@ -24,6 +59,10 @@
             "system/bt/binder",
         ],
     },
+    exclude_srcs: [
+        "src/android/car/storagemonitoring/IoStats.aidl",
+        "src/android/car/storagemonitoring/IoStatsEntry.aidl",
+    ],
     product_variables: {
         pdk: {
             enabled: false,
diff --git a/car-lib/Android.mk b/car-lib/Android.mk
index 4873ab9..e0fa482 100644
--- a/car-lib/Android.mk
+++ b/car-lib/Android.mk
@@ -23,8 +23,17 @@
 
 car_lib_sources := $(call all-java-files-under, src)
 car_lib_sources += $(call all-java-files-under, src_feature_future)
+
 car_lib_sources += $(call all-Iaidl-files-under, src)
 
+# IoStats* are parcelable types (vs. interface types), but the build system uses an initial
+# I as a magic marker to mean "interface", and due to this ends up refusing to compile
+# these files as part of the build process.
+# A clean solution to this is actively being worked on by the build team, but is not yet
+# available, so for now we just filter the files out by hand.
+car_lib_sources := $(filter-out src/android/car/storagemonitoring/IoStats.aidl,$(car_lib_sources))
+car_lib_sources := $(filter-out src/android/car/storagemonitoring/IoStatsEntry.aidl,$(car_lib_sources))
+
 ifeq ($(BOARD_IS_AUTOMOTIVE), true)
 full_classes_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,android.car,,COMMON)/classes.jar
 $(call dist-for-goals,dist_files,$(full_classes_jar):android.car.jar)
@@ -40,18 +49,63 @@
 car_module_java_packages := android.car*
 include $(CAR_API_CHECK)
 
+# Build stubs jar for target android-support-car
+# ---------------------------------------------
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := android.car7
-LOCAL_SRC_FILES := $(car_lib_sources)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AIDL_INCLUDES += system/bt/binder
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
-LOCAL_EMMA_INSTRUMENT := true
-endif
+LOCAL_JAVA_LIBRARIES := android.car
 
-include $(BUILD_JAVA_LIBRARY)
-$(call dist-for-goals,dist_files,$(full_classes_jar):$(LOCAL_MODULE).jar)
+LOCAL_ADDITIONAL_JAVA_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,android.car,,COMMON)/src
+
+android_car_stub_packages := \
+    android.car*
+
+android_car_api := \
+    $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/android.car_api.txt
+
+# Note: The make target is android.car-stub-docs
+LOCAL_MODULE := android.car-stub
+LOCAL_DROIDDOC_OPTIONS := \
+    -stubs $(call intermediates-dir-for,JAVA_LIBRARIES,android.car-stubs,,COMMON)/src \
+    -stubpackages $(subst $(space),:,$(android_car_stub_packages)) \
+    -api $(android_car_api) \
+    -nodocs
+
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/java/
+LOCAL_DROIDDOC_HTML_DIR :=
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_DROIDDOC)
+
+$(android_car_api): $(full_target)
+
+android.car-stubs_stamp := $(full_target)
+
+###############################################
+# Build the stubs java files into a jar. This build rule relies on the
+# stubs_stamp make variable being set from the droiddoc rule.
+
+include $(CLEAR_VARS)
+
+# CAR_API_CHECK uses the same name to generate a module, but BUILD_DROIDDOC
+# appends "-docs" to module name.
+LOCAL_MODULE := android.car-stubs
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+
+# Make sure to run droiddoc first to generate the stub source files.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(android.car-stubs_stamp)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+android.car-stubs_stamp :=
+android_car_stub_packages :=
+android_car_api :=
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
 
 endif #TARGET_BUILD_PDK
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 242c337..9cd2e4c 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -11,16 +11,23 @@
     method public boolean isConnecting();
     field public static final java.lang.String APP_FOCUS_SERVICE = "app_focus";
     field public static final java.lang.String AUDIO_SERVICE = "audio";
+    field public static final java.lang.String CAR_CONFIGURATION_SERVICE = "configuration";
     field public static final java.lang.String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
     field public static final java.lang.String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
+    field public static final java.lang.String CAR_NAVIGATION_SERVICE = "car_navigation_service";
+    field public static final java.lang.String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
     field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
     field public static final java.lang.String INFO_SERVICE = "info";
     field public static final java.lang.String PACKAGE_SERVICE = "package";
     field public static final java.lang.String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
-    field public static final java.lang.String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
-    field public static final java.lang.String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
+    field public static final java.lang.String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
+    field public static final java.lang.String PERMISSION_CAR_NAVIGATION_MANAGER = "android.car.permission.CAR_NAVIGATION_MANAGER";
+    field public static final java.lang.String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
+    field public static final java.lang.String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
+    field public static final java.lang.String PERMISSION_EXTERIOR_ENVIRONMENT = "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
+    field public static final java.lang.String PERMISSION_IDENTIFICATION = "android.car.permission.CAR_IDENTIFICATION";
+    field public static final java.lang.String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN";
     field public static final java.lang.String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
-    field public static final java.lang.String PERMISSION_VEHICLE_DYNAMICS_STATE = "android.car.permission.VEHICLE_DYNAMICS_STATE";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final int VERSION = 3; // 0x3
   }
@@ -49,6 +56,10 @@
   }
 
   public final class CarInfoManager {
+    method public float getEvBatteryCapacity() throws android.car.CarNotConnectedException;
+    method public int[] getEvConnectorTypes() throws android.car.CarNotConnectedException;
+    method public float getFuelCapacity() throws android.car.CarNotConnectedException;
+    method public int[] getFuelTypes() throws android.car.CarNotConnectedException;
     method public java.lang.String getManufacturer() throws android.car.CarNotConnectedException;
     method public java.lang.String getModel() throws android.car.CarNotConnectedException;
     method public java.lang.String getModelYear() throws android.car.CarNotConnectedException;
@@ -172,8 +183,58 @@
 package android.car.content.pm {
 
   public final class CarPackageManager {
-    method public boolean isActivityAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isServiceAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
+    method public boolean isActivityDistractionOptimized(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
+    method public boolean isServiceDistractionOptimized(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
+  }
+
+}
+
+package android.car.drivingstate {
+
+  public class CarUxRestrictions implements android.os.Parcelable {
+    ctor public CarUxRestrictions(android.car.drivingstate.CarUxRestrictions);
+    method public int describeContents();
+    method public int getActiveRestrictions();
+    method public int getMaxContentDepth();
+    method public int getMaxCumulativeContentItems();
+    method public int getMaxRestrictedStringLength();
+    method public long getTimeStamp();
+    method public boolean isRequiresDistractionOptimization();
+    method public boolean isSameRestrictions(android.car.drivingstate.CarUxRestrictions);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.drivingstate.CarUxRestrictions> CREATOR;
+    field public static final int UX_RESTRICTIONS_BASELINE = 0; // 0x0
+    field public static final int UX_RESTRICTIONS_FULLY_RESTRICTED = 511; // 0x1ff
+    field public static final int UX_RESTRICTIONS_LIMIT_CONTENT = 32; // 0x20
+    field public static final int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 4; // 0x4
+    field public static final int UX_RESTRICTIONS_NO_DIALPAD = 1; // 0x1
+    field public static final int UX_RESTRICTIONS_NO_FILTERING = 2; // 0x2
+    field public static final int UX_RESTRICTIONS_NO_KEYBOARD = 8; // 0x8
+    field public static final int UX_RESTRICTIONS_NO_SETUP = 64; // 0x40
+    field public static final int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 128; // 0x80
+    field public static final int UX_RESTRICTIONS_NO_VIDEO = 16; // 0x10
+    field public static final int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 256; // 0x100
+  }
+
+  public static class CarUxRestrictions.Builder {
+    ctor public CarUxRestrictions.Builder(boolean, int, long);
+    method public android.car.drivingstate.CarUxRestrictions build();
+    method public android.car.drivingstate.CarUxRestrictions.Builder setMaxContentDepth(int);
+    method public android.car.drivingstate.CarUxRestrictions.Builder setMaxCumulativeContentItems(int);
+    method public android.car.drivingstate.CarUxRestrictions.Builder setMaxStringLength(int);
+  }
+
+  public static abstract class CarUxRestrictions.CarUxRestrictionsInfo implements java.lang.annotation.Annotation {
+  }
+
+  public final class CarUxRestrictionsManager {
+    method public android.car.drivingstate.CarUxRestrictions getCurrentCarUxRestrictions() throws android.car.CarNotConnectedException;
+    method public synchronized void registerListener(android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
+    method public synchronized void unregisterListener() throws android.car.CarNotConnectedException;
+  }
+
+  public static abstract interface CarUxRestrictionsManager.OnUxRestrictionsChangedListener {
+    method public abstract void onUxRestrictionsChanged(android.car.drivingstate.CarUxRestrictions);
   }
 
 }
@@ -184,27 +245,20 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.car.hardware.CarSensorEvent> CREATOR;
-    field public static final int DRIVE_STATUS_FULLY_RESTRICTED = 31; // 0x1f
-    field public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 16; // 0x10
-    field public static final int DRIVE_STATUS_NO_CONFIG = 8; // 0x8
-    field public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 2; // 0x2
-    field public static final int DRIVE_STATUS_NO_VIDEO = 1; // 0x1
-    field public static final int DRIVE_STATUS_NO_VOICE_INPUT = 4; // 0x4
-    field public static final int DRIVE_STATUS_UNRESTRICTED = 0; // 0x0
-    field public static final int GEAR_DRIVE = 100; // 0x64
-    field public static final int GEAR_EIGHTH = 8; // 0x8
-    field public static final int GEAR_FIFTH = 5; // 0x5
-    field public static final int GEAR_FIRST = 1; // 0x1
-    field public static final int GEAR_FOURTH = 4; // 0x4
-    field public static final int GEAR_NEUTRAL = 0; // 0x0
-    field public static final int GEAR_NINTH = 9; // 0x9
-    field public static final int GEAR_PARK = 101; // 0x65
-    field public static final int GEAR_REVERSE = 102; // 0x66
-    field public static final int GEAR_SECOND = 2; // 0x2
-    field public static final int GEAR_SEVENTH = 7; // 0x7
-    field public static final int GEAR_SIXTH = 6; // 0x6
-    field public static final int GEAR_TENTH = 10; // 0xa
-    field public static final int GEAR_THIRD = 3; // 0x3
+    field public static final int GEAR_DRIVE = 8; // 0x8
+    field public static final int GEAR_EIGHTH = 2048; // 0x800
+    field public static final int GEAR_FIFTH = 256; // 0x100
+    field public static final int GEAR_FIRST = 16; // 0x10
+    field public static final int GEAR_FOURTH = 128; // 0x80
+    field public static final int GEAR_NEUTRAL = 1; // 0x1
+    field public static final int GEAR_NINTH = 4096; // 0x1000
+    field public static final int GEAR_PARK = 4; // 0x4
+    field public static final int GEAR_REVERSE = 2; // 0x2
+    field public static final int GEAR_SECOND = 32; // 0x20
+    field public static final int GEAR_SEVENTH = 1024; // 0x400
+    field public static final int GEAR_SIXTH = 512; // 0x200
+    field public static final int GEAR_TENTH = 8192; // 0x2000
+    field public static final int GEAR_THIRD = 64; // 0x40
     field public static final int IGNITION_STATE_ACC = 3; // 0x3
     field public static final int IGNITION_STATE_LOCK = 1; // 0x1
     field public static final int IGNITION_STATE_OFF = 2; // 0x2
@@ -213,9 +267,6 @@
     field public static final int IGNITION_STATE_UNDEFINED = 0; // 0x0
     field public static final int INDEX_ENVIRONMENT_PRESSURE = 1; // 0x1
     field public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0; // 0x0
-    field public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1; // 0x1
-    field public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0; // 0x0
-    field public static final int INDEX_FUEL_LOW_WARNING = 0; // 0x0
     field public static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1; // 0x1
     field public static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2; // 0x2
     field public static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4; // 0x4
@@ -236,30 +287,34 @@
 
   public final class CarSensorManager {
     method public android.car.hardware.CarSensorEvent getLatestSensorEvent(int) throws android.car.CarNotConnectedException;
+    method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
     method public int[] getSupportedSensors() throws android.car.CarNotConnectedException;
     method public boolean isSensorSupported(int) throws android.car.CarNotConnectedException;
     method public static boolean isSensorSupported(int[], int);
     method public boolean registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
     method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener);
     method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int);
-    field public static final int SENSOR_RATE_FAST = 1; // 0x1
-    field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
-    field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
-    field public static final int SENSOR_RATE_UI = 2; // 0x2
-    field public static final int SENSOR_TYPE_ABS_ACTIVE = 24; // 0x18
-    field public static final int SENSOR_TYPE_CAR_SPEED = 2; // 0x2
-    field public static final int SENSOR_TYPE_DRIVING_STATUS = 11; // 0xb
+    field public static final int SENSOR_RATE_FAST = 10; // 0xa
+    field public static final int SENSOR_RATE_FASTEST = 100; // 0x64
+    field public static final int SENSOR_RATE_NORMAL = 1; // 0x1
+    field public static final int SENSOR_RATE_UI = 5; // 0x5
+    field public static final int SENSOR_TYPE_ABS_ACTIVE = 287310858; // 0x1120040a
+    field public static final int SENSOR_TYPE_CAR_SPEED = 291504647; // 0x11600207
     field public static final int SENSOR_TYPE_ENVIRONMENT = 12; // 0xc
-    field public static final int SENSOR_TYPE_FUEL_LEVEL = 5; // 0x5
-    field public static final int SENSOR_TYPE_GEAR = 7; // 0x7
-    field public static final int SENSOR_TYPE_IGNITION_STATE = 22; // 0x16
-    field public static final int SENSOR_TYPE_NIGHT = 9; // 0x9
-    field public static final int SENSOR_TYPE_ODOMETER = 4; // 0x4
-    field public static final int SENSOR_TYPE_PARKING_BRAKE = 6; // 0x6
-    field public static final int SENSOR_TYPE_RPM = 3; // 0x3
-    field public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 25; // 0x19
-    field public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 1879048191; // 0x6fffffff
-    field public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 23; // 0x17
+    field public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 291504908; // 0x1160030c
+    field public static final int SENSOR_TYPE_EV_BATTERY_LEVEL = 291504905; // 0x11600309
+    field public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 287310603; // 0x1120030b
+    field public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 287310602; // 0x1120030a
+    field public static final int SENSOR_TYPE_FUEL_DOOR_OPEN = 287310600; // 0x11200308
+    field public static final int SENSOR_TYPE_FUEL_LEVEL = 291504903; // 0x11600307
+    field public static final int SENSOR_TYPE_GEAR = 289408000; // 0x11400400
+    field public static final int SENSOR_TYPE_IGNITION_STATE = 289408009; // 0x11400409
+    field public static final int SENSOR_TYPE_NIGHT = 287310855; // 0x11200407
+    field public static final int SENSOR_TYPE_ODOMETER = 291504644; // 0x11600204
+    field public static final int SENSOR_TYPE_PARKING_BRAKE = 287310850; // 0x11200402
+    field public static final int SENSOR_TYPE_RPM = 291504901; // 0x11600305
+    field public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
+    field public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 290521862; // 0x11510306
   }
 
   public static abstract interface CarSensorManager.OnSensorChangedListener {
@@ -271,30 +326,49 @@
 package android.car.media {
 
   public final class CarAudioManager {
-    method public void abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
-    method public android.media.AudioAttributes getAudioAttributesForCarUsage(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMaxVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMinVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamVolume(int) throws android.car.CarNotConnectedException;
-    method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public void setStreamVolume(int, int, int) throws android.car.CarNotConnectedException;
-    field public static final int CAR_AUDIO_USAGE_ALARM = 6; // 0x6
-    field public static final int CAR_AUDIO_USAGE_DEFAULT = 0; // 0x0
-    field public static final int CAR_AUDIO_USAGE_MUSIC = 1; // 0x1
-    field public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3; // 0x3
-    field public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7; // 0x7
-    field public static final int CAR_AUDIO_USAGE_RADIO = 2; // 0x2
-    field public static final int CAR_AUDIO_USAGE_RINGTONE = 10; // 0xa
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9; // 0x9
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8; // 0x8
-    field public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4; // 0x4
-    field public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5; // 0x5
+    method public android.car.media.CarAudioPatchHandle createAudioPatch(java.lang.String, int, int) throws android.car.CarNotConnectedException;
+    method public java.lang.String[] getExternalSources() throws android.car.CarNotConnectedException;
+    method public int getGroupMaxVolume(int) throws android.car.CarNotConnectedException;
+    method public int getGroupMinVolume(int) throws android.car.CarNotConnectedException;
+    method public int getGroupVolume(int) throws android.car.CarNotConnectedException;
+    method public int[] getUsagesForVolumeGroupId(int) throws android.car.CarNotConnectedException;
+    method public int getVolumeGroupCount() throws android.car.CarNotConnectedException;
+    method public int getVolumeGroupIdForUsage(int) throws android.car.CarNotConnectedException;
+    method public static java.lang.String getVolumeSettingsKeyForGroup(int);
+    method public void registerVolumeCallback(android.os.IBinder) throws android.car.CarNotConnectedException;
+    method public void registerVolumeChangeObserver(android.database.ContentObserver);
+    method public void releaseAudioPatch(android.car.media.CarAudioPatchHandle) throws android.car.CarNotConnectedException;
+    method public void setBalanceTowardRight(float) throws android.car.CarNotConnectedException;
+    method public void setFadeTowardFront(float) throws android.car.CarNotConnectedException;
+    method public void setGroupVolume(int, int, int) throws android.car.CarNotConnectedException;
+    method public void unregisterVolumeCallback(android.os.IBinder) throws android.car.CarNotConnectedException;
+    method public void unregisterVolumeChangeObserver(android.database.ContentObserver);
+  }
+
+  public final class CarAudioPatchHandle implements android.os.Parcelable {
+    ctor public CarAudioPatchHandle(android.media.AudioPatch);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.media.CarAudioPatchHandle> CREATOR;
+  }
+
+}
+
+package android.car.navigation {
+
+  public final class CarNavigationStatusManager {
+    method public android.car.navigation.CarNavigationInstrumentCluster getInstrumentClusterInfo() throws android.car.CarNotConnectedException;
+    method public void sendEvent(int, android.os.Bundle) throws android.car.CarNotConnectedException;
   }
 
 }
 
 package android.car.settings {
 
+  public class CarConfigurationManager {
+    method public android.car.settings.SpeedBumpConfiguration getSpeedBumpConfiguration() throws android.car.CarNotConnectedException;
+  }
+
   public class CarSettings {
     ctor public CarSettings();
   }
@@ -306,5 +380,15 @@
     field public static final java.lang.String KEY_GARAGE_MODE_WAKE_UP_TIME = "android.car.GARAGE_MODE_WAKE_UP_TIME";
   }
 
+  public final class SpeedBumpConfiguration implements android.os.Parcelable {
+    ctor public SpeedBumpConfiguration(double, double, long);
+    method public int describeContents();
+    method public double getAcquiredPermitsPerSecond();
+    method public double getMaxPermitPool();
+    method public long getPermitFillDelay();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.settings.SpeedBumpConfiguration> CREATOR;
+  }
+
 }
 
diff --git a/car-lib/api/system-1.txt b/car-lib/api/system-1.txt
index 253c874..e58b9be 100644
--- a/car-lib/api/system-1.txt
+++ b/car-lib/api/system-1.txt
@@ -635,8 +635,8 @@
     field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
     field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
     field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
-    field public static final int ID_ZONED_FAN_POSITION = 16391; // 0x4007
-    field public static final int ID_ZONED_FAN_POSITION_AVAILABLE = 16390; // 0x4006
+    field public static final int ID_ZONED_FAN_DIRECTION = 16391; // 0x4007
+    field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 16390; // 0x4006
     field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
     field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
     field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
diff --git a/car-lib/api/system-2.txt b/car-lib/api/system-2.txt
index e8540ad..3a2f2de 100644
--- a/car-lib/api/system-2.txt
+++ b/car-lib/api/system-2.txt
@@ -586,11 +586,11 @@
     method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
     method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
     method public synchronized void unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
-    field public static final int FAN_POSITION_DEFROST = 4; // 0x4
-    field public static final int FAN_POSITION_DEFROST_AND_FLOOR = 5; // 0x5
-    field public static final int FAN_POSITION_FACE = 1; // 0x1
-    field public static final int FAN_POSITION_FACE_AND_FLOOR = 3; // 0x3
-    field public static final int FAN_POSITION_FLOOR = 2; // 0x2
+    field public static final int FAN_DIRECTION_DEFROST = 4; // 0x4
+    field public static final int FAN_DIRECTION_DEFROST_AND_FLOOR = 5; // 0x5
+    field public static final int FAN_DIRECTION_FACE = 1; // 0x1
+    field public static final int FAN_DIRECTION_FACE_AND_FLOOR = 3; // 0x3
+    field public static final int FAN_DIRECTION_FLOOR = 2; // 0x2
     field public static final int ID_MIRROR_DEFROSTER_ON = 1; // 0x1
     field public static final int ID_OUTSIDE_AIR_TEMP = 3; // 0x3
     field public static final int ID_STEERING_WHEEL_TEMP = 2; // 0x2
@@ -600,8 +600,8 @@
     field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
     field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
     field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
-    field public static final int ID_ZONED_FAN_POSITION = 16391; // 0x4007
-    field public static final int ID_ZONED_FAN_POSITION_AVAILABLE = 16390; // 0x4006
+    field public static final int ID_ZONED_FAN_DIRECTION = 16391; // 0x4007
+    field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 16390; // 0x4006
     field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
     field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
     field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 6f32dd7..d611932 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -1,82 +1,42 @@
 package android.car {
 
   public final class Car {
-    method public void connect() throws java.lang.IllegalStateException;
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection, android.os.Handler);
-    method public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection);
-    method public void disconnect();
-    method public int getCarConnectionType();
-    method public java.lang.Object getCarManager(java.lang.String) throws android.car.CarNotConnectedException;
-    method public boolean isConnected();
-    method public boolean isConnecting();
-    field public static final java.lang.String APP_FOCUS_SERVICE = "app_focus";
-    field public static final java.lang.String AUDIO_SERVICE = "audio";
     field public static final java.lang.String CABIN_SERVICE = "cabin";
-    field public static final java.lang.String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
-    field public static final java.lang.String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
-    field public static final int CONNECTION_TYPE_EMBEDDED = 5; // 0x5
+    field public static final java.lang.String CAR_DRIVING_STATE_SERVICE = "drivingstate";
     field public static final java.lang.String DIAGNOSTIC_SERVICE = "diagnostic";
     field public static final java.lang.String HVAC_SERVICE = "hvac";
-    field public static final java.lang.String INFO_SERVICE = "info";
-    field public static final java.lang.String PACKAGE_SERVICE = "package";
-    field public static final java.lang.String PERMISSION_CAR_CABIN = "android.car.permission.CAR_CABIN";
-    field public static final java.lang.String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
-    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.DIAGNOSTIC_CLEAR";
-    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.DIAGNOSTIC_READ_ALL";
-    field public static final java.lang.String PERMISSION_CAR_HVAC = "android.car.permission.CAR_HVAC";
+    field public static final java.lang.String PERMISSION_ADJUST_CAR_CABIN = "android.car.permission.ADJUST_CAR_CABIN";
+    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
+    field public static final java.lang.String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS";
+    field public static final java.lang.String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
+    field public static final java.lang.String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
+    field public static final java.lang.String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
+    field public static final java.lang.String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
+    field public static final java.lang.String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
     field public static final java.lang.String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
-    field public static final java.lang.String PERMISSION_CAR_RADIO = "android.car.permission.CAR_RADIO";
     field public static final java.lang.String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
     field public static final java.lang.String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
-    field public static final java.lang.String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
+    field public static final java.lang.String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
+    field public static final java.lang.String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
+    field public static final java.lang.String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS";
+    field public static final java.lang.String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS";
+    field public static final java.lang.String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
+    field public static final java.lang.String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+    field public static final java.lang.String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
     field public static final java.lang.String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
     field public static final deprecated java.lang.String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
-    field public static final java.lang.String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
-    field public static final java.lang.String PERMISSION_VEHICLE_DYNAMICS_STATE = "android.car.permission.VEHICLE_DYNAMICS_STATE";
+    field public static final java.lang.String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
+    field public static final java.lang.String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
     field public static final java.lang.String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
+    field public static final java.lang.String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
+    field public static final java.lang.String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
+    field public static final java.lang.String POWER_SERVICE = "power";
     field public static final java.lang.String PROJECTION_SERVICE = "projection";
-    field public static final java.lang.String RADIO_SERVICE = "radio";
-    field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String PROPERTY_SERVICE = "property";
+    field public static final java.lang.String STORAGE_MONITORING_SERVICE = "storage_monitoring";
     field public static final java.lang.String TEST_SERVICE = "car-service-test";
     field public static final java.lang.String VENDOR_EXTENSION_SERVICE = "vendor_extension";
-    field public static final int VERSION = 3; // 0x3
-  }
-
-  public final class CarAppFocusManager {
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int);
-    method public void abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback);
-    method public void addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int) throws android.car.CarNotConnectedException;
-    method public boolean isOwningFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback, int) throws android.car.CarNotConnectedException;
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener, int);
-    method public void removeFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener);
-    method public int requestAppFocus(int, android.car.CarAppFocusManager.OnAppFocusOwnershipCallback) throws android.car.CarNotConnectedException, java.lang.SecurityException;
-    field public static final int APP_FOCUS_REQUEST_FAILED = 0; // 0x0
-    field public static final int APP_FOCUS_REQUEST_SUCCEEDED = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_NAVIGATION = 1; // 0x1
-    field public static final int APP_FOCUS_TYPE_VOICE_COMMAND = 2; // 0x2
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusChangedListener {
-    method public abstract void onAppFocusChanged(int, boolean);
-  }
-
-  public static abstract interface CarAppFocusManager.OnAppFocusOwnershipCallback {
-    method public abstract void onAppFocusOwnershipGranted(int);
-    method public abstract void onAppFocusOwnershipLost(int);
-  }
-
-  public final class CarInfoManager {
-    method public java.lang.String getManufacturer() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModel() throws android.car.CarNotConnectedException;
-    method public java.lang.String getModelYear() throws android.car.CarNotConnectedException;
-    method public java.lang.String getVehicleId() throws android.car.CarNotConnectedException;
-  }
-
-  public class CarNotConnectedException extends java.lang.Exception {
-    ctor public CarNotConnectedException();
-    ctor public CarNotConnectedException(java.lang.String);
-    ctor public CarNotConnectedException(java.lang.String, java.lang.Throwable);
-    ctor public CarNotConnectedException(java.lang.Exception);
+    field public static final java.lang.String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
   }
 
   public final class CarProjectionManager {
@@ -93,16 +53,7 @@
     method public abstract void onVoiceAssistantRequest(boolean);
   }
 
-  public final class VehicleAreaType {
-    field public static final int VEHICLE_AREA_TYPE_DOOR = 4; // 0x4
-    field public static final int VEHICLE_AREA_TYPE_MIRROR = 5; // 0x5
-    field public static final int VEHICLE_AREA_TYPE_NONE = 0; // 0x0
-    field public static final int VEHICLE_AREA_TYPE_SEAT = 3; // 0x3
-    field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
-    field public static final int VEHICLE_AREA_TYPE_ZONE = 1; // 0x1
-  }
-
-  public final class VehicleDoor {
+  public final class VehicleAreaDoor {
     field public static final int DOOR_HOOD = 268435456; // 0x10000000
     field public static final int DOOR_REAR = 536870912; // 0x20000000
     field public static final int DOOR_ROW_1_LEFT = 1; // 0x1
@@ -113,13 +64,13 @@
     field public static final int DOOR_ROW_3_RIGHT = 1024; // 0x400
   }
 
-  public final class VehicleMirror {
+  public final class VehicleAreaMirror {
     field public static final int MIRROR_DRIVER_CENTER = 4; // 0x4
     field public static final int MIRROR_DRIVER_LEFT = 1; // 0x1
     field public static final int MIRROR_DRIVER_RIGHT = 2; // 0x2
   }
 
-  public final class VehicleSeat {
+  public final class VehicleAreaSeat {
     field public static final int SEAT_ROW_1_CENTER = 2; // 0x2
     field public static final int SEAT_ROW_1_LEFT = 1; // 0x1
     field public static final int SEAT_ROW_1_RIGHT = 4; // 0x4
@@ -131,149 +82,50 @@
     field public static final int SEAT_ROW_3_RIGHT = 1024; // 0x400
   }
 
-  public final class VehicleWindow {
+  public final class VehicleAreaType {
+    field public static final int VEHICLE_AREA_TYPE_DOOR = 4; // 0x4
+    field public static final int VEHICLE_AREA_TYPE_GLOBAL = 0; // 0x0
+    field public static final int VEHICLE_AREA_TYPE_MIRROR = 5; // 0x5
+    field public static final int VEHICLE_AREA_TYPE_SEAT = 3; // 0x3
+    field public static final int VEHICLE_AREA_TYPE_WHEEL = 6; // 0x6
+    field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
+  }
+
+  public final class VehicleAreaWheel {
+    field public static final int WHEEL_LEFT_FRONT = 1; // 0x1
+    field public static final int WHEEL_LEFT_REAR = 4; // 0x4
+    field public static final int WHEEL_RIGHT_FRONT = 2; // 0x2
+    field public static final int WHEEL_RIGHT_REAR = 8; // 0x8
+    field public static final int WHEEL_UNKNOWN = 0; // 0x0
+  }
+
+  public final class VehicleAreaWindow {
     field public static final int WINDOW_FRONT_WINDSHIELD = 1; // 0x1
     field public static final int WINDOW_REAR_WINDSHIELD = 2; // 0x2
-    field public static final int WINDOW_ROOF_TOP = 4; // 0x4
+    field public static final int WINDOW_ROOF_TOP_1 = 65536; // 0x10000
+    field public static final int WINDOW_ROOF_TOP_2 = 131072; // 0x20000
     field public static final int WINDOW_ROW_1_LEFT = 16; // 0x10
-    field public static final int WINDOW_ROW_1_RIGHT = 32; // 0x20
+    field public static final int WINDOW_ROW_1_RIGHT = 64; // 0x40
     field public static final int WINDOW_ROW_2_LEFT = 256; // 0x100
-    field public static final int WINDOW_ROW_2_RIGHT = 512; // 0x200
+    field public static final int WINDOW_ROW_2_RIGHT = 1024; // 0x400
     field public static final int WINDOW_ROW_3_LEFT = 4096; // 0x1000
-    field public static final int WINDOW_ROW_3_RIGHT = 8192; // 0x2000
-  }
-
-  public final class VehicleZone {
-    field public static final int ZONE_ALL = -2147483648; // 0x80000000
-    field public static final int ZONE_ROW_1_ALL = 8; // 0x8
-    field public static final int ZONE_ROW_1_CENTER = 2; // 0x2
-    field public static final int ZONE_ROW_1_LEFT = 1; // 0x1
-    field public static final int ZONE_ROW_1_RIGHT = 4; // 0x4
-    field public static final int ZONE_ROW_2_ALL = 128; // 0x80
-    field public static final int ZONE_ROW_2_CENTER = 32; // 0x20
-    field public static final int ZONE_ROW_2_LEFT = 16; // 0x10
-    field public static final int ZONE_ROW_2_RIGHT = 64; // 0x40
-    field public static final int ZONE_ROW_3_ALL = 2048; // 0x800
-    field public static final int ZONE_ROW_3_CENTER = 512; // 0x200
-    field public static final int ZONE_ROW_3_LEFT = 256; // 0x100
-    field public static final int ZONE_ROW_3_RIGHT = 1024; // 0x400
-    field public static final int ZONE_ROW_4_ALL = 32768; // 0x8000
-    field public static final int ZONE_ROW_4_CENTER = 8192; // 0x2000
-    field public static final int ZONE_ROW_4_LEFT = 4096; // 0x1000
-    field public static final int ZONE_ROW_4_RIGHT = 16384; // 0x4000
-  }
-
-  public final class VehicleZoneUtil {
-    method public static int getFirstZone(int);
-    method public static int getNextZone(int, int) throws java.lang.IllegalArgumentException;
-    method public static int getNumberOfZones(int);
-    method public static int[] listAllZones(int);
-    method public static int zoneToIndex(int, int) throws java.lang.IllegalArgumentException;
+    field public static final int WINDOW_ROW_3_RIGHT = 16384; // 0x4000
   }
 
 }
 
-package android.car.app.menu {
+package android.car.cluster {
 
-  public abstract class CarMenuCallbacks {
-    ctor public CarMenuCallbacks();
-    method public abstract android.car.app.menu.RootMenu getRootMenu(android.os.Bundle);
-    method public abstract void onCarMenuClosed();
-    method public abstract void onCarMenuClosing();
-    method public abstract void onCarMenuOpened();
-    method public abstract void onCarMenuOpening();
-    method public abstract void onItemClicked(java.lang.String);
-    method public abstract boolean onItemLongClicked(java.lang.String);
-    method public abstract boolean onMenuClicked();
-    method public abstract void subscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
-    method public abstract void unsubscribe(java.lang.String, android.car.app.menu.SubscriptionCallbacks);
+  public class CarInstrumentClusterManager {
+    method public void registerCallback(java.lang.String, android.car.cluster.CarInstrumentClusterManager.Callback) throws android.car.CarNotConnectedException;
+    method public void startActivity(android.content.Intent) throws android.car.CarNotConnectedException;
+    method public void unregisterCallback(android.car.cluster.CarInstrumentClusterManager.Callback) throws android.car.CarNotConnectedException;
+    field public static final java.lang.String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
+    field public static final java.lang.String KEY_EXTRA_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
   }
 
-  public class CarMenuConstants {
-    ctor public CarMenuConstants();
-  }
-
-  public static class CarMenuConstants.MenuItemConstants {
-    ctor public CarMenuConstants.MenuItemConstants();
-    field public static final int FLAG_BROWSABLE = 1; // 0x1
-    field public static final int FLAG_FIRSTITEM = 2; // 0x2
-    field public static final java.lang.String KEY_EMPTY_PLACEHOLDER = "android.car.app.menu.empty_placeholder";
-    field public static final java.lang.String KEY_FLAGS = "android.car.app.menu.flags";
-    field public static final java.lang.String KEY_ID = "android.car.app.menu.id";
-    field public static final java.lang.String KEY_LEFTICON = "android.car.app.menu.leftIcon";
-    field public static final java.lang.String KEY_REMOTEVIEWS = "android.car.app.menu.remoteViews";
-    field public static final java.lang.String KEY_RIGHTICON = "android.car.app.menu.rightIcon";
-    field public static final java.lang.String KEY_RIGHTTEXT = "android.car.app.menu.rightText";
-    field public static final java.lang.String KEY_TEXT = "android.car.app.menu.text";
-    field public static final java.lang.String KEY_TITLE = "android.car.app.menu.title";
-    field public static final java.lang.String KEY_WIDGET = "android.car.app.menu.widget";
-    field public static final java.lang.String KEY_WIDGET_STATE = "android.car.app.menu.widget_state";
-    field public static final int WIDGET_CHECKBOX = 1; // 0x1
-    field public static final int WIDGET_TEXT_VIEW = 2; // 0x2
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.MenuItemFlags implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class CarMenuConstants.MenuItemConstants.WidgetTypes implements java.lang.annotation.Annotation {
-  }
-
-  public abstract class CarUiEntry {
-    ctor public CarUiEntry(android.content.Context, android.content.Context);
-    method public abstract void closeDrawer();
-    method public abstract android.view.View getContentView();
-    method public abstract int getFragmentContainerId();
-    method public abstract java.lang.CharSequence getSearchBoxText();
-    method public abstract void hideMenuButton();
-    method public abstract void hideTitle();
-    method public abstract void onPause();
-    method public abstract void onRestoreInstanceState(android.os.Bundle);
-    method public abstract void onResume();
-    method public abstract void onSaveInstanceState(android.os.Bundle);
-    method public abstract void onStart();
-    method public abstract void onStop();
-    method public abstract void openDrawer();
-    method public abstract void restoreMenuDrawable();
-    method public abstract void setAutoLightDarkMode();
-    method public abstract void setBackground(android.graphics.Bitmap);
-    method public abstract void setCarMenuCallbacks(android.car.app.menu.CarMenuCallbacks);
-    method public abstract void setDarkMode();
-    method public abstract void setLightMode();
-    method public abstract void setMenuButtonBitmap(android.graphics.Bitmap);
-    method public abstract void setMenuButtonColor(int);
-    method public abstract void setScrimColor(int);
-    method public abstract void setSearchBoxColors(int, int, int, int);
-    method public abstract void setSearchBoxEditListener(android.car.app.menu.SearchBoxEditListener);
-    method public abstract void setSearchBoxEndView(android.view.View);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void showMenu(java.lang.String, java.lang.String);
-    method public abstract void showSearchBox(android.view.View.OnClickListener);
-    method public abstract void showTitle();
-    method public abstract void showToast(java.lang.String, long);
-    method public abstract android.widget.EditText startInput(java.lang.String, android.view.View.OnClickListener);
-    method public abstract void stopInput();
-    field protected final android.content.Context mAppContext;
-    field protected final android.content.Context mUiLibContext;
-  }
-
-  public class RootMenu {
-    ctor public RootMenu(java.lang.String);
-    ctor public RootMenu(java.lang.String, android.os.Bundle);
-    method public android.os.Bundle getBundle();
-    method public java.lang.String getId();
-  }
-
-  public abstract class SearchBoxEditListener {
-    ctor public SearchBoxEditListener();
-    method public abstract void onEdit(java.lang.String);
-    method public abstract void onSearch(java.lang.String);
-  }
-
-  public abstract class SubscriptionCallbacks {
-    ctor public SubscriptionCallbacks();
-    method public abstract void onChildChanged(java.lang.String, android.os.Bundle);
-    method public abstract void onChildrenLoaded(java.lang.String, java.util.List<android.os.Bundle>);
-    method public abstract void onError(java.lang.String);
+  public static abstract interface CarInstrumentClusterManager.Callback {
+    method public abstract void onClusterActivityStateChanged(java.lang.String, android.os.Bundle);
   }
 
 }
@@ -300,10 +152,7 @@
   public abstract class NavigationRenderer {
     ctor public NavigationRenderer();
     method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
-    method public abstract void onNextTurnChanged(int, java.lang.CharSequence, int, int, android.graphics.Bitmap, int);
-    method public abstract void onNextTurnDistanceChanged(int, int, int, int);
-    method public abstract void onStartNavigation();
-    method public abstract void onStopNavigation();
+    method public abstract void onEvent(int, android.os.Bundle);
   }
 
 }
@@ -344,9 +193,7 @@
   }
 
   public final class CarPackageManager {
-    method public boolean isActivityAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
     method public boolean isActivityBackedBySafeActivity(android.content.ComponentName) throws android.car.CarNotConnectedException;
-    method public boolean isServiceAllowedWhileDriving(java.lang.String, java.lang.String) throws android.car.CarNotConnectedException;
     method public void setAppBlockingPolicy(java.lang.String, android.car.content.pm.CarAppBlockingPolicy, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException, java.lang.SecurityException;
     field public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
     field public static final int FLAG_SET_POLICY_REMOVE = 4; // 0x4
@@ -485,6 +332,7 @@
     method public boolean isFreezeFrameNotificationSupported() throws android.car.CarNotConnectedException;
     method public boolean isGetFreezeFrameSupported() throws android.car.CarNotConnectedException;
     method public boolean isLiveFrameSupported() throws android.car.CarNotConnectedException;
+    method public boolean isSelectiveClearFreezeFramesSupported() throws android.car.CarNotConnectedException;
     method public void onCarDisconnected();
     method public boolean registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
     method public void unregisterListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener);
@@ -614,16 +462,49 @@
 
 }
 
+package android.car.drivingstate {
+
+  public class CarDrivingStateEvent implements android.os.Parcelable {
+    ctor public CarDrivingStateEvent(int, long);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.drivingstate.CarDrivingStateEvent> CREATOR;
+    field public static final int DRIVING_STATE_IDLING = 1; // 0x1
+    field public static final int DRIVING_STATE_MOVING = 2; // 0x2
+    field public static final int DRIVING_STATE_PARKED = 0; // 0x0
+    field public static final int DRIVING_STATE_UNKNOWN = -1; // 0xffffffff
+    field public final int eventValue;
+    field public final long timeStamp;
+  }
+
+  public final class CarDrivingStateManager {
+    method public android.car.drivingstate.CarDrivingStateEvent getCurrentCarDrivingState() throws android.car.CarNotConnectedException;
+    method public synchronized void registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
+    method public synchronized void unregisterListener() throws android.car.CarNotConnectedException;
+  }
+
+  public static abstract interface CarDrivingStateManager.CarDrivingStateEventListener {
+    method public abstract void onDrivingStateChanged(android.car.drivingstate.CarDrivingStateEvent);
+  }
+
+}
+
 package android.car.hardware {
 
   public class CarPropertyConfig<T> implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAccess();
     method public int getAreaCount();
     method public int[] getAreaIds();
     method public int getAreaType();
+    method public int getChangeMode();
+    method public java.util.List<java.lang.Integer> getConfigArray();
+    method public java.lang.String getConfigString();
     method public int getFirstAndOnlyAreaId();
+    method public float getMaxSampleRate();
     method public T getMaxValue(int);
     method public T getMaxValue();
+    method public float getMinSampleRate();
     method public T getMinValue(int);
     method public T getMinValue();
     method public int getPropertyId();
@@ -649,114 +530,37 @@
     method public android.car.hardware.CarPropertyConfig.Builder<T> addAreaConfig(int, T, T);
     method public android.car.hardware.CarPropertyConfig.Builder<T> addAreas(int[]);
     method public android.car.hardware.CarPropertyConfig<T> build();
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setAccess(int);
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setChangeMode(int);
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigArray(java.util.ArrayList<java.lang.Integer>);
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigString(java.lang.String);
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setMaxSampleRate(float);
+    method public android.car.hardware.CarPropertyConfig.Builder<T> setMinSampleRate(float);
   }
 
   public class CarPropertyValue<T> implements android.os.Parcelable {
-    ctor public CarPropertyValue(int, T);
     ctor public CarPropertyValue(int, int, T);
+    ctor public CarPropertyValue(int, int, int, long, T);
     ctor public CarPropertyValue(android.os.Parcel);
     method public int describeContents();
     method public int getAreaId();
     method public int getPropertyId();
+    method public int getStatus();
+    method public long getTimestamp();
     method public T getValue();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.car.hardware.CarPropertyValue> CREATOR;
   }
 
-  public class CarSensorEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.CarSensorEvent> CREATOR;
-    field public static final int DRIVE_STATUS_FULLY_RESTRICTED = 31; // 0x1f
-    field public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 16; // 0x10
-    field public static final int DRIVE_STATUS_NO_CONFIG = 8; // 0x8
-    field public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 2; // 0x2
-    field public static final int DRIVE_STATUS_NO_VIDEO = 1; // 0x1
-    field public static final int DRIVE_STATUS_NO_VOICE_INPUT = 4; // 0x4
-    field public static final int DRIVE_STATUS_UNRESTRICTED = 0; // 0x0
-    field public static final int GEAR_DRIVE = 100; // 0x64
-    field public static final int GEAR_EIGHTH = 8; // 0x8
-    field public static final int GEAR_FIFTH = 5; // 0x5
-    field public static final int GEAR_FIRST = 1; // 0x1
-    field public static final int GEAR_FOURTH = 4; // 0x4
-    field public static final int GEAR_NEUTRAL = 0; // 0x0
-    field public static final int GEAR_NINTH = 9; // 0x9
-    field public static final int GEAR_PARK = 101; // 0x65
-    field public static final int GEAR_REVERSE = 102; // 0x66
-    field public static final int GEAR_SECOND = 2; // 0x2
-    field public static final int GEAR_SEVENTH = 7; // 0x7
-    field public static final int GEAR_SIXTH = 6; // 0x6
-    field public static final int GEAR_TENTH = 10; // 0xa
-    field public static final int GEAR_THIRD = 3; // 0x3
-    field public static final int IGNITION_STATE_ACC = 3; // 0x3
-    field public static final int IGNITION_STATE_LOCK = 1; // 0x1
-    field public static final int IGNITION_STATE_OFF = 2; // 0x2
-    field public static final int IGNITION_STATE_ON = 4; // 0x4
-    field public static final int IGNITION_STATE_START = 5; // 0x5
-    field public static final int IGNITION_STATE_UNDEFINED = 0; // 0x0
-    field public static final int INDEX_ENVIRONMENT_PRESSURE = 1; // 0x1
-    field public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0; // 0x0
-    field public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1; // 0x1
-    field public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0; // 0x0
-    field public static final int INDEX_FUEL_LOW_WARNING = 0; // 0x0
-    field public static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1; // 0x1
-    field public static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2; // 0x2
-    field public static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4; // 0x4
-    field public static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3; // 0x3
-    field public static final int INDEX_WHEEL_DISTANCE_RESET_COUNT = 0; // 0x0
-    field public final float[] floatValues;
-    field public final int[] intValues;
-    field public final long[] longValues;
-    field public int sensorType;
-    field public long timestamp;
-  }
-
-  public static class CarSensorEvent.EnvironmentData {
-    field public float pressure;
-    field public float temperature;
-    field public long timestamp;
-  }
-
-  public final class CarSensorManager {
-    method public android.car.hardware.CarSensorEvent getLatestSensorEvent(int) throws android.car.CarNotConnectedException;
-    method public int[] getSupportedSensors() throws android.car.CarNotConnectedException;
-    method public boolean isSensorSupported(int) throws android.car.CarNotConnectedException;
-    method public static boolean isSensorSupported(int[], int);
-    method public boolean registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener);
-    method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int);
-    field public static final int SENSOR_RATE_FAST = 1; // 0x1
-    field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
-    field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
-    field public static final int SENSOR_RATE_UI = 2; // 0x2
-    field public static final int SENSOR_TYPE_ABS_ACTIVE = 24; // 0x18
-    field public static final int SENSOR_TYPE_CAR_SPEED = 2; // 0x2
-    field public static final int SENSOR_TYPE_DRIVING_STATUS = 11; // 0xb
-    field public static final int SENSOR_TYPE_ENVIRONMENT = 12; // 0xc
-    field public static final int SENSOR_TYPE_FUEL_LEVEL = 5; // 0x5
-    field public static final int SENSOR_TYPE_GEAR = 7; // 0x7
-    field public static final int SENSOR_TYPE_IGNITION_STATE = 22; // 0x16
-    field public static final int SENSOR_TYPE_NIGHT = 9; // 0x9
-    field public static final int SENSOR_TYPE_ODOMETER = 4; // 0x4
-    field public static final int SENSOR_TYPE_PARKING_BRAKE = 6; // 0x6
-    field public static final int SENSOR_TYPE_RPM = 3; // 0x3
-    field public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 25; // 0x19
-    field public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 1879048191; // 0x6fffffff
-    field public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 23; // 0x17
-  }
-
-  public static abstract interface CarSensorManager.OnSensorChangedListener {
-    method public abstract void onSensorChanged(android.car.hardware.CarSensorEvent);
-  }
-
   public final class CarVendorExtensionManager {
     method public <E> E getGlobalProperty(java.lang.Class<E>, int) throws android.car.CarNotConnectedException;
     method public java.util.List<android.car.hardware.CarPropertyConfig> getProperties() throws android.car.CarNotConnectedException;
     method public <E> E getProperty(java.lang.Class<E>, int, int) throws android.car.CarNotConnectedException;
+    method public boolean isPropertyAvailable(int, int) throws android.car.CarNotConnectedException;
     method public void registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
     method public <E> void setGlobalProperty(java.lang.Class<E>, int, E) throws android.car.CarNotConnectedException;
     method public <E> void setProperty(java.lang.Class<E>, int, int, E) throws android.car.CarNotConnectedException;
-    method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
+    method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
   }
 
   public static abstract interface CarVendorExtensionManager.CarVendorExtensionCallback {
@@ -778,48 +582,46 @@
     method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
     method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
     method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
-    method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
-    field public static final int ID_DOOR_LOCK = 3; // 0x3
-    field public static final int ID_DOOR_MOVE = 2; // 0x2
-    field public static final int ID_DOOR_POS = 1; // 0x1
-    field public static final int ID_MIRROR_FOLD = 4102; // 0x1006
-    field public static final int ID_MIRROR_LOCK = 4101; // 0x1005
-    field public static final int ID_MIRROR_Y_MOVE = 4100; // 0x1004
-    field public static final int ID_MIRROR_Y_POS = 4099; // 0x1003
-    field public static final int ID_MIRROR_Z_MOVE = 4098; // 0x1002
-    field public static final int ID_MIRROR_Z_POS = 4097; // 0x1001
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 8201; // 0x2009
-    field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 8200; // 0x2008
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 8203; // 0x200b
-    field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 8202; // 0x200a
-    field public static final int ID_SEAT_BELT_BUCKLED = 8195; // 0x2003
-    field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 8197; // 0x2005
-    field public static final int ID_SEAT_BELT_HEIGHT_POS = 8196; // 0x2004
-    field public static final int ID_SEAT_DEPTH_MOVE = 8207; // 0x200f
-    field public static final int ID_SEAT_DEPTH_POS = 8206; // 0x200e
-    field public static final int ID_SEAT_FORE_AFT_MOVE = 8199; // 0x2007
-    field public static final int ID_SEAT_FORE_AFT_POS = 8198; // 0x2006
-    field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 8217; // 0x2019
-    field public static final int ID_SEAT_HEADREST_ANGLE_POS = 8216; // 0x2018
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 8219; // 0x201b
-    field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 8218; // 0x201a
-    field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 8215; // 0x2017
-    field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 8214; // 0x2016
-    field public static final int ID_SEAT_HEIGHT_MOVE = 8205; // 0x200d
-    field public static final int ID_SEAT_HEIGHT_POS = 8204; // 0x200c
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 8211; // 0x2013
-    field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 8210; // 0x2012
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 8213; // 0x2015
-    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 8212; // 0x2014
-    field public static final int ID_SEAT_MEMORY_SELECT = 8193; // 0x2001
-    field public static final int ID_SEAT_MEMORY_SET = 8194; // 0x2002
-    field public static final int ID_SEAT_TILT_MOVE = 8209; // 0x2011
-    field public static final int ID_SEAT_TILT_POS = 8208; // 0x2010
-    field public static final int ID_WINDOW_LOCK = 12293; // 0x3005
-    field public static final int ID_WINDOW_MOVE = 12290; // 0x3002
-    field public static final int ID_WINDOW_POS = 12289; // 0x3001
-    field public static final int ID_WINDOW_VENT_MOVE = 12292; // 0x3004
-    field public static final int ID_WINDOW_VENT_POS = 12291; // 0x3003
+    method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) throws android.car.CarNotConnectedException;
+    field public static final int ID_DOOR_LOCK = 371198722; // 0x16200b02
+    field public static final int ID_DOOR_MOVE = 373295873; // 0x16400b01
+    field public static final int ID_DOOR_POS = 373295872; // 0x16400b00
+    field public static final int ID_MIRROR_FOLD = 287312709; // 0x11200b45
+    field public static final int ID_MIRROR_LOCK = 287312708; // 0x11200b44
+    field public static final int ID_MIRROR_Y_MOVE = 339741507; // 0x14400b43
+    field public static final int ID_MIRROR_Y_POS = 339741506; // 0x14400b42
+    field public static final int ID_MIRROR_Z_MOVE = 339741505; // 0x14400b41
+    field public static final int ID_MIRROR_Z_POS = 339741504; // 0x14400b40
+    field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
+    field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
+    field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
+    field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 356518793; // 0x15400b89
+    field public static final int ID_SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
+    field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
+    field public static final int ID_SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+    field public static final int ID_SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
+    field public static final int ID_SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+    field public static final int ID_SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
+    field public static final int ID_SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
+    field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
+    field public static final int ID_SEAT_HEADREST_ANGLE_POS = 356518807; // 0x15400b97
+    field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 356518810; // 0x15400b9a
+    field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 356518809; // 0x15400b99
+    field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 356518806; // 0x15400b96
+    field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 356518805; // 0x15400b95
+    field public static final int ID_SEAT_HEIGHT_MOVE = 356518796; // 0x15400b8c
+    field public static final int ID_SEAT_HEIGHT_POS = 356518795; // 0x15400b8b
+    field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 356518802; // 0x15400b92
+    field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
+    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
+    field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+    field public static final int ID_SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
+    field public static final int ID_SEAT_MEMORY_SET = 356518785; // 0x15400b81
+    field public static final int ID_SEAT_TILT_MOVE = 356518800; // 0x15400b90
+    field public static final int ID_SEAT_TILT_POS = 356518799; // 0x15400b8f
+    field public static final int ID_WINDOW_LOCK = 322964420; // 0x13400bc4
+    field public static final int ID_WINDOW_MOVE = 322964417; // 0x13400bc1
+    field public static final int ID_WINDOW_POS = 322964416; // 0x13400bc0
   }
 
   public static abstract interface CarCabinManager.CarCabinEventCallback {
@@ -836,37 +638,35 @@
     method public float getFloatProperty(int, int) throws android.car.CarNotConnectedException;
     method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
     method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
-    method public static boolean isZonedProperty(int);
+    method public boolean isPropertyAvailable(int, int) throws android.car.CarNotConnectedException;
     method public synchronized void registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) throws android.car.CarNotConnectedException;
     method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
     method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
     method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
     method public synchronized void unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
-    field public static final int FAN_POSITION_DEFROST = 4; // 0x4
-    field public static final int FAN_POSITION_DEFROST_AND_FLOOR = 5; // 0x5
-    field public static final int FAN_POSITION_FACE = 1; // 0x1
-    field public static final int FAN_POSITION_FACE_AND_FLOOR = 3; // 0x3
-    field public static final int FAN_POSITION_FLOOR = 2; // 0x2
-    field public static final int ID_MIRROR_DEFROSTER_ON = 1; // 0x1
-    field public static final int ID_OUTSIDE_AIR_TEMP = 3; // 0x3
-    field public static final int ID_STEERING_WHEEL_TEMP = 2; // 0x2
-    field public static final int ID_TEMPERATURE_UNITS = 4; // 0x4
-    field public static final int ID_WINDOW_DEFROSTER_ON = 20481; // 0x5001
-    field public static final int ID_ZONED_AC_ON = 16393; // 0x4009
-    field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
-    field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
-    field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
-    field public static final int ID_ZONED_FAN_POSITION = 16391; // 0x4007
-    field public static final int ID_ZONED_FAN_POSITION_AVAILABLE = 16390; // 0x4006
-    field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
-    field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
-    field public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 16399; // 0x400f
-    field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
-    field public static final int ID_ZONED_MAX_AC_ON = 16396; // 0x400c
-    field public static final int ID_ZONED_MAX_DEFROST_ON = 16398; // 0x400e
-    field public static final int ID_ZONED_SEAT_TEMP = 16392; // 0x4008
-    field public static final int ID_ZONED_TEMP_ACTUAL = 16386; // 0x4002
-    field public static final int ID_ZONED_TEMP_SETPOINT = 16385; // 0x4001
+    field public static final int FAN_DIRECTION_DEFROST = 4; // 0x4
+    field public static final int FAN_DIRECTION_FACE = 1; // 0x1
+    field public static final int FAN_DIRECTION_FLOOR = 2; // 0x2
+    field public static final int ID_MIRROR_DEFROSTER_ON = 339739916; // 0x1440050c
+    field public static final int ID_OUTSIDE_AIR_TEMP = 291505923; // 0x11600703
+    field public static final int ID_STEERING_WHEEL_HEAT = 289408269; // 0x1140050d
+    field public static final int ID_TEMPERATURE_DISPLAY_UNITS = 289408270; // 0x1140050e
+    field public static final int ID_WINDOW_DEFROSTER_ON = 320865540; // 0x13200504
+    field public static final int ID_ZONED_AC_ON = 354419973; // 0x15200505
+    field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 354419976; // 0x15200508
+    field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 354419978; // 0x1520050a
+    field public static final int ID_ZONED_DUAL_ZONE_ON = 354419977; // 0x15200509
+    field public static final int ID_ZONED_FAN_DIRECTION = 356517121; // 0x15400501
+    field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 356582673; // 0x15410511
+    field public static final int ID_ZONED_FAN_SPEED_RPM = 356517135; // 0x1540050f
+    field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 356517120; // 0x15400500
+    field public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 354419986; // 0x15200512
+    field public static final int ID_ZONED_HVAC_POWER_ON = 354419984; // 0x15200510
+    field public static final int ID_ZONED_MAX_AC_ON = 354419974; // 0x15200506
+    field public static final int ID_ZONED_MAX_DEFROST_ON = 354419975; // 0x15200507
+    field public static final int ID_ZONED_SEAT_TEMP = 356517131; // 0x1540050b
+    field public static final int ID_ZONED_TEMP_ACTUAL = 358614274; // 0x15600502
+    field public static final int ID_ZONED_TEMP_SETPOINT = 358614275; // 0x15600503
   }
 
   public static abstract interface CarHvacManager.CarHvacEventCallback {
@@ -876,39 +676,22 @@
 
 }
 
-package android.car.hardware.radio {
+package android.car.hardware.power {
 
-  public class CarRadioEvent implements android.os.Parcelable {
-    ctor public CarRadioEvent(int, android.car.hardware.radio.CarRadioPreset);
-    method public int describeContents();
-    method public int getEventType();
-    method public android.car.hardware.radio.CarRadioPreset getPreset();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioEvent> CREATOR;
-    field public static final int RADIO_PRESET = 0; // 0x0
+  public class CarPowerManager {
+    field public static final int BOOT_REASON_DOOR_OPEN = 4; // 0x4
+    field public static final int BOOT_REASON_DOOR_UNLOCK = 2; // 0x2
+    field public static final int BOOT_REASON_REMOTE_START = 5; // 0x5
+    field public static final int BOOT_REASON_TIMER = 3; // 0x3
+    field public static final int BOOT_REASON_USER_POWER_ON = 1; // 0x1
   }
 
-  public final class CarRadioManager {
-    method public android.car.hardware.radio.CarRadioPreset getPreset(int) throws android.car.CarNotConnectedException;
-    method public int getPresetCount() throws android.car.CarNotConnectedException;
-    method public synchronized void registerListener(android.car.hardware.radio.CarRadioManager.CarRadioEventListener) throws android.car.CarNotConnectedException;
-    method public boolean setPreset(android.car.hardware.radio.CarRadioPreset) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public synchronized void unregisterListener();
-  }
-
-  public static abstract interface CarRadioManager.CarRadioEventListener {
-    method public abstract void onEvent(android.car.hardware.radio.CarRadioEvent);
-  }
-
-  public class CarRadioPreset implements android.os.Parcelable {
-    ctor public CarRadioPreset(int, int, int, int);
-    method public int describeContents();
-    method public int getBand();
-    method public int getChannel();
-    method public int getPresetNumber();
-    method public int getSubChannel();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.car.hardware.radio.CarRadioPreset> CREATOR;
+  public static abstract interface CarPowerManager.CarPowerStateListener {
+    method public abstract void onStateChanged(int);
+    field public static final int SHUTDOWN_CANCELLED = 0; // 0x0
+    field public static final int SHUTDOWN_ENTER = 1; // 0x1
+    field public static final int SUSPEND_ENTER = 2; // 0x2
+    field public static final int SUSPEND_EXIT = 3; // 0x3
   }
 
 }
@@ -937,27 +720,22 @@
 package android.car.media {
 
   public final class CarAudioManager {
-    method public void abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
-    method public android.media.AudioAttributes getAudioAttributesForCarUsage(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMaxVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamMinVolume(int) throws android.car.CarNotConnectedException;
-    method public int getStreamVolume(int) throws android.car.CarNotConnectedException;
-    method public boolean isMediaMuted() throws android.car.CarNotConnectedException;
-    method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
-    method public boolean setMediaMute(boolean) throws android.car.CarNotConnectedException;
-    method public void setStreamVolume(int, int, int) throws android.car.CarNotConnectedException;
-    method public void setVolumeController(android.media.IVolumeController) throws android.car.CarNotConnectedException;
-    field public static final int CAR_AUDIO_USAGE_ALARM = 6; // 0x6
-    field public static final int CAR_AUDIO_USAGE_DEFAULT = 0; // 0x0
-    field public static final int CAR_AUDIO_USAGE_MUSIC = 1; // 0x1
-    field public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3; // 0x3
-    field public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7; // 0x7
-    field public static final int CAR_AUDIO_USAGE_RADIO = 2; // 0x2
-    field public static final int CAR_AUDIO_USAGE_RINGTONE = 10; // 0xa
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9; // 0x9
-    field public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8; // 0x8
-    field public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4; // 0x4
-    field public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5; // 0x5
+    method public android.car.media.CarAudioPatchHandle createAudioPatch(java.lang.String, int, int) throws android.car.CarNotConnectedException;
+    method public java.lang.String[] getExternalSources() throws android.car.CarNotConnectedException;
+    method public int getGroupMaxVolume(int) throws android.car.CarNotConnectedException;
+    method public int getGroupMinVolume(int) throws android.car.CarNotConnectedException;
+    method public int getGroupVolume(int) throws android.car.CarNotConnectedException;
+    method public int[] getUsagesForVolumeGroupId(int) throws android.car.CarNotConnectedException;
+    method public int getVolumeGroupCount() throws android.car.CarNotConnectedException;
+    method public int getVolumeGroupIdForUsage(int) throws android.car.CarNotConnectedException;
+    method public void registerVolumeCallback(android.os.IBinder) throws android.car.CarNotConnectedException;
+    method public void registerVolumeChangeObserver(android.database.ContentObserver);
+    method public void releaseAudioPatch(android.car.media.CarAudioPatchHandle) throws android.car.CarNotConnectedException;
+    method public void setBalanceTowardRight(float) throws android.car.CarNotConnectedException;
+    method public void setFadeTowardFront(float) throws android.car.CarNotConnectedException;
+    method public void setGroupVolume(int, int, int) throws android.car.CarNotConnectedException;
+    method public void unregisterVolumeCallback(android.os.IBinder) throws android.car.CarNotConnectedException;
+    method public void unregisterVolumeChangeObserver(android.database.ContentObserver);
   }
 
 }
@@ -983,17 +761,128 @@
 
 }
 
-package android.car.settings {
+package android.car.storagemonitoring {
 
-  public class CarSettings {
-    ctor public CarSettings();
+  public final class CarStorageMonitoringManager {
+    method public java.util.List<android.car.storagemonitoring.IoStatsEntry> getAggregateIoStats() throws android.car.CarNotConnectedException;
+    method public java.util.List<android.car.storagemonitoring.IoStatsEntry> getBootIoStats() throws android.car.CarNotConnectedException;
+    method public java.util.List<android.car.storagemonitoring.IoStats> getIoStatsDeltas() throws android.car.CarNotConnectedException;
+    method public int getPreEolIndicatorStatus() throws android.car.CarNotConnectedException;
+    method public long getShutdownDiskWriteAmount() throws android.car.CarNotConnectedException;
+    method public android.car.storagemonitoring.WearEstimate getWearEstimate() throws android.car.CarNotConnectedException;
+    method public java.util.List<android.car.storagemonitoring.WearEstimateChange> getWearEstimateHistory() throws android.car.CarNotConnectedException;
+    method public void registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener) throws android.car.CarNotConnectedException;
+    method public void unregisterListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener) throws android.car.CarNotConnectedException;
+    field public static final java.lang.String INTENT_EXCESSIVE_IO = "android.car.storagemonitoring.EXCESSIVE_IO";
+    field public static final int PRE_EOL_INFO_NORMAL = 1; // 0x1
+    field public static final int PRE_EOL_INFO_UNKNOWN = 0; // 0x0
+    field public static final int PRE_EOL_INFO_URGENT = 3; // 0x3
+    field public static final int PRE_EOL_INFO_WARNING = 2; // 0x2
+    field public static final long SHUTDOWN_COST_INFO_MISSING = -1L; // 0xffffffffffffffffL
   }
 
-  public static final class CarSettings.Global {
-    ctor public CarSettings.Global();
-    field public static final java.lang.String KEY_GARAGE_MODE_ENABLED = "android.car.GARAGE_MODE_ENABLED";
-    field public static final java.lang.String KEY_GARAGE_MODE_MAINTENANCE_WINDOW = "android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
-    field public static final java.lang.String KEY_GARAGE_MODE_WAKE_UP_TIME = "android.car.GARAGE_MODE_WAKE_UP_TIME";
+  public static abstract interface CarStorageMonitoringManager.IoStatsListener {
+    method public abstract void onSnapshot(android.car.storagemonitoring.IoStats);
+  }
+
+  public class IoStats implements android.os.Parcelable {
+    ctor public IoStats(java.util.List<android.car.storagemonitoring.IoStatsEntry>, long);
+    ctor public IoStats(android.os.Parcel);
+    ctor public IoStats(org.json.JSONObject) throws org.json.JSONException;
+    method public int describeContents();
+    method public android.car.storagemonitoring.IoStatsEntry.Metrics getBackgroundTotals();
+    method public android.car.storagemonitoring.IoStatsEntry.Metrics getForegroundTotals();
+    method public java.util.List<android.car.storagemonitoring.IoStatsEntry> getStats();
+    method public long getTimestamp();
+    method public android.car.storagemonitoring.IoStatsEntry.Metrics getTotals();
+    method public android.car.storagemonitoring.IoStatsEntry getUserIdStats(int);
+    method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStats> CREATOR;
+  }
+
+  public final class IoStatsEntry implements android.os.Parcelable {
+    ctor public IoStatsEntry(int, long, android.car.storagemonitoring.IoStatsEntry.Metrics, android.car.storagemonitoring.IoStatsEntry.Metrics);
+    ctor public IoStatsEntry(android.os.Parcel);
+    ctor public IoStatsEntry(android.car.storagemonitoring.UidIoRecord, long);
+    ctor public IoStatsEntry(org.json.JSONObject) throws org.json.JSONException;
+    method public int describeContents();
+    method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStatsEntry> CREATOR;
+    field public final android.car.storagemonitoring.IoStatsEntry.Metrics background;
+    field public final android.car.storagemonitoring.IoStatsEntry.Metrics foreground;
+    field public final long runtimeMillis;
+    field public final int uid;
+  }
+
+  public static final class IoStatsEntry.Metrics implements android.os.Parcelable {
+    ctor public IoStatsEntry.Metrics(long, long, long, long, long);
+    ctor public IoStatsEntry.Metrics(android.os.Parcel);
+    ctor public IoStatsEntry.Metrics(org.json.JSONObject) throws org.json.JSONException;
+    method public int describeContents();
+    method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStatsEntry.Metrics> CREATOR;
+    field public final long bytesRead;
+    field public final long bytesReadFromStorage;
+    field public final long bytesWritten;
+    field public final long bytesWrittenToStorage;
+    field public final long fsyncCalls;
+  }
+
+  public class LifetimeWriteInfo implements android.os.Parcelable {
+    ctor public LifetimeWriteInfo(java.lang.String, java.lang.String, long);
+    ctor public LifetimeWriteInfo(android.os.Parcel);
+    ctor public LifetimeWriteInfo(org.json.JSONObject) throws org.json.JSONException;
+    method public int describeContents();
+    method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStats> CREATOR;
+    field public final java.lang.String fstype;
+    field public final java.lang.String partition;
+    field public final long writtenBytes;
+  }
+
+  public final class UidIoRecord {
+    ctor public UidIoRecord(int, long, long, long, long, long, long, long, long, long, long);
+    field public final long background_fsync;
+    field public final long background_rchar;
+    field public final long background_read_bytes;
+    field public final long background_wchar;
+    field public final long background_write_bytes;
+    field public final long foreground_fsync;
+    field public final long foreground_rchar;
+    field public final long foreground_read_bytes;
+    field public final long foreground_wchar;
+    field public final long foreground_write_bytes;
+    field public final int uid;
+  }
+
+  public class WearEstimate implements android.os.Parcelable {
+    ctor public WearEstimate(int, int);
+    ctor public WearEstimate(android.os.Parcel);
+    ctor public WearEstimate(android.util.JsonReader) throws java.io.IOException;
+    method public int describeContents();
+    method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.WearEstimate> CREATOR;
+    field public static final int UNKNOWN = -1; // 0xffffffff
+    field public final int typeA;
+    field public final int typeB;
+  }
+
+  public class WearEstimateChange implements android.os.Parcelable {
+    ctor public WearEstimateChange(android.car.storagemonitoring.WearEstimate, android.car.storagemonitoring.WearEstimate, long, java.time.Instant, boolean);
+    ctor public WearEstimateChange(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.WearEstimateChange> CREATOR;
+    field public final java.time.Instant dateAtChange;
+    field public final boolean isAcceptableDegradation;
+    field public final android.car.storagemonitoring.WearEstimate newEstimate;
+    field public final android.car.storagemonitoring.WearEstimate oldEstimate;
+    field public final long uptimeAtChange;
   }
 
 }
@@ -1008,3 +897,95 @@
 
 }
 
+package android.car.vms {
+
+  public final class VmsAvailableLayers implements android.os.Parcelable {
+    ctor public VmsAvailableLayers(java.util.Set<android.car.vms.VmsAssociatedLayer>, int);
+    method public int describeContents();
+    method public java.util.Set<android.car.vms.VmsAssociatedLayer> getAssociatedLayers();
+    method public int getSequence();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.vms.VmsAvailableLayers> CREATOR;
+  }
+
+  public final class VmsLayer implements android.os.Parcelable {
+    ctor public VmsLayer(int, int, int);
+    method public int describeContents();
+    method public int getSubtype();
+    method public int getType();
+    method public int getVersion();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayer> CREATOR;
+  }
+
+  public final class VmsLayerDependency implements android.os.Parcelable {
+    ctor public VmsLayerDependency(android.car.vms.VmsLayer, java.util.Set<android.car.vms.VmsLayer>);
+    ctor public VmsLayerDependency(android.car.vms.VmsLayer);
+    method public int describeContents();
+    method public java.util.Set<android.car.vms.VmsLayer> getDependencies();
+    method public android.car.vms.VmsLayer getLayer();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayerDependency> CREATOR;
+  }
+
+  public final class VmsLayersOffering implements android.os.Parcelable {
+    ctor public VmsLayersOffering(java.util.Set<android.car.vms.VmsLayerDependency>, int);
+    method public int describeContents();
+    method public java.util.Set<android.car.vms.VmsLayerDependency> getDependencies();
+    method public int getPublisherId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.car.vms.VmsLayersOffering> CREATOR;
+  }
+
+  public final class VmsOperationRecorder {
+    ctor public VmsOperationRecorder(android.car.vms.VmsOperationRecorder.Writer);
+    method public void addHalSubscription(int, android.car.vms.VmsLayer);
+    method public void addPromiscuousSubscription(int);
+    method public void addSubscription(int, android.car.vms.VmsLayer);
+    method public static android.car.vms.VmsOperationRecorder get();
+    method public void getPublisherId(int);
+    method public void removeHalSubscription(int, android.car.vms.VmsLayer);
+    method public void removePromiscuousSubscription(int);
+    method public void removeSubscription(int, android.car.vms.VmsLayer);
+    method public void setHalPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+    method public void setLayersOffering(android.car.vms.VmsLayersOffering);
+    method public void setPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+    method public void startMonitoring();
+    method public void stopMonitoring();
+    method public void subscribe(android.car.vms.VmsLayer);
+    method public void subscribe(android.car.vms.VmsLayer, int);
+    method public void unsubscribe(android.car.vms.VmsLayer);
+    method public void unsubscribe(android.car.vms.VmsLayer, int);
+  }
+
+  public abstract class VmsPublisherClientService extends android.app.Service {
+    ctor public VmsPublisherClientService();
+    method public final int getPublisherId(byte[]);
+    method public final android.car.vms.VmsSubscriptionState getSubscriptions();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method protected abstract void onVmsPublisherServiceReady();
+    method public abstract void onVmsSubscriptionChange(android.car.vms.VmsSubscriptionState);
+    method public final void publish(android.car.vms.VmsLayer, int, byte[]);
+    method public final void setLayersOffering(android.car.vms.VmsLayersOffering);
+  }
+
+  public final class VmsSubscriberManager {
+    method public void clearVmsSubscriberClientCallback() throws android.car.CarNotConnectedException;
+    method public android.car.vms.VmsAvailableLayers getAvailableLayers() throws android.car.CarNotConnectedException, java.lang.IllegalStateException;
+    method public byte[] getPublisherInfo(int) throws android.car.CarNotConnectedException, java.lang.IllegalStateException;
+    method public void setVmsSubscriberClientCallback(java.util.concurrent.Executor, android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback) throws android.car.CarNotConnectedException;
+    method public void startMonitoring() throws android.car.CarNotConnectedException;
+    method public void stopMonitoring();
+    method public void subscribe(android.car.vms.VmsLayer) throws android.car.CarNotConnectedException;
+    method public void subscribe(android.car.vms.VmsLayer, int) throws android.car.CarNotConnectedException;
+    method public void unsubscribe(android.car.vms.VmsLayer);
+    method public void unsubscribe(android.car.vms.VmsLayer, int);
+  }
+
+  public static abstract interface VmsSubscriberManager.VmsSubscriberClientCallback {
+    method public abstract void onLayersAvailabilityChanged(android.car.vms.VmsAvailableLayers);
+    method public abstract void onVmsMessageReceived(android.car.vms.VmsLayer, byte[]);
+  }
+
+}
+
diff --git a/car-lib/native/CarPowerManager/CarPowerManager.cpp b/car-lib/native/CarPowerManager/CarPowerManager.cpp
new file mode 100644
index 0000000..856f6cd
--- /dev/null
+++ b/car-lib/native/CarPowerManager/CarPowerManager.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "CarPowerManagerNative"
+
+#include <binder/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <utils/Log.h>
+
+#include "CarPowerManager.h"
+
+namespace android {
+namespace car {
+namespace hardware {
+namespace power {
+
+// Public functions
+int CarPowerManager::clearListener() {
+    int retVal = -1;
+
+    if (mIsConnected && (mListenerToService != nullptr)) {
+        mICarPower->unregisterListener(mListenerToService);
+        mListenerToService = nullptr;
+        retVal = 0;
+    }
+    return retVal;
+}
+
+int CarPowerManager::getBootReason(BootReason *bootReason) {
+    int retVal = -1;
+
+    if ((bootReason != nullptr) && connectToCarService()) {
+        int reason = -1;
+        mICarPower->getBootReason(&reason);
+
+        if ((reason >= static_cast<int>(BootReason::kFirst)) &&
+            (reason <= static_cast<int>(BootReason::kLast))) {
+            *bootReason = static_cast<BootReason>(reason);
+            retVal = 0;
+        } else {
+            ALOGE("Received unknown bootReason = %d", reason);
+        }
+    }
+    return retVal;
+}
+
+int CarPowerManager::requestShutdownOnNextSuspend() {
+    int retVal = -1;
+
+    if (connectToCarService()) {
+        mICarPower->requestShutdownOnNextSuspend();
+        retVal = 0;
+    }
+    return retVal;
+}
+
+int CarPowerManager::setListener(Listener listener) {
+    int retVal = -1;
+
+    if (connectToCarService()) {
+        if (mListenerToService == nullptr) {
+            mListenerToService = new CarPowerStateListener(this);
+            mICarPower->registerListener(mListenerToService);
+        }
+
+        // Set the listener
+        mListener = listener;
+        retVal = 0;
+    }
+    return retVal;
+}
+
+
+// Private functions
+bool CarPowerManager::connectToCarService() {
+    if (mIsConnected) {
+        // Service is already connected
+        return true;
+    }
+
+    const String16 ICarName("car_service");
+    const String16 ICarPowerName("power");
+
+    ALOGI("Connecting to CarService" LOG_TAG);
+
+    // Get ICar
+    sp<IServiceManager> serviceManager = defaultServiceManager();
+    if (serviceManager == nullptr) {
+        ALOGE("Cannot get defaultServiceManager");
+        return(false);
+    }
+
+    sp<IBinder> binder = (serviceManager->getService(ICarName));
+    if (binder == nullptr) {
+        ALOGE("Cannot get ICar");
+        return false;
+    }
+
+    // Get ICarPower
+    sp<ICar> iCar = interface_cast<ICar>(binder);
+    if (iCar == nullptr) {
+        ALOGW("car service unavailable");
+        return false;
+    }
+
+    iCar->getCarService(ICarPowerName, &binder);
+    if (binder == nullptr) {
+        ALOGE("Cannot get ICarPower");
+        return false;
+    }
+
+    mICarPower = interface_cast<ICarPower>(binder);
+    if (mICarPower == nullptr) {
+        ALOGW("car power management service unavailable");
+        return false;
+    }
+    mIsConnected = true;
+    return true;
+}
+
+
+} // namespace power
+} // namespace hardware
+} // namespace car
+} // namespace android
+
diff --git a/car-lib/native/include/CarPowerManager.h b/car-lib/native/include/CarPowerManager.h
new file mode 100644
index 0000000..aa31030
--- /dev/null
+++ b/car-lib/native/include/CarPowerManager.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef CAR_POWER_MANAGER
+#define CAR_POWER_MANAGER
+
+#include <binder/Status.h>
+#include <utils/RefBase.h>
+
+#include "android/car/ICar.h"
+#include "android/car/hardware/power/BnCarPowerStateListener.h"
+#include "android/car/hardware/power/ICarPower.h"
+
+using android::binder::Status;
+
+namespace android {
+namespace car {
+namespace hardware {
+namespace power {
+
+
+class CarPowerManager : public RefBase {
+public:
+    // Enumeration of possible boot reasons
+    //  NOTE:  The entries in this enum must match the ones in located CarPowerManager java class:
+    //      packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerManager.java
+    enum class BootReason {
+        kUserPowerOn = 1,
+        kDoorUnlock = 2,
+        kTimer = 3,
+        kDoorOpen = 4,
+        kRemoteStart = 5,
+
+        kFirst = kUserPowerOn,
+        kLast = kRemoteStart,
+    };
+
+    // Enumeration of state change events
+    //  NOTE:  The entries in this enum must match the ones in CarPowerStateListener located in
+    //      packages/services/Car/car-lib/src/android/car/hardware/power/CarPowerManager.java
+    enum class State {
+        kShutdownCancelled = 0,
+        kShutdownEnter = 1,
+        kSuspendEnter = 2,
+        kSuspendExit = 3,
+
+        kFirst = kShutdownCancelled,
+        kLast = kSuspendExit,
+    };
+
+    using Listener = std::function<void(State)>;
+
+    CarPowerManager() = default;
+    virtual ~CarPowerManager() = default;
+
+    // Removes the listener and turns off callbacks
+    //  Returns 0 on success
+    int clearListener();
+
+    // Returns the boot reason, defined in kBootReason*
+    //  Returns 0 on success
+    int getBootReason(BootReason *bootReason);
+
+    // Request device to shutdown in lieu of suspend at the next opportunity
+    //  Returns 0 on success
+    int requestShutdownOnNextSuspend();
+
+    // Set the callback function.  This will execute in the binder thread.
+    //  Returns 0 on success
+    int setListener(Listener listener);
+
+private:
+    class CarPowerStateListener final : public BnCarPowerStateListener {
+    public:
+        explicit CarPowerStateListener(CarPowerManager* parent) : mParent(parent) {};
+
+        Status onStateChanged(int state, int token) override {
+            sp<CarPowerManager> parent = mParent.promote();
+            if ((parent != nullptr) && (parent->mListener != nullptr)) {
+                if ((state >= static_cast<int>(State::kFirst)) &&
+                    (state <= static_cast<int>(State::kLast))) {
+                    parent->mListener(static_cast<State>(state));
+                } else {
+                    ALOGE("onStateChanged unknown state received = %d", state);
+                }
+            }
+
+            if (token != 0) {
+                // Call finished() method to let CPMS know that we're ready to suspend/shutdown.
+                parent->mICarPower->finished(parent->mListenerToService, token);
+            }
+            return binder::Status::ok();
+        };
+
+    private:
+        wp<CarPowerManager> mParent;
+    };
+
+    bool connectToCarService();
+
+    sp<ICarPower> mICarPower;
+    bool mIsConnected;
+    Listener mListener;
+    sp<CarPowerStateListener> mListenerToService;
+};
+
+} // namespace power
+} // namespace hardware
+} // namespace car
+} // namespace android
+
+#endif // CAR_POWER_MANAGER
+
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index c0b83f7..738a423 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -19,18 +19,21 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.car.annotation.FutureFeature;
 import android.car.cluster.CarInstrumentClusterManager;
 import android.car.content.pm.CarPackageManager;
 import android.car.diagnostic.CarDiagnosticManager;
+import android.car.drivingstate.CarDrivingStateManager;
+import android.car.drivingstate.CarUxRestrictionsManager;
 import android.car.hardware.CarSensorManager;
 import android.car.hardware.CarVendorExtensionManager;
 import android.car.hardware.cabin.CarCabinManager;
 import android.car.hardware.hvac.CarHvacManager;
-import android.car.hardware.radio.CarRadioManager;
+import android.car.hardware.power.CarPowerManager;
+import android.car.hardware.property.CarPropertyManager;
 import android.car.media.CarAudioManager;
 import android.car.navigation.CarNavigationStatusManager;
-import android.car.CarBluetoothManager;
+import android.car.settings.CarConfigurationManager;
+import android.car.storagemonitoring.CarStorageMonitoringManager;
 import android.car.test.CarTestManagerBinderWrapper;
 import android.car.vms.VmsSubscriberManager;
 import android.content.ComponentName;
@@ -45,7 +48,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.car.internal.FeatureConfiguration;
 import com.android.internal.annotations.GuardedBy;
 
 import java.lang.annotation.Retention;
@@ -82,11 +84,9 @@
     /** Service name for {@link CarAudioManager} */
     public static final String AUDIO_SERVICE = "audio";
 
-    /**
-     * Service name for {@link CarNavigationStatusManager}
-     * @hide
-     */
+    /** Service name for {@link CarNavigationStatusManager} */
     public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
+
     /**
      * Service name for {@link CarInstrumentClusterManager}
      * @hide
@@ -109,24 +109,30 @@
      * @hide
      */
     @SystemApi
-    public static final String RADIO_SERVICE = "radio";
-
-    /**
-     * @hide
-     */
-    @SystemApi
     public static final String HVAC_SERVICE = "hvac";
 
     /**
      * @hide
      */
     @SystemApi
+    public static final String POWER_SERVICE = "power";
+
+    /**
+     * @hide
+     */
+    @SystemApi
     public static final String PROJECTION_SERVICE = "projection";
 
     /**
      * @hide
      */
     @SystemApi
+    public static final String PROPERTY_SERVICE = "property";
+
+    /**
+     * @hide
+     */
+    @SystemApi
     public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
 
     /**
@@ -135,12 +141,35 @@
     public static final String BLUETOOTH_SERVICE = "car_bluetooth";
 
     /**
-     * @FutureFeature Cannot drop due to usage in non-flag protected place.
      * @hide
      */
+    @SystemApi
     public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
 
     /**
+     * Service name for {@link CarDrivingStateManager}
+     * @hide
+     */
+    @SystemApi
+    public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
+
+    /**
+     * Service name for {@link CarUxRestrictionsManager}
+     */
+    public static final String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
+
+    /**
+     * Service name for {@link android.car.settings.CarConfigurationManager}
+     */
+    public static final String CAR_CONFIGURATION_SERVICE = "configuration";
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
+
+    /**
      * Service for testing. This is system app only feature.
      * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
      * @hide
@@ -148,18 +177,48 @@
     @SystemApi
     public static final String TEST_SERVICE = "car-service-test";
 
-    /** Permission necessary to access car's mileage information. */
+    /** Permission necessary to access car's mileage information.
+     *  @hide
+     */
+    @SystemApi
     public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
 
-    /** Permission necessary to access car's fuel level. */
-    public static final String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
+    /** Permission necessary to access car's energy information. */
+    public static final String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
+
+    /** Permission necessary to access car's VIN information */
+    public static final String PERMISSION_IDENTIFICATION =
+            "android.car.permission.CAR_IDENTIFICATION";
 
     /** Permission necessary to access car's speed. */
     public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
 
-    /** Permission necessary to access car's dynamics state. */
-    public static final String PERMISSION_VEHICLE_DYNAMICS_STATE =
-        "android.car.permission.VEHICLE_DYNAMICS_STATE";
+    /** Permission necessary to access car's dynamics state.
+     *  @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CAR_DYNAMICS_STATE =
+            "android.car.permission.CAR_DYNAMICS_STATE";
+
+    /** Permission necessary to access car's fuel door and ev charge port. */
+    public static final String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
+
+    /** Permission necessary to read car's lights information.
+     *  @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_EXTERIOR_LIGHTS =
+            "android.car.permission.CAR_EXTERIOR_LIGHTS";
+
+    /** Permission necessary to control car's exterior lights.
+     *  @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS =
+            "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+
+    /** Permission necessary to access car's powertrain information.*/
+    public static final String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN";
 
     /**
      * Permission necessary to change car audio volume through {@link CarAudioManager}.
@@ -176,7 +235,6 @@
 
     /**
      * Permission necessary to use {@link CarNavigationStatusManager}.
-     * @hide
      */
     public static final String PERMISSION_CAR_NAVIGATION_MANAGER =
             "android.car.permission.CAR_NAVIGATION_MANAGER";
@@ -187,6 +245,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL =
             "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
 
@@ -199,6 +258,13 @@
     public static final String PERMISSION_CAR_DISPLAY_IN_CLUSTER =
             "android.car.permission.CAR_DISPLAY_IN_CLUSTER";
 
+    /** Permission necessary to use {@link CarInfoManager}. */
+    public static final String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
+
+    /** Permission necessary to read temperature of car's exterior environment. */
+    public static final String PERMISSION_EXTERIOR_ENVIRONMENT =
+            "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
+
     /**
      * Permission necessary to access car specific communication channel.
      * @hide
@@ -219,22 +285,70 @@
      * @hide
      */
     @SystemApi
-    public static final String PERMISSION_CAR_CABIN = "android.car.permission.CAR_CABIN";
+    public static final String PERMISSION_ADJUST_CAR_CABIN =
+            "android.car.permission.ADJUST_CAR_CABIN";
+
+    /**
+     * Permission necessary to access car's engine information.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CAR_ENGINE_DETAILED =
+            "android.car.permission.CAR_ENGINE_DETAILED";
+
+    /**
+     * Permission necessary to access car's tire pressure information.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
+
+    /**
+     * Permission necessary to control car's door.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_DOORS =
+            "android.car.permission.CONTROL_CAR_DOORS";
+
+    /**
+     * Permission necessary to control car's windows.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_WINDOWS =
+            "android.car.permission.CONTROL_CAR_WINDOWS";
+
+    /**
+     * Permission necessary to control car's seats.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_SEATS =
+            "android.car.permission.CONTROL_CAR_SEATS";
+
+    /**
+     * Permission necessary to control car's mirrors.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CONTROL_CAR_MIRRORS =
+            "android.car.permission.CONTROL_CAR_MIRRORS";
 
     /**
      * Permission necessary to access Car HVAC APIs.
      * @hide
      */
     @SystemApi
-    public static final String PERMISSION_CAR_HVAC = "android.car.permission.CAR_HVAC";
+    public static final String PERMISSION_CONTROL_CAR_CLIMATE =
+            "android.car.permission.CONTROL_CAR_CLIMATE";
 
     /**
-     * Permission necessary to access Car RADIO system APIs.
+     * Permission necessary to access Car POWER APIs.
      * @hide
      */
     @SystemApi
-    public static final String PERMISSION_CAR_RADIO = "android.car.permission.CAR_RADIO";
-
+    public static final String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
 
     /**
      * Permission necessary to access Car PROJECTION system APIs.
@@ -261,11 +375,19 @@
             "android.car.permission.CAR_TEST_SERVICE";
 
     /**
+     * Permission necessary to access CarDrivingStateService to get a Car's driving state.
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CAR_DRIVING_STATE =
+            "android.car.permission.CAR_DRIVING_STATE";
+
+    /**
      * Permissions necessary to access VMS publisher APIs.
      *
      * @hide
      */
-    @FutureFeature
+    @SystemApi
     public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
 
     /**
@@ -273,7 +395,7 @@
      *
      * @hide
      */
-    @FutureFeature
+    @SystemApi
     public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
 
     /**
@@ -283,7 +405,7 @@
      */
     @SystemApi
     public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL =
-        "android.car.permission.DIAGNOSTIC_READ_ALL";
+        "android.car.permission.CAR_DIAGNOSTICS";
 
     /**
      * Permissions necessary to clear diagnostic information.
@@ -291,7 +413,15 @@
      * @hide
      */
     @SystemApi
-    public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.DIAGNOSTIC_CLEAR";
+    public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
+
+    /**
+     * Permissions necessary to clear diagnostic information.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
 
     /** Type of car connection: platform runs directly in car. */
     public static final int CONNECTION_TYPE_EMBEDDED = 5;
@@ -637,11 +767,15 @@
             case HVAC_SERVICE:
                 manager = new CarHvacManager(binder, mContext, mEventHandler);
                 break;
+            case POWER_SERVICE:
+                manager = new CarPowerManager(binder, mContext, mEventHandler);
+                break;
             case PROJECTION_SERVICE:
                 manager = new CarProjectionManager(binder, mEventHandler);
                 break;
-            case RADIO_SERVICE:
-                manager = new CarRadioManager(binder, mEventHandler);
+            case PROPERTY_SERVICE:
+                manager = new CarPropertyManager(binder, mEventHandler, false,
+                                                 "CarPropertyManager");
                 break;
             case VENDOR_EXTENSION_SERVICE:
                 manager = new CarVendorExtensionManager(binder, mEventHandler);
@@ -655,12 +789,25 @@
                 manager = new CarTestManagerBinderWrapper(binder);
                 break;
             case VMS_SUBSCRIBER_SERVICE:
-                if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) {
-                    manager = new VmsSubscriberManager(binder, mEventHandler);
-                }
+                manager = new VmsSubscriberManager(binder);
                 break;
             case BLUETOOTH_SERVICE:
                 manager = new CarBluetoothManager(binder, mContext);
+                break;
+            case STORAGE_MONITORING_SERVICE:
+                manager = new CarStorageMonitoringManager(binder, mEventHandler);
+                break;
+            case CAR_DRIVING_STATE_SERVICE:
+                manager = new CarDrivingStateManager(binder, mContext, mEventHandler);
+                break;
+            case CAR_UX_RESTRICTION_SERVICE:
+                manager = new CarUxRestrictionsManager(binder, mContext, mEventHandler);
+                break;
+            case CAR_CONFIGURATION_SERVICE:
+                manager = new CarConfigurationManager(binder);
+                break;
+            default:
+                break;
         }
         return manager;
     }
diff --git a/car-lib/src/android/car/CarInfoManager.java b/car-lib/src/android/car/CarInfoManager.java
index b73e879..b228ca7 100644
--- a/car-lib/src/android/car/CarInfoManager.java
+++ b/car-lib/src/android/car/CarInfoManager.java
@@ -16,46 +16,46 @@
 
 package android.car;
 
+import static java.lang.Integer.toHexString;
+
 import android.annotation.Nullable;
-import android.car.annotation.FutureFeature;
 import android.car.annotation.ValueTypeDef;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.ICarProperty;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import android.util.Log;
 
 
 /**
  * Utility to retrieve various static information from car. Each data are grouped as {@link Bundle}
  * and relevant data can be checked from {@link Bundle} using pre-specified keys.
  */
-public final class CarInfoManager implements CarManagerBase {
+public final class CarInfoManager implements CarManagerBase{
 
+    private static final boolean DBG = false;
+    private static final String TAG = "CarInfoManager";
     /**
      * Key for manufacturer of the car. Passed in basic info Bundle.
      * @hide
      */
-    @ValueTypeDef(type = String.class)
-    public static final String BASIC_INFO_KEY_MANUFACTURER = "android.car.manufacturer";
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_KEY_MANUFACTURER = 0x11100101;
     /**
      * Key for model name of the car. This information may not necessarily allow distinguishing
      * different car models as the same name may be used for different cars depending on
      * manufacturers. Passed in basic info Bundle.
      * @hide
      */
-    @ValueTypeDef(type = String.class)
-    public static final String BASIC_INFO_KEY_MODEL = "android.car.model";
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_KEY_MODEL = 0x11100102;
     /**
      * Key for model year of the car in AC. Passed in basic info Bundle.
      * @hide
      */
     @ValueTypeDef(type = Integer.class)
-    public static final String BASIC_INFO_KEY_MODEL_YEAR = "android.car.model-year";
+    public static final int BASIC_INFO_KEY_MODEL_YEAR = 0x11400103;
     /**
      * Key for unique identifier for the car. This is not VIN, and id is persistent until user
      * resets it. Passed in basic info Bundle.
@@ -88,99 +88,146 @@
 
     // add: transmission gear available selection, gear available steps
     //          drive wheel: FWD, RWD, AWD, 4WD */
-
-    private final ICarInfo mService;
-
-    @GuardedBy("this")
-    private Bundle mBasicInfo;
-
     /**
-     * Return manufacturer of the car.
-     * @return null if information is not available.
-     */
-    public @android.annotation.Nullable String getManufacturer() throws CarNotConnectedException {
-        return getBasicInfo().getString(BASIC_INFO_KEY_MANUFACTURER);
-    }
-
-    /**
-     * Return model name of the car. This information may not necessarily allow distinguishing
-     * different car models as the same name may be used for different cars depending on
-     * manufacturers.
-     * @return null if information is not available.
-     */
-    public @Nullable String getModel() throws CarNotConnectedException {
-        return getBasicInfo().getString(BASIC_INFO_KEY_MODEL);
-    }
-
-    /**
-     * Return model year of the car in AC.
-     * @return null if information is not available.
-     */
-    public @Nullable String getModelYear() throws CarNotConnectedException {
-        return getBasicInfo().getString(BASIC_INFO_KEY_MODEL_YEAR);
-    }
-
-    /**
-     * Return unique identifier for the car. This is not VIN, and id is persistent until user
-     * resets it. This ID is guaranteed to be always available.
-     * @return vehicle id
-     */
-    public String getVehicleId() throws CarNotConnectedException {
-        return getBasicInfo().getString(BASIC_INFO_KEY_VEHICLE_ID);
-    }
-
-    /**
-     * Get product configuration string. Contents of this string is product specific but it should
-     * be composed of key-value pairs with the format of:
-     *   key1=value1;key2=value2;...
-     * @return null if such information is not available in this car.
-     * @throws CarNotConnectedException
+     * Key for Fuel Capacity in milliliters.  Passed in basic info Bundle.
      * @hide
      */
-    @FutureFeature
-    public @Nullable String getProductConfiguration() throws CarNotConnectedException {
-        try {
-            return mService.getStringInfo(INFO_KEY_PRODUCT_CONFIGURATION);
-        } catch (IllegalStateException e) {
-            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException(e);
-        }
-        return null;
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_FUEL_CAPACITY = 0x11600104;
+    /**
+     * Key for Fuel Types.  This is an array of fuel types the vehicle supports.
+     * Passed in basic info Bundle.
+     * @hide
+     */
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_FUEL_TYPES = 0x11410105;
+    /**
+     * Key for EV Battery Capacity in WH.  Passed in basic info Bundle.
+     * @hide
+     */
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_EV_BATTERY_CAPACITY = 0x11600106;
+    /**
+     * Key for EV Connector Types.  This is an array of connector types the vehicle supports.
+     * Passed in basic info Bundle.
+     * @hide
+     */
+    @ValueTypeDef(type = Integer.class)
+    public static final int BASIC_INFO_EV_CONNECTOR_TYPES = 0x11410107;
+
+    private final ICarProperty mService;
+
+    /**
+     * @return Manufacturer of the car.  Null if not available.
+     */
+    @Nullable
+    public String getManufacturer() throws CarNotConnectedException {
+        CarPropertyValue<String> carProp = getProperty(String.class,
+                BASIC_INFO_KEY_MANUFACTURER, 0);
+        return carProp != null ? carProp.getValue() : null;
     }
 
     /**
-     * Get {@link android.os.Bundle} containing basic car information. Check
-     * {@link #BASIC_INFO_KEY_MANUFACTURER}, {@link #BASIC_INFO_KEY_MODEL},
-     * {@link #BASIC_INFO_KEY_MODEL_YEAR}, and {@link #BASIC_INFO_KEY_VEHICLE_ID} for supported
-     * keys in the {@link android.os.Bundle}.
-     * @return {@link android.os.Bundle} containing basic car info.
-     * @throws CarNotConnectedException
+     * @return Model name of the car, null if not available.  This information
+     * may not necessarily allow distinguishing different car models as the same
+     * name may be used for different cars depending on manufacturers.
      */
-    private synchronized Bundle getBasicInfo() throws CarNotConnectedException {
-        if (mBasicInfo != null) {
-            return mBasicInfo;
-        }
-        try {
-            mBasicInfo = mService.getBasicInfo();
-        } catch (IllegalStateException e) {
-            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException(e);
-        }
-        return mBasicInfo;
+    @Nullable
+    public String getModel() throws CarNotConnectedException {
+        CarPropertyValue<String> carProp = getProperty(String.class, BASIC_INFO_KEY_MODEL, 0);
+        return carProp != null ? carProp.getValue() : null;
+    }
+
+    /**
+     * @return Model year of the car in AC.  Null if not available.
+     */
+    @Nullable
+    public String getModelYear() throws CarNotConnectedException {
+        CarPropertyValue<String> carProp = getProperty(String.class,
+                BASIC_INFO_KEY_MODEL_YEAR, 0);
+        return carProp != null ? carProp.getValue() : null;
+    }
+
+    /**
+     * @return Unique identifier for the car. This is not VIN, and vehicle id is
+     * persistent until user resets it. This ID is guaranteed to be always
+     * available.
+     * TODO: BASIC_INFO_KEY_VEHICLE_ID property?
+     */
+    public String getVehicleId() throws CarNotConnectedException {
+        return "";
+    }
+
+    /**
+     * @return Fuel capacity of the car in milliliters.  0 if car doesn't run on
+     *         fuel.
+     */
+    public float getFuelCapacity() throws CarNotConnectedException {
+        CarPropertyValue<Float> carProp = getProperty(Float.class,
+                BASIC_INFO_FUEL_CAPACITY, 0);
+        return carProp != null ? carProp.getValue() : 0f;
+    }
+
+    /**
+     * @return Array of FUEL_TYPEs available in the car.  Empty array if no fuel
+     *         types available.
+     */
+    public @FuelType.Enum int[] getFuelTypes() throws CarNotConnectedException {
+        CarPropertyValue<int[]> carProp = getProperty(int[].class, BASIC_INFO_FUEL_TYPES, 0);
+        return carProp != null ? carProp.getValue() : new int[0];
+    }
+
+    /**
+     * @return Battery capacity of the car in WH.  0 if car doesn't run on
+     *         battery.
+     */
+    public float getEvBatteryCapacity() throws CarNotConnectedException {
+        CarPropertyValue<Float> carProp = getProperty(Float.class,
+                BASIC_INFO_EV_BATTERY_CAPACITY, 0);
+        return carProp != null ? carProp.getValue() : 0f;
+    }
+
+    /**
+     * @return Array of EV_CONNECTOR_TYPEs available in the car.  Empty array if
+     *         no connector types available.
+     */
+    public @EvConnectorType.Enum int[] getEvConnectorTypes() throws CarNotConnectedException {
+        CarPropertyValue<int[]> carProp = getProperty(int[].class,
+                BASIC_INFO_EV_CONNECTOR_TYPES, 0);
+        return carProp != null ? carProp.getValue() : new int[0];
     }
 
     /** @hide */
     CarInfoManager(IBinder service) {
-        mService = ICarInfo.Stub.asInterface(service);
+        mService = ICarProperty.Stub.asInterface(service);
     }
 
     /** @hide */
-    @Override
     public void onCarDisconnected() {
-        synchronized (this) {
-            mBasicInfo = null;
+    }
+
+    private  <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
+            throws CarNotConnectedException {
+        if (DBG) {
+            Log.d(TAG, "getProperty, propId: 0x" + toHexString(propId)
+                    + ", area: 0x" + toHexString(area) + ", class: " + clazz);
+        }
+        try {
+            CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+            if (propVal != null && propVal.getValue() != null) {
+                Class<?> actualClass = propVal.getValue().getClass();
+                if (actualClass != clazz) {
+                    throw new IllegalArgumentException("Invalid property type. " + "Expected: "
+                            + clazz + ", but was: " + actualClass);
+                }
+            }
+            return propVal;
+        } catch (RemoteException e) {
+            Log.e(TAG, "getProperty failed with " + e.toString()
+                    + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+            throw new CarNotConnectedException(e);
+        } catch (IllegalArgumentException e)  {
+            return null;
         }
     }
 }
diff --git a/car-lib/src/android/car/EvConnectorType.java b/car-lib/src/android/car/EvConnectorType.java
new file mode 100644
index 0000000..15370c8
--- /dev/null
+++ b/car-lib/src/android/car/EvConnectorType.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 android.car;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * EvConnectorType denotes the different connectors a EV may use.
+ * @hide
+ */
+public final class EvConnectorType {
+    /**
+     * List of EV Connector Types from VHAL
+     */
+    public static final int UNKNOWN = 0;
+    public static final int J1772 = 1;
+    public static final int MENNEKES = 2;
+    public static final int CHADEMO = 3;
+    public static final int COMBO_1 = 4;
+    public static final int COMBO_2 = 5;
+    public static final int TESLA_ROADSTER = 6;
+    public static final int TESLA_HPWC = 7;
+    public static final int TESLA_SUPERCHARGER = 8;
+    public static final int GBT = 9;
+    /**
+     * Connector type to use when no other types apply. Before using this
+     * value, work with the AOSP community to see if the EvConnectorType enum can be
+     * extended with an appropriate value.
+     */
+    public static final int OTHER = 101;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        UNKNOWN,
+        J1772,
+        MENNEKES,
+        CHADEMO,
+        COMBO_1,
+        COMBO_2,
+        TESLA_ROADSTER,
+        TESLA_HPWC,
+        TESLA_SUPERCHARGER,
+        GBT,
+        OTHER
+    })
+    public @interface Enum {}
+
+
+    private EvConnectorType() {}
+}
diff --git a/car-lib/src/android/car/FuelType.java b/car-lib/src/android/car/FuelType.java
new file mode 100644
index 0000000..a808fb6
--- /dev/null
+++ b/car-lib/src/android/car/FuelType.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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 android.car;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * FuelType denotes the different fuels a vehicle may use.
+ * @hide
+ */
+public final class FuelType {
+    /**
+     * List of Fuel Types from VHAL
+     */
+    public static final int UNKNOWN = 0;
+    /** Unleaded gasoline */
+    public static final int UNLEADED = 1;
+    /** Leaded gasoline */
+    public static final int LEADED = 2;
+    /** Diesel #1 */
+    public static final int DIESEL_1 = 3;
+    /** Diesel #2 */
+    public static final int DIESEL_2 = 4;
+    /** Biodiesel */
+    public static final int BIODIESEL = 5;
+    /** 85% ethanol/gasoline blend */
+    public static final int E85 = 6;
+    /** Liquified petroleum gas */
+    public static final int LPG = 7;
+    /** Compressed natural gas */
+    public static final int CNG = 8;
+    /** Liquified natural gas */
+    public static final int LNG = 9;
+    /** Electric */
+    public static final int ELECTRIC = 10;
+    /** Hydrogen fuel cell */
+    public static final int HYDROGEN = 11;
+    /**
+     * Fuel type to use when no other types apply. Before using this value, work with
+     * Google to see if the FuelType enum can be extended with an appropriate value.
+     */
+    public static final int OTHER = 12;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        UNKNOWN,
+        UNLEADED,
+        LEADED,
+        DIESEL_1,
+        DIESEL_2,
+        BIODIESEL,
+        E85,
+        LPG,
+        CNG,
+        LNG,
+        ELECTRIC,
+        HYDROGEN,
+        OTHER
+    })
+    public @interface Enum {}
+
+
+    private FuelType() {}
+}
diff --git a/car-lib/src/android/car/VehicleDoor.java b/car-lib/src/android/car/VehicleAreaDoor.java
similarity index 88%
rename from car-lib/src/android/car/VehicleDoor.java
rename to car-lib/src/android/car/VehicleAreaDoor.java
index 69c445d..7b06e0d 100644
--- a/car-lib/src/android/car/VehicleDoor.java
+++ b/car-lib/src/android/car/VehicleAreaDoor.java
@@ -18,12 +18,12 @@
 import android.annotation.SystemApi;
 
 /**
- * VehicleDoor is an abstraction for a door in a car. Some car APIs may provide control per
+ * VehicleAreaDoor is an abstraction for a door in a car. Some car APIs may provide control per
  * door and values defined here should be used to distinguish different doors.
  * @hide
  */
 @SystemApi
-public final class VehicleDoor {
+public final class VehicleAreaDoor {
     public static final int DOOR_ROW_1_LEFT = 0x00000001;
     public static final int DOOR_ROW_1_RIGHT = 0x00000004;
     public static final int DOOR_ROW_2_LEFT = 0x00000010;
@@ -33,5 +33,5 @@
     public static final int DOOR_HOOD = 0x10000000;
     public static final int DOOR_REAR = 0x20000000;
 
-    private VehicleDoor() {}
+    private VehicleAreaDoor() {}
 }
diff --git a/car-lib/src/android/car/VehicleMirror.java b/car-lib/src/android/car/VehicleAreaMirror.java
similarity index 84%
rename from car-lib/src/android/car/VehicleMirror.java
rename to car-lib/src/android/car/VehicleAreaMirror.java
index 21feb7a..4dd00ef 100644
--- a/car-lib/src/android/car/VehicleMirror.java
+++ b/car-lib/src/android/car/VehicleAreaMirror.java
@@ -18,15 +18,15 @@
 import android.annotation.SystemApi;
 
 /**
- * VehicleMirror is an abstraction for a mirror in a car. Some car APIs may provide control per
+ * VehicleAreaMirror is an abstraction for a mirror in a car. Some car APIs may provide control per
  * mirror and values defined here should be used to distinguish different mirrors.
  * @hide
  */
 @SystemApi
-public final class VehicleMirror {
+public final class VehicleAreaMirror {
     public static final int MIRROR_DRIVER_LEFT   = 0x00000001;
     public static final int MIRROR_DRIVER_RIGHT  = 0x00000002;
     public static final int MIRROR_DRIVER_CENTER = 0x00000004;
 
-    private VehicleMirror() {}
+    private VehicleAreaMirror() {}
 }
diff --git a/car-lib/src/android/car/VehicleSeat.java b/car-lib/src/android/car/VehicleAreaSeat.java
similarity index 90%
rename from car-lib/src/android/car/VehicleSeat.java
rename to car-lib/src/android/car/VehicleAreaSeat.java
index 3707454..b56e5a0 100644
--- a/car-lib/src/android/car/VehicleSeat.java
+++ b/car-lib/src/android/car/VehicleAreaSeat.java
@@ -19,13 +19,13 @@
 import android.car.hardware.CarPropertyValue;
 
 /**
- * VehicleSeat is an abstraction for a seat in a car. Some car APIs like
+ * VehicleAreaSeat is an abstraction for a seat in a car. Some car APIs like
  * {@link CarPropertyValue} may provide control per seat and
  * values defined here should be used to distinguish different seats.
  * @hide
  */
 @SystemApi
-public final class VehicleSeat {
+public final class VehicleAreaSeat {
     public static final int SEAT_ROW_1_LEFT = 0x0001;
     public static final int SEAT_ROW_1_CENTER = 0x0002;
     public static final int SEAT_ROW_1_RIGHT = 0x0004;
@@ -36,5 +36,5 @@
     public static final int SEAT_ROW_3_CENTER = 0x0200;
     public static final int SEAT_ROW_3_RIGHT = 0x0400;
 
-    private VehicleSeat() {}
+    private VehicleAreaSeat() {}
 }
diff --git a/car-lib/src/android/car/VehicleAreaType.java b/car-lib/src/android/car/VehicleAreaType.java
index f4b5b91..971f000 100644
--- a/car-lib/src/android/car/VehicleAreaType.java
+++ b/car-lib/src/android/car/VehicleAreaType.java
@@ -22,32 +22,31 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Represents vehicle area such as window, door, seat, zone, etc.
- * See also {@link android.car.VehicleDoor}, {@link android.car.VehicleSeat},
- * {@link android.car.VehicleWindow}, {@link android.car.VehicleZone}
+ * Represents vehicle area such as window, door, seat, etc.
+ * See also {@link VehicleAreaDoor}, {@link VehicleAreaSeat},
+ * {@link VehicleAreaWindow},
  *
  * @hide
  */
 @SystemApi
 public final class VehicleAreaType {
     /** Used for global properties */
-    public static final int VEHICLE_AREA_TYPE_NONE = 0;
-
-    public static final int VEHICLE_AREA_TYPE_ZONE = 1;
+    public static final int VEHICLE_AREA_TYPE_GLOBAL = 0;
     public static final int VEHICLE_AREA_TYPE_WINDOW = 2;
     public static final int VEHICLE_AREA_TYPE_SEAT = 3;
     public static final int VEHICLE_AREA_TYPE_DOOR = 4;
     public static final int VEHICLE_AREA_TYPE_MIRROR = 5;
+    public static final int VEHICLE_AREA_TYPE_WHEEL = 6;
     private VehicleAreaType() {}
 
     /** @hide */
     @IntDef({
-        VEHICLE_AREA_TYPE_NONE,
-        VEHICLE_AREA_TYPE_ZONE,
+        VEHICLE_AREA_TYPE_GLOBAL,
         VEHICLE_AREA_TYPE_WINDOW,
         VEHICLE_AREA_TYPE_SEAT,
         VEHICLE_AREA_TYPE_DOOR,
-        VEHICLE_AREA_TYPE_MIRROR
+        VEHICLE_AREA_TYPE_MIRROR,
+        VEHICLE_AREA_TYPE_WHEEL
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface VehicleAreaTypeValue {}
diff --git a/car-lib/src/android/car/VehicleMirror.java b/car-lib/src/android/car/VehicleAreaWheel.java
similarity index 60%
copy from car-lib/src/android/car/VehicleMirror.java
copy to car-lib/src/android/car/VehicleAreaWheel.java
index 21feb7a..9e66ed5 100644
--- a/car-lib/src/android/car/VehicleMirror.java
+++ b/car-lib/src/android/car/VehicleAreaWheel.java
@@ -18,15 +18,18 @@
 import android.annotation.SystemApi;
 
 /**
- * VehicleMirror is an abstraction for a mirror in a car. Some car APIs may provide control per
- * mirror and values defined here should be used to distinguish different mirrors.
+ * VehicleAreaWheel is an abstraction for the wheels on a car.  It exists to isolate the java APIs
+ * from the VHAL definitions.
  * @hide
  */
 @SystemApi
-public final class VehicleMirror {
-    public static final int MIRROR_DRIVER_LEFT   = 0x00000001;
-    public static final int MIRROR_DRIVER_RIGHT  = 0x00000002;
-    public static final int MIRROR_DRIVER_CENTER = 0x00000004;
+public final class VehicleAreaWheel {
+    public static final int WHEEL_UNKNOWN = 0x00;
+    public static final int WHEEL_LEFT_FRONT = 0x01;
+    public static final int WHEEL_RIGHT_FRONT = 0x02;
+    public static final int WHEEL_LEFT_REAR = 0x04;
+    public static final int WHEEL_RIGHT_REAR = 0x08;
 
-    private VehicleMirror() {}
+    private VehicleAreaWheel() {}
 }
+
diff --git a/car-lib/src/android/car/VehicleWindow.java b/car-lib/src/android/car/VehicleAreaWindow.java
similarity index 70%
rename from car-lib/src/android/car/VehicleWindow.java
rename to car-lib/src/android/car/VehicleAreaWindow.java
index 8c147d9..57b46f5 100644
--- a/car-lib/src/android/car/VehicleWindow.java
+++ b/car-lib/src/android/car/VehicleAreaWindow.java
@@ -18,22 +18,23 @@
 import android.annotation.SystemApi;
 
 /**
- * VehicleWindow is an abstraction for a window in a car. Some car APIs may provide control per
+ * VehicleAreaWindow is an abstraction for a window in a car. Some car APIs may provide control per
  * window and values defined here should be used to distinguish different windows.
  * @hide
  */
 @SystemApi
-public final class VehicleWindow {
+public final class VehicleAreaWindow {
     public static final int WINDOW_FRONT_WINDSHIELD = 0x0001;
     public static final int WINDOW_REAR_WINDSHIELD = 0x0002;
-    public static final int WINDOW_ROOF_TOP = 0x0004;
     public static final int WINDOW_ROW_1_LEFT = 0x0010;
-    public static final int WINDOW_ROW_1_RIGHT = 0x0020;
+    public static final int WINDOW_ROW_1_RIGHT = 0x0040;
     public static final int WINDOW_ROW_2_LEFT = 0x0100;
-    public static final int WINDOW_ROW_2_RIGHT = 0x0200;
+    public static final int WINDOW_ROW_2_RIGHT = 0x0400;
     public static final int WINDOW_ROW_3_LEFT = 0x1000;
-    public static final int WINDOW_ROW_3_RIGHT = 0x2000;
+    public static final int WINDOW_ROW_3_RIGHT = 0x4000;
+    public static final int WINDOW_ROOF_TOP_1 = 0x10000;
+    public static final int WINDOW_ROOF_TOP_2 = 0x20000;
 
-    private VehicleWindow() {}
+    private VehicleAreaWindow() {}
 }
 
diff --git a/car-lib/src/android/car/VehicleOilLevel.java b/car-lib/src/android/car/VehicleOilLevel.java
new file mode 100644
index 0000000..5a21a2d
--- /dev/null
+++ b/car-lib/src/android/car/VehicleOilLevel.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 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 android.car;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * OilLevel in the engine
+ * @hide
+ */
+public final class VehicleOilLevel {
+    /**
+     * List of Oil Levels from VHAL
+     */
+    public static final int CRITICALLY_LOW = 0;
+    public static final int LOW = 1;
+    public static final int NORMAL = 2;
+    public static final int HIGH = 3;
+    public static final int ERROR = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        CRITICALLY_LOW,
+        LOW,
+        NORMAL,
+        HIGH,
+        ERROR,
+    })
+    public @interface Enum {}
+
+    private VehicleOilLevel() {}
+}
diff --git a/car-lib/src/android/car/VehiclePropertyType.java b/car-lib/src/android/car/VehiclePropertyType.java
new file mode 100644
index 0000000..b236d2d
--- /dev/null
+++ b/car-lib/src/android/car/VehiclePropertyType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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 android.car;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Value type of VehicleProperty
+ * @hide
+ */
+public class VehiclePropertyType {
+    public static final int STRING          = 0x00100000;
+    public static final int BOOLEAN         = 0x00200000;
+    public static final int INT32           = 0x00400000;
+    public static final int INT32_VEC       = 0x00410000;
+    public static final int INT64           = 0x00500000;
+    public static final int INT64_VEC       = 0x00510000;
+    public static final int FLOAT           = 0x00600000;
+    public static final int FLOAT_VEC       = 0x00610000;
+    public static final int BYTES           = 0x00700000;
+    public static final int MIXED           = 0x00e00000;
+    public static final int MASK            = 0x00ff0000;
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            STRING,
+            BOOLEAN,
+            INT32,
+            INT32_VEC,
+            INT64,
+            INT64_VEC,
+            FLOAT,
+            FLOAT_VEC,
+            BYTES,
+            /**
+             * Any combination of scalar or vector types. The exact format must be
+             * provided in the description of the property.
+            */
+            MIXED,
+            MASK
+    })
+    public @interface Enum {}
+    private VehiclePropertyType() {}
+}
diff --git a/car-lib/src/android/car/VehicleUnit.java b/car-lib/src/android/car/VehicleUnit.java
new file mode 100644
index 0000000..a08ccb5
--- /dev/null
+++ b/car-lib/src/android/car/VehicleUnit.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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 android.car;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Units used for int or float type with no attached enum types.
+ * @hide
+ */
+public final class VehicleUnit {
+    /**
+     * List of Unit Types from VHAL
+     */
+    public static final int SHOULD_NOT_USE = 0x000;
+
+    public static final int METER_PER_SEC = 0x01;
+    public static final int RPM = 0x02;
+    public static final int HERTZ = 0x03;
+    public static final int PERCENTILE = 0x10;
+    public static final int MILLIMETER = 0x20;
+    public static final int METER = 0x21;
+    public static final int KILOMETER = 0x23;
+    public static final int CELSIUS = 0x30;
+    public static final int FAHRENHEIT = 0x31;
+    public static final int KELVIN = 0x32;
+    public static final int MILLILITER = 0x40;
+    public static final int NANO_SECS = 0x50;
+    public static final int SECS = 0x53;
+    public static final int YEAR = 0x59;
+    public static final int KILOPASCAL = 0x70;
+    public static final int WATT_HOUR = 0x60;
+    public static final int MILLIAMPERE = 0x61;
+    public static final int MILLIVOLT = 0x62;
+    public static final int MILLIWATTS = 0x63;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            SHOULD_NOT_USE,
+            METER_PER_SEC,
+            RPM,
+            HERTZ,
+            PERCENTILE,
+            MILLIMETER,
+            METER,
+            KILOMETER,
+            CELSIUS,
+            FAHRENHEIT,
+            KELVIN,
+            MILLILITER,
+            NANO_SECS,
+            SECS,
+            YEAR,
+            KILOPASCAL,
+            WATT_HOUR,
+            MILLIAMPERE,
+            MILLIVOLT,
+            MILLIWATTS
+    })
+    public @interface Enum {}
+
+    private VehicleUnit() {}
+}
diff --git a/car-lib/src/android/car/VehicleZone.java b/car-lib/src/android/car/VehicleZone.java
deleted file mode 100644
index 780d827..0000000
--- a/car-lib/src/android/car/VehicleZone.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.car;
-
-import android.annotation.SystemApi;
-import android.car.hardware.CarPropertyValue;
-
-/**
- * VehicleZone is an abstraction for an area in a car. Some car APIs like
- * {@link CarPropertyValue} needs to handle zone and values defined
- * here should be used.
- * @hide
- */
-@SystemApi
-public final class VehicleZone {
-    public static final int ZONE_ROW_1_LEFT = 0x00000001;
-    public static final int ZONE_ROW_1_CENTER = 0x00000002;
-    public static final int ZONE_ROW_1_RIGHT = 0x00000004;
-    public static final int ZONE_ROW_1_ALL = 0x00000008;
-    public static final int ZONE_ROW_2_LEFT = 0x00000010;
-    public static final int ZONE_ROW_2_CENTER = 0x00000020;
-    public static final int ZONE_ROW_2_RIGHT = 0x00000040;
-    public static final int ZONE_ROW_2_ALL = 0x00000080;
-    public static final int ZONE_ROW_3_LEFT = 0x00000100;
-    public static final int ZONE_ROW_3_CENTER = 0x00000200;
-    public static final int ZONE_ROW_3_RIGHT = 0x00000400;
-    public static final int ZONE_ROW_3_ALL = 0x00000800;
-    public static final int ZONE_ROW_4_LEFT = 0x00001000;
-    public static final int ZONE_ROW_4_CENTER = 0x00002000;
-    public static final int ZONE_ROW_4_RIGHT = 0x00004000;
-    public static final int ZONE_ROW_4_ALL = 0x00008000;
-    public static final int ZONE_ALL = 0x80000000;
-
-    private VehicleZone() {}
-}
diff --git a/car-lib/src/android/car/VehicleZoneUtil.java b/car-lib/src/android/car/VehicleZoneUtil.java
deleted file mode 100644
index a35bc3c..0000000
--- a/car-lib/src/android/car/VehicleZoneUtil.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.car;
-
-import android.annotation.SystemApi;
-
-/**
- * Collection of utilities for handling zones
- * @hide
- */
-@SystemApi
-public final class VehicleZoneUtil {
-
-    /**
-     * Change zone flag into index with available zones.
-     * For example with zoned of 0x80000001, 0x1 will be index 0 and 0x80000000 will be index 2.
-     * @param available zones, should not be zero
-     * @param zone flag for the zone to get index, should not be zero and should be one of the flags
-     *             defined in zones.
-     * @return index of desired zone.
-     * @throws IllegalArgumentException if zones or zone is invalid.
-     */
-    public static int zoneToIndex(int zones, int zone) throws IllegalArgumentException {
-        if ((zone == 0) || // check that zone is non-zero
-                ((zone & zones) != zone) || // check that zone is inside of zones
-                ((zone & (zone - 1)) != 0)) { // check that zone only has one bit set
-            throw new IllegalArgumentException("Invalid zones 0x" + Integer.toHexString(zones) +
-                    " or zone 0x" + Integer.toHexString(zone));
-        }
-        int index = -1;
-        while((zone & zones) != 0) {
-            index++;
-            zones &= zones - 1;
-        }
-        return index;
-    }
-
-    /**
-     * Return number of zones (non-zero flag) from given zones.
-     */
-    public static int getNumberOfZones(int zones) {
-        int numZones = 0;
-        while (zones != 0) {
-            zones &= zones - 1;
-            numZones++;
-        }
-        return numZones;
-    }
-
-    /**
-     * Return bit flag of first zone. If zones is 0, it will just return 0.
-     * @param zones can be 0 if there is no zone
-     * @return
-     */
-    public static int getFirstZone(int zones) {
-        if (zones == 0) {
-            return 0;
-        }
-        int xorFlag = zones & (zones - 1);
-
-        return zones ^ xorFlag;
-    }
-
-    /**
-     * Return bit flag of zone available after startingZone. For zones of 0x7 with startingZone of
-     * 0x2, it will return 0x4. If no zone exist after startingZone, it will return 0.
-     * @param zones
-     * @param startingZone A bit flag representing a zone. This does not necessarily be one of flags
-     *                     available in zones.
-     * @return
-     * @throws IllegalArgumentException If startingZone is invalid.
-     */
-    public static int getNextZone(int zones, int startingZone) throws IllegalArgumentException {
-        if ((startingZone & (startingZone - 1)) != 0 || startingZone == 0) {
-            throw new IllegalArgumentException(
-                    "Starting zone should represent only one bit flag: 0x" +
-                            Integer.toHexString(startingZone));
-        }
-
-        // Create a mask that sets all bits above the current one
-        int mask = startingZone << 1;
-        mask -= 1;
-        mask = ~mask;
-        return getFirstZone(zones & mask);
-    }
-
-    /**
-     * Return array of zone with each active zone in one index. This can be useful for iterating
-     * all available zones.
-     */
-    public static int[] listAllZones(int zones) {
-        int numberOfZones = getNumberOfZones(zones);
-        int[] list = new int[numberOfZones];
-        if (numberOfZones == 0) {
-            return list;
-        }
-
-        int arrayIndex = 0;
-        while (zones != 0) {
-            int xorFlag = zones & (zones - 1);
-            int zone = zones ^ xorFlag;
-            list[arrayIndex++] = zone;
-            zones = xorFlag;
-        }
-        return list;
-    }
-
-    private VehicleZoneUtil() {}
-}
diff --git a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
index 758ce9e..0ec6d72 100644
--- a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
+++ b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java
@@ -16,6 +16,7 @@
 
 package android.car.cluster;
 
+import android.annotation.SystemApi;
 import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
 import android.content.Intent;
@@ -40,10 +41,12 @@
  *
  * @hide
  */
+@SystemApi
 public class CarInstrumentClusterManager implements CarManagerBase {
     private static final String TAG = CarInstrumentClusterManager.class.getSimpleName();
 
     /** @hide */
+    @SystemApi
     public static final String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
 
     /**
@@ -53,6 +56,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String KEY_EXTRA_ACTIVITY_STATE =
             "android.car.cluster.ClusterActivityState";
 
@@ -70,6 +74,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void startActivity(Intent intent) throws CarNotConnectedException {
         try {
             mService.startClusterActivity(intent);
@@ -88,6 +93,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void registerCallback(String category, Callback callback)
             throws CarNotConnectedException {
         Log.i(TAG, "registerCallback, category: " + category + ", callback: " + callback);
@@ -130,6 +136,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void unregisterCallback(Callback callback) throws CarNotConnectedException {
         List<String> keysToRemove = new ArrayList<>(1);
         synchronized (mLock) {
@@ -164,6 +171,7 @@
     }
 
     /** @hide */
+    @SystemApi
     public interface Callback {
 
         /**
diff --git a/car-lib/src/android/car/cluster/renderer/IInstrumentClusterNavigation.aidl b/car-lib/src/android/car/cluster/renderer/IInstrumentClusterNavigation.aidl
index b1fb7b1..6f33a9d 100644
--- a/car-lib/src/android/car/cluster/renderer/IInstrumentClusterNavigation.aidl
+++ b/car-lib/src/android/car/cluster/renderer/IInstrumentClusterNavigation.aidl
@@ -25,13 +25,6 @@
  * @hide
  */
 interface IInstrumentClusterNavigation {
-    void onStartNavigation();
-    void onStopNavigation();
-    void onNextManeuverChanged(
-        int event, CharSequence eventName, int turnAngle, int turnNumber, in Bitmap image,
-        int turnSide);
-    void onNextManeuverDistanceChanged(int distanceMeters, int timeSeconds,
-        int displayDistanceMillis, int displayDistanceUnit);
     void onEvent(int eventType, in Bundle bundle);
     CarNavigationInstrumentCluster getInstrumentClusterInfo();
 }
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index e34f2fa..d572d9a 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -24,7 +24,6 @@
 import android.car.CarNotConnectedException;
 import android.car.navigation.CarNavigationInstrumentCluster;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -239,34 +238,6 @@
         }
 
         @Override
-        public void onStartNavigation() throws RemoteException {
-            assertContextOwnership();
-            mNavigationRenderer.onStartNavigation();
-        }
-
-        @Override
-        public void onStopNavigation() throws RemoteException {
-            assertContextOwnership();
-            mNavigationRenderer.onStopNavigation();
-        }
-
-        @Override
-        public void onNextManeuverChanged(int event, CharSequence eventName, int turnAngle,
-                int turnNumber, Bitmap image, int turnSide) throws RemoteException {
-            assertContextOwnership();
-            mNavigationRenderer.onNextTurnChanged(event, eventName, turnAngle, turnNumber,
-                    image, turnSide);
-        }
-
-        @Override
-        public void onNextManeuverDistanceChanged(int distanceMeters, int timeSeconds,
-                int displayDistanceMillis, int displayDistanceUnit) throws RemoteException {
-            assertContextOwnership();
-            mNavigationRenderer.onNextTurnDistanceChanged(distanceMeters, timeSeconds,
-                    displayDistanceMillis, displayDistanceUnit);
-        }
-
-        @Override
         public void onEvent(int eventType, Bundle bundle) throws RemoteException {
             assertContextOwnership();
             mNavigationRenderer.onEvent(eventType, bundle);
@@ -284,7 +255,7 @@
             Pair<Integer, Integer> owner = mNavContextOwner;
             if (owner == null || owner.first != uid || owner.second != pid) {
                 throw new IllegalStateException("Client (uid:" + uid + ", pid: " + pid + ") is"
-                        + "not an owner of APP_CONTEXT_NAVIGATION");
+                        + " not an owner of APP_FOCUS_TYPE_NAVIGATION");
             }
         }
     }
diff --git a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
index 0958548..4681a8b 100644
--- a/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
+++ b/car-lib/src/android/car/cluster/renderer/NavigationRenderer.java
@@ -24,7 +24,6 @@
 /**
  * Contains methods specified for Navigation App renderer in instrument cluster.
  *
- * TODO: Consider to add methods to report time / distance to final destination. bug:32060070
  * @hide
  */
 @SystemApi
@@ -35,13 +34,8 @@
      */
     abstract public CarNavigationInstrumentCluster getNavigationProperties();
 
-    abstract public void onStartNavigation();
-    abstract public void onStopNavigation();
-    abstract public void onNextTurnChanged(int event, CharSequence eventName, int turnAngle,
-            int turnNumber, Bitmap image, int turnSide);
-    abstract public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds,
-            int displayDistanceMillis, int displayDistanceUnit);
-
-    /** @hide */
-    public void onEvent(int eventType, Bundle bundle) {}
+    /**
+     * Called when an event is fired to change the navigation state.
+     */
+    abstract public void onEvent(int eventType, Bundle bundle);
 }
diff --git a/car-lib/src/android/car/cluster/renderer/ThreadSafeNavigationRenderer.java b/car-lib/src/android/car/cluster/renderer/ThreadSafeNavigationRenderer.java
index 047ed90..251b670 100644
--- a/car-lib/src/android/car/cluster/renderer/ThreadSafeNavigationRenderer.java
+++ b/car-lib/src/android/car/cluster/renderer/ThreadSafeNavigationRenderer.java
@@ -30,16 +30,13 @@
  * A wrapper over {@link NavigationRenderer} that runs all its methods in the context of provided
  * looper. It is guaranteed that all calls will be invoked in order they were called.
  */
+// TODO(deanh): Does this class even need to exist?
 /* package */ class ThreadSafeNavigationRenderer extends NavigationRenderer {
 
     private final Handler mHandler;
     private final NavigationRenderer mRenderer;
 
-    private final static int MSG_NAV_START = 1;
-    private final static int MSG_NAV_STOP = 2;
-    private final static int MSG_NAV_NEXT_TURN = 3;
-    private final static int MSG_NAV_NEXT_TURN_DISTANCE = 4;
-    private final static int MSG_EVENT = 5;
+    private final static int MSG_EVENT = 1;
 
     /** Creates thread-safe {@link NavigationRenderer}. Returns null if renderer == null */
     @Nullable
@@ -68,31 +65,6 @@
     }
 
     @Override
-    public void onStartNavigation() {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_START));
-    }
-
-    @Override
-    public void onStopNavigation() {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_STOP));
-    }
-
-    @Override
-    public void onNextTurnChanged(int event, CharSequence eventName, int turnAngle, int turnNumber,
-            Bitmap image, int turnSide) {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN,
-                new NextTurn(event, eventName, turnAngle, turnNumber, image, turnSide)));
-    }
-
-    @Override
-    public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds,
-            int displayDistanceMillis, int displayDistanceUnit) {
-        ManeuverDistance distance = new ManeuverDistance(distanceMeters, timeSeconds,
-                displayDistanceMillis, displayDistanceUnit);
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN_DISTANCE, distance));
-    }
-
-    @Override
     public void onEvent(int eventType, Bundle bundle) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_EVENT, eventType, 0, bundle));
     }
@@ -106,22 +78,6 @@
         @Override
         public void handleMessage(Message msg, NavigationRenderer renderer) {
             switch (msg.what) {
-                case MSG_NAV_START:
-                    renderer.onStartNavigation();
-                    break;
-                case MSG_NAV_STOP:
-                    renderer.onStopNavigation();
-                    break;
-                case MSG_NAV_NEXT_TURN:
-                    NextTurn nt = (NextTurn) msg.obj;
-                    renderer.onNextTurnChanged(nt.event, nt.eventName, nt.turnAngle, nt.turnNumber,
-                            nt.bitmap, nt.turnSide);
-                    break;
-                case MSG_NAV_NEXT_TURN_DISTANCE:
-                    ManeuverDistance d = (ManeuverDistance) msg.obj;
-                    renderer.onNextTurnDistanceChanged(
-                            d.meters, d.seconds, d.displayDistanceMillis, d.displayDistanceUnit);
-                    break;
                 case MSG_EVENT:
                     Bundle bundle = (Bundle) msg.obj;
                     renderer.onEvent(msg.arg1, bundle);
@@ -153,25 +109,6 @@
         return runnable.getResult();
     }
 
-    private static class NextTurn {
-        private final int event;
-        private final CharSequence eventName;
-        private final int turnAngle;
-        private final int turnNumber;
-        private final Bitmap bitmap;
-        private final int turnSide;
-
-        NextTurn(int event, CharSequence eventName, int turnAngle, int turnNumber, Bitmap bitmap,
-                int turnSide) {
-            this.event = event;
-            this.eventName = eventName;
-            this.turnAngle = turnAngle;
-            this.turnNumber = turnNumber;
-            this.bitmap = bitmap;
-            this.turnSide = turnSide;
-        }
-    }
-
     private static abstract class RunnableWithResult<T> implements Runnable {
         private volatile T result;
 
@@ -206,19 +143,4 @@
 
         public abstract void handleMessage(Message msg, T renderer);
     }
-
-    private static class ManeuverDistance {
-        final int meters;
-        final int seconds;
-        final int displayDistanceMillis;
-        final int displayDistanceUnit;
-
-        ManeuverDistance(int meters, int seconds, int displayDistanceMillis,
-                int displayDistanceUnit) {
-            this.meters = meters;
-            this.seconds = seconds;
-            this.displayDistanceMillis = displayDistanceMillis;
-            this.displayDistanceUnit = displayDistanceUnit;
-        }
-    }
 }
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index 380432f..b1828db 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.car.CarApiUtil;
 import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
@@ -26,6 +27,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -34,6 +36,7 @@
  * Provides car specific API related with package management.
  */
 public final class CarPackageManager implements CarManagerBase {
+    private static final String TAG = "CarPackageManager";
 
     /**
      * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
@@ -118,7 +121,21 @@
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
         } catch (RemoteException e) {
-            //ignore as CarApi will handle disconnection anyway.
+            // Ignore as CarApi will handle disconnection anyway.
+        }
+    }
+
+    /**
+     * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
+     *
+     * @hide
+     */
+    public void restartTask(int taskId) {
+        try {
+            mService.restartTask(taskId);
+        } catch (RemoteException e) {
+            // Ignore as CarApi will handle disconnection anyway.
+            Log.e(TAG, "Could not restart task " + taskId, e);
         }
     }
 
@@ -150,15 +167,31 @@
     }
 
     /**
-     * Check if given activity is allowed while driving.
+     * Enable/Disable Activity Blocking.  This is to provide an option for toggling app blocking
+     * behavior for development purposes.
+     * @hide
+     */
+    @TestApi
+    public void setEnableActivityBlocking(boolean enable) {
+        try {
+            mService.setEnableActivityBlocking(enable);
+        } catch (RemoteException e) {
+            //ignore as CarApi will handle disconnection anyway.
+        }
+    }
+
+    /**
+     * Check if given activity is distraction optimized, i.e, allowed in a
+     * restricted driving state
+     *
      * @param packageName
      * @param className
      * @return
      */
-    public boolean isActivityAllowedWhileDriving(String packageName, String className)
+    public boolean isActivityDistractionOptimized(String packageName, String className)
             throws CarNotConnectedException {
         try {
-            return mService.isActivityAllowedWhileDriving(packageName, className);
+            return mService.isActivityDistractionOptimized(packageName, className);
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
         } catch (RemoteException e) {
@@ -168,15 +201,17 @@
     }
 
     /**
-     * Check if given service is allowed while driving.
+     * Check if given service is distraction optimized, i.e, allowed in a restricted
+     * driving state.
+     *
      * @param packageName
      * @param className
      * @return
      */
-    public boolean isServiceAllowedWhileDriving(String packageName, String className)
+    public boolean isServiceDistractionOptimized(String packageName, String className)
             throws CarNotConnectedException {
         try {
-            return mService.isServiceAllowedWhileDriving(packageName, className);
+            return mService.isServiceDistractionOptimized(packageName, className);
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
         } catch (RemoteException e) {
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index 306db65..7210f90 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -22,7 +22,9 @@
 /** @hide */
 interface ICarPackageManager {
     void setAppBlockingPolicy(in String packageName, in CarAppBlockingPolicy policy, int flags) = 0;
-    boolean isActivityAllowedWhileDriving(in String packageName, in String className) = 1;
-    boolean isServiceAllowedWhileDriving(in String packageName, in String className) = 2;
+    boolean isActivityDistractionOptimized(in String packageName, in String className) = 1;
+    boolean isServiceDistractionOptimized(in String packageName, in String className) = 2;
     boolean isActivityBackedBySafeActivity(in ComponentName activityName) = 3;
+    void setEnableActivityBlocking(boolean enable) = 4;
+    void restartTask(int taskId) = 5;
 }
diff --git a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
index 84cdd3e..88980bf 100644
--- a/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
+++ b/car-lib/src/android/car/diagnostic/CarDiagnosticManager.java
@@ -349,8 +349,13 @@
     }
 
     /**
-     * Returns true if this vehicle supports clearing freeze frame timestamps.
+     * Returns true if this vehicle supports clearing all freeze frames.
      * This is only meaningful if freeze frame data is also supported.
+     *
+     * A return value of true for this method indicates that it is supported to call
+     * carDiagnosticManager.clearFreezeFrames()
+     * to delete all freeze frames stored in vehicle memory.
+     *
      * @return
      * @throws CarNotConnectedException
      */
@@ -365,6 +370,28 @@
         return false;
     }
 
+    /**
+     * Returns true if this vehicle supports clearing specific freeze frames by timestamp.
+     * This is only meaningful if freeze frame data is also supported.
+     *
+     * A return value of true for this method indicates that it is supported to call
+     * carDiagnosticManager.clearFreezeFrames(timestamp1, timestamp2, ...)
+     * to delete the freeze frames stored for the provided input timestamps, provided any exist.
+     *
+     * @return
+     * @throws CarNotConnectedException
+     */
+    public boolean isSelectiveClearFreezeFramesSupported() throws CarNotConnectedException {
+        try {
+            return mService.isSelectiveClearFreezeFramesSupported();
+        } catch (IllegalStateException e) {
+            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException();
+        }
+        return false;
+    }
+
     private static class CarDiagnosticEventListenerToService
             extends Stub {
         private final WeakReference<CarDiagnosticManager> mManager;
diff --git a/car-lib/src/android/car/diagnostic/ICarDiagnostic.aidl b/car-lib/src/android/car/diagnostic/ICarDiagnostic.aidl
index 3d1808f..57443d8 100644
--- a/car-lib/src/android/car/diagnostic/ICarDiagnostic.aidl
+++ b/car-lib/src/android/car/diagnostic/ICarDiagnostic.aidl
@@ -74,4 +74,10 @@
      * Returns whether the underlying HAL supports clearing freeze frames.
      */
      boolean isClearFreezeFramesSupported() = 10;
+
+    /**
+     * Returns whether the underlying HAL supports clearing specific freeze frames specified
+     * by means of their timestamps.
+     */
+     boolean isSelectiveClearFreezeFramesSupported() = 11;
 }
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.aidl
similarity index 81%
copy from car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
copy to car-lib/src/android/car/drivingstate/CarDrivingStateEvent.aidl
index 0865646..ac800ae 100644
--- a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.car.hardware.radio;
+package android.car.drivingstate;
 
-parcelable CarRadioEvent;
+parcelable CarDrivingStateEvent;
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
new file mode 100644
index 0000000..e3fa2ea
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateEvent.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Driving State related events.  Driving State of a car conveys if the car is currently parked,
+ * idling or moving.
+ *
+ * @hide
+ */
+@SystemApi
+public class CarDrivingStateEvent implements Parcelable {
+
+    // New Driving States
+    /**
+     * This is when we don't have enough information to infer the car's driving state.
+     */
+    public static final int DRIVING_STATE_UNKNOWN = -1;
+    /**
+     * Car is parked - Gear is in Parked mode.
+     */
+    public static final int DRIVING_STATE_PARKED = 0;
+    /**
+     * Car is idling.  Gear is not in Parked mode and Speed of the vehicle is zero.
+     * TODO: (b/72157869) - Should speed that differentiates moving vs idling be configurable?
+     */
+    public static final int DRIVING_STATE_IDLING = 1;
+    /**
+     * Car is moving.  Gear is not in parked mode and speed of the vehicle is non zero.
+     */
+    public static final int DRIVING_STATE_MOVING = 2;
+
+    /** @hide */
+    @IntDef({DRIVING_STATE_UNKNOWN,
+            DRIVING_STATE_PARKED,
+            DRIVING_STATE_IDLING,
+            DRIVING_STATE_MOVING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CarDrivingState {
+    }
+
+    /**
+     * Time at which this driving state was inferred based on the car's sensors.
+     * It is the elapsed time in nanoseconds since system boot.
+     */
+    public final long timeStamp;
+
+    /**
+     * The Car's driving state.
+     */
+    @CarDrivingState
+    public final int eventValue;
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(eventValue);
+        dest.writeLong(timeStamp);
+    }
+
+    public static final Parcelable.Creator<CarDrivingStateEvent> CREATOR
+            = new Parcelable.Creator<CarDrivingStateEvent>() {
+        public CarDrivingStateEvent createFromParcel(Parcel in) {
+            return new CarDrivingStateEvent(in);
+        }
+
+        public CarDrivingStateEvent[] newArray(int size) {
+            return new CarDrivingStateEvent[size];
+        }
+    };
+
+    public CarDrivingStateEvent(int value, long time) {
+        eventValue = value;
+        timeStamp = time;
+    }
+
+    private CarDrivingStateEvent(Parcel in) {
+        eventValue = in.readInt();
+        timeStamp = in.readLong();
+    }
+
+    @Override
+    public String toString() {
+        return eventValue + " " + timeStamp;
+    }
+}
diff --git a/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
new file mode 100644
index 0000000..8c2a24f
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/CarDrivingStateManager.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.ICarDrivingState;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import java.lang.ref.WeakReference;
+
+/**
+ * API to register and get driving state related information in a car.
+ * @hide
+ */
+@SystemApi
+public final class CarDrivingStateManager implements CarManagerBase {
+    private static final String TAG = "CarDrivingStateMgr";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+    private static final int MSG_HANDLE_DRIVING_STATE_CHANGE = 0;
+
+    private final Context mContext;
+    private final ICarDrivingState mDrivingService;
+    private final EventCallbackHandler mEventCallbackHandler;
+    private CarDrivingStateEventListener mDrvStateEventListener;
+    private CarDrivingStateChangeListenerToService mListenerToService;
+
+
+    /** @hide */
+    public CarDrivingStateManager(IBinder service, Context context, Handler handler) {
+        mContext = context;
+        mDrivingService = ICarDrivingState.Stub.asInterface(service);
+        mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
+    }
+
+    /** @hide */
+    @Override
+    public synchronized void onCarDisconnected() {
+            mListenerToService = null;
+            mDrvStateEventListener = null;
+    }
+
+    /**
+     * Listener Interface for clients to implement to get updated on driving state changes.
+     */
+    public interface CarDrivingStateEventListener {
+        /**
+         * Called when the car's driving state changes.
+         * @param event Car's driving state.
+         */
+        void onDrivingStateChanged(CarDrivingStateEvent event);
+    }
+
+    /**
+     * Register a {@link CarDrivingStateEventListener} to listen for driving state changes.
+     *
+     * @param listener  {@link CarDrivingStateEventListener}
+     */
+    public synchronized void registerListener(@NonNull CarDrivingStateEventListener listener)
+            throws CarNotConnectedException, IllegalArgumentException {
+        if (listener == null) {
+            if (VDBG) {
+                Log.v(TAG, "registerCarDrivingStateEventListener(): null listener");
+            }
+            throw new IllegalArgumentException("Listener is null");
+        }
+        // Check if the listener has been already registered for this event type
+        if (mDrvStateEventListener != null) {
+            if (DBG) {
+                Log.d(TAG, "Listener already registered");
+            }
+            return;
+        }
+        mDrvStateEventListener = listener;
+        try {
+            if (mListenerToService == null) {
+                mListenerToService = new CarDrivingStateChangeListenerToService(this);
+            }
+            // register to the Service for getting notified
+            mDrivingService.registerDrivingStateChangeListener(mListenerToService);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not register a listener to Driving State Service " + e);
+            throw new CarNotConnectedException(e);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Could not register a listener to Driving State Service " + e);
+            Car.checkCarNotConnectedExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Unregister the registered {@link CarDrivingStateEventListener} for the given driving event
+     * type.
+     */
+    public synchronized void unregisterListener()
+            throws CarNotConnectedException {
+        if (mDrvStateEventListener == null) {
+            if (DBG) {
+                Log.d(TAG, "Listener was not previously registered");
+            }
+            return;
+        }
+        try {
+            mDrivingService.unregisterDrivingStateChangeListener(mListenerToService);
+            mDrvStateEventListener = null;
+            mListenerToService = null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not unregister listener from Driving State Service " + e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Get the current value of the car's driving state.
+     *
+     * @return {@link CarDrivingStateEvent} corresponding to the given eventType
+     */
+    @Nullable
+    public CarDrivingStateEvent getCurrentCarDrivingState()
+            throws CarNotConnectedException {
+        try {
+            return mDrivingService.getCurrentDrivingState();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not get current driving state " + e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from the
+     * {@link com.android.car.CarDrivingStateService} across the binder interface.
+     */
+    private static class CarDrivingStateChangeListenerToService extends
+            ICarDrivingStateChangeListener.Stub {
+        private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
+
+        public CarDrivingStateChangeListenerToService(CarDrivingStateManager manager) {
+            mDrvStateMgr = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onDrivingStateChanged(CarDrivingStateEvent event) {
+            CarDrivingStateManager manager = mDrvStateMgr.get();
+            if (manager != null) {
+                manager.handleDrivingStateChanged(event);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link CarDrivingStateEvent} from the service listener
+     * {@link CarDrivingStateChangeListenerToService} and dispatches it to a handler provided
+     * to the manager
+     *
+     * @param event  {@link CarDrivingStateEvent} that has been registered to listen on
+     */
+    private void handleDrivingStateChanged(CarDrivingStateEvent event) {
+        // send a message to the handler
+        mEventCallbackHandler.sendMessage(
+                mEventCallbackHandler.obtainMessage(MSG_HANDLE_DRIVING_STATE_CHANGE, event));
+
+    }
+
+    /**
+     * Callback Handler to handle dispatching the driving state changes to the corresponding
+     * listeners
+     */
+    private static final class EventCallbackHandler extends Handler {
+        private final WeakReference<CarDrivingStateManager> mDrvStateMgr;
+
+        public EventCallbackHandler(CarDrivingStateManager manager, Looper looper) {
+            super(looper);
+            mDrvStateMgr = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            CarDrivingStateManager mgr = mDrvStateMgr.get();
+            if (mgr != null) {
+                mgr.dispatchDrivingStateChangeToClient((CarDrivingStateEvent) msg.obj);
+            }
+        }
+
+    }
+
+    /**
+     * Checks for the listener to {@link CarDrivingStateEvent} and calls it back
+     * in the callback handler thread
+     *
+     * @param event  {@link CarDrivingStateEvent}
+     */
+    private void dispatchDrivingStateChangeToClient(CarDrivingStateEvent event) {
+        if (event == null) {
+            return;
+        }
+        CarDrivingStateEventListener listener;
+        synchronized (this) {
+            listener = mDrvStateEventListener;
+        }
+        if (listener != null) {
+            listener.onDrivingStateChanged(event);
+        }
+    }
+
+}
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl b/car-lib/src/android/car/drivingstate/CarUxRestrictions.aidl
similarity index 82%
copy from car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
copy to car-lib/src/android/car/drivingstate/CarUxRestrictions.aidl
index 0865646..b80b94c 100644
--- a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictions.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.car.hardware.radio;
+package android.car.drivingstate;
 
-parcelable CarRadioEvent;
+parcelable CarUxRestrictions;
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictions.java b/car-lib/src/android/car/drivingstate/CarUxRestrictions.java
new file mode 100644
index 0000000..c6c22bc
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictions.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Car UX Restrictions event.  This contains information on the set of UX restrictions
+ * that is in place due to the car's driving state.
+ * <p>
+ * The restriction information is organized as follows:
+ * <ul>
+ * <li> When there are no restrictions in place, for example when the car is parked,
+ * <ul>
+ * <li> {@link #mRequiresDistractionOptimization} is set to false.  Apps can display activities
+ * that are not distraction optimized.
+ * <li> {@link #mActiveRestrictions} should contain UX_RESTRICTIONS_UNRESTRICTED.  Apps don't
+ * have to check for this since {@code mRequiresDistractionOptimization} is false.
+ * </ul>
+ * <li> When the driving state changes, causing the UX restrictions to come in effect,
+ * <ul>
+ * <li> {@code mRequiresDistractionOptimization} is set to true.  Apps can only display
+ * activities that are distraction optimized.  Distraction optimized activities follow the base
+ * design guidelines that provide a distraction free driving user experience.
+ * <li> In addition, apps will have to check for the content of mActiveRestrictions.
+ * {@code mActiveRestrictions} will have additional granular information on the set of UX
+ * restrictions that are in place for the current driving state.  The content of
+ * {@code mActiveRestrictions}, for the same driving state of the vehicle, could vary depending
+ * on the car maker and the market.  For example, when the car is idling, the set of active
+ * UX restrictions contained in the {@code mActiveRestrictions} will depend on the car maker
+ * and the safety standards of the market that the vehicle is deployed in.
+ * </ul>
+ * </ul>
+ * <p>
+ * Apps that intend to be run when the car is being driven need to
+ * <ul>
+ * <li> Comply with the general distraction optimization guidelines.
+ * <li> Listen and react to the UX restrictions changes as detailed above.  Since the restrictions
+ * could vary depending on the market, apps are expected to react to the restriction information
+ * and not to the absolute driving state.
+ * </ul>
+ */
+public class CarUxRestrictions implements Parcelable {
+
+    // Default fallback values for the restriction related parameters if the information is
+    // not available from the underlying service.
+    private static final int DEFAULT_MAX_LENGTH = 120;
+    private static final int DEFAULT_MAX_CUMULATIVE_ITEMS = 21;
+    private static final int DEFAULT_MAX_CONTENT_DEPTH = 3;
+
+    /**
+     * No specific restrictions in place, but baseline distraction optimization guidelines need to
+     * be adhered to when {@link #isRequiresDistractionOptimization()} is true.
+     */
+    public static final int UX_RESTRICTIONS_BASELINE = 0;
+
+    // Granular UX Restrictions that are imposed when distraction optimization is required.
+    /**
+     * No dialpad for the purpose of initiating a phone call.
+     */
+    public static final int UX_RESTRICTIONS_NO_DIALPAD = 1;
+
+    /**
+     * No filtering a list.
+     */
+    public static final int UX_RESTRICTIONS_NO_FILTERING = 0x1 << 1;
+
+    /**
+     * General purpose strings length cannot exceed the character limit provided by
+     * {@link #getMaxRestrictedStringLength()}
+     */
+    public static final int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 0x1 << 2;
+
+    /**
+     * No text entry for the purpose of searching etc.
+     */
+    public static final int UX_RESTRICTIONS_NO_KEYBOARD = 0x1 << 3;
+
+    /**
+     * No video - no animated frames > 1fps.
+     */
+    public static final int UX_RESTRICTIONS_NO_VIDEO = 0x1 << 4;
+
+    /**
+     * Limit the number of items displayed on the screen.
+     * Refer to {@link #getMaxCumulativeContentItems()} and
+     * {@link #getMaxContentDepth()} for the upper bounds on content
+     * serving.
+     */
+    public static final int UX_RESTRICTIONS_LIMIT_CONTENT = 0x1 << 5;
+
+    /**
+     * No setup that requires form entry or interaction with external devices.
+     */
+    public static final int UX_RESTRICTIONS_NO_SETUP = 0x1 << 6;
+
+    /**
+     * No Text Message (SMS, email, conversational, etc.)
+     */
+    public static final int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 0x1 << 7;
+
+    /**
+     * No text transcription (live or leave behind) of voice can be shown.
+     */
+    public static final int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 0x1 << 8;
+
+
+    /**
+     * All the above restrictions are in effect.
+     */
+    public static final int UX_RESTRICTIONS_FULLY_RESTRICTED =
+            UX_RESTRICTIONS_NO_DIALPAD | UX_RESTRICTIONS_NO_FILTERING
+                    | UX_RESTRICTIONS_LIMIT_STRING_LENGTH | UX_RESTRICTIONS_NO_KEYBOARD
+                    | UX_RESTRICTIONS_NO_VIDEO | UX_RESTRICTIONS_LIMIT_CONTENT
+                    | UX_RESTRICTIONS_NO_SETUP | UX_RESTRICTIONS_NO_TEXT_MESSAGE
+                    | UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION;
+
+    @IntDef(flag = true,
+            prefix = {"UX_RESTRICTIONS_"},
+            value = {UX_RESTRICTIONS_BASELINE,
+                    UX_RESTRICTIONS_NO_DIALPAD,
+                    UX_RESTRICTIONS_NO_FILTERING,
+                    UX_RESTRICTIONS_LIMIT_STRING_LENGTH,
+                    UX_RESTRICTIONS_NO_KEYBOARD,
+                    UX_RESTRICTIONS_NO_VIDEO,
+                    UX_RESTRICTIONS_LIMIT_CONTENT,
+                    UX_RESTRICTIONS_NO_SETUP,
+                    UX_RESTRICTIONS_NO_TEXT_MESSAGE,
+                    UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CarUxRestrictionsInfo {
+    }
+
+    private final long mTimeStamp;
+    private final boolean mRequiresDistractionOptimization;
+    @CarUxRestrictionsInfo
+    private final int mActiveRestrictions;
+    // Restriction Parameters
+    private final int mMaxStringLength;
+    private final int mMaxCumulativeContentItems;
+    private final int mMaxContentDepth;
+
+    /**
+     * Builder class for {@link CarUxRestrictions}
+     */
+    public static class Builder {
+        private final long mTimeStamp;
+        private final boolean mRequiresDistractionOptimization;
+        @CarUxRestrictionsInfo
+        private final int mActiveRestrictions;
+        // Restriction Parameters
+        private int mMaxStringLength = DEFAULT_MAX_LENGTH;
+        private int mMaxCumulativeContentItems = DEFAULT_MAX_CUMULATIVE_ITEMS;
+        private int mMaxContentDepth = DEFAULT_MAX_CONTENT_DEPTH;
+
+        public Builder(boolean reqOpt, @CarUxRestrictionsInfo int restrictions, long time) {
+            mRequiresDistractionOptimization = reqOpt;
+            mActiveRestrictions = restrictions;
+            mTimeStamp = time;
+        }
+
+        /**
+         * Set the maximum length of general purpose strings that can be displayed when
+         * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed.
+         */
+        public Builder setMaxStringLength(int length) {
+            mMaxStringLength = length;
+            return this;
+        }
+
+        /**
+         *  Set the maximum number of cumulative content items that can be displayed when
+         * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
+         */
+        public Builder setMaxCumulativeContentItems(int number) {
+            mMaxCumulativeContentItems = number;
+            return this;
+        }
+
+        /**
+         * Set the maximum number of levels that the user can navigate to when
+         * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
+         */
+        public Builder setMaxContentDepth(int depth) {
+            mMaxContentDepth = depth;
+            return this;
+        }
+
+        /**
+         * Build and return the {@link CarUxRestrictions} object
+         */
+        public CarUxRestrictions build() {
+            return new CarUxRestrictions(this);
+        }
+
+    }
+
+    /**
+     * Time at which this UX restriction event was deduced based on the car's driving state.
+     *
+     * @return Elapsed time in nanoseconds since system boot.
+     */
+    public long getTimeStamp() {
+        return mTimeStamp;
+    }
+
+    /**
+     * Conveys if the foreground activity needs to be distraction optimized.
+     * Activities that can handle distraction optimization need to be tagged as a distraction
+     * optimized in the app's manifest.
+     * <p>
+     * If the app has a foreground activity that has not been distraction optimized, the app has
+     * to switch to another activity that is distraction optimized.  Failing that, the system will
+     * stop the foreground activity.
+     *
+     * @return true if distraction optimization is required, false if not
+     */
+    public boolean isRequiresDistractionOptimization() {
+        return mRequiresDistractionOptimization;
+    }
+
+    /**
+     * A combination of the Car UX Restrictions that is active for the current state of driving.
+     *
+     * @return A combination of the above {@code @CarUxRestrictionsInfo}
+     */
+    @CarUxRestrictionsInfo
+    public int getActiveRestrictions() {
+        return mActiveRestrictions;
+    }
+
+    /**
+     * Get the maximum length of general purpose strings that can be displayed when
+     * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed.
+     *
+     * @return the maximum length of string that can be displayed
+     */
+    public int getMaxRestrictedStringLength() {
+        return mMaxStringLength;
+    }
+
+    /**
+     * Get the maximum allowable number of content items that can be displayed to a user during
+     * traversal through any one path in a single task, when
+     * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
+     * <p>
+     * For example, if a task involving only one view, this represents the maximum allowable number
+     * of content items in this single view.
+     * <p>
+     * However, if the task involves selection of a content item in an originating view that then
+     * surfaces a secondary view to the user, then this value represents the maximum allowable
+     * number of content items between the originating and secondary views combined.
+     * <p>
+     * Specifically, if the maximum allowable value was 60 and a task involved browsing a list of
+     * countries and then viewing the top songs within a country, it would be acceptable to do
+     * either of the following:
+     * <ul>
+     * <li> list 10 countries, and then display the top 50 songs after country selection, or
+     * <li> list 20 countries, and then display the top 40 songs after country selection.
+     * </ul>
+     * <p>
+     * Please refer to this and {@link #getMaxContentDepth()} to know the upper bounds on the
+     * content display when the restriction is in place.
+     *
+     * @return maximum number of cumulative items that can be displayed
+     */
+    public int getMaxCumulativeContentItems() {
+        return mMaxCumulativeContentItems;
+    }
+
+    /**
+     * Get the maximum allowable number of content depth levels or view traversals through any one
+     * path in a single task.  This is applicable when
+     * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
+     * <p>
+     * For example, if a task involves only selecting an item from a single list on one view,
+     * the task's content depth would be considered 1.
+     * <p>
+     * However, if the task involves selection of a content item in an originating view that then
+     * surfaces a secondary view to the user, the task's content depth would be considered 2.
+     * <p>
+     * Specifically, if a task involved browsing a list of countries, selecting a genre within the
+     * country, and then viewing the top songs within a country, the task's content depth would be
+     * considered 3.
+     * <p>
+     * Please refer to this and {@link #getMaxCumulativeContentItems()} to know the upper bounds on
+     * the content display when the restriction is in place.
+     *
+     * @return maximum number of cumulative items that can be displayed
+     */
+    public int getMaxContentDepth() {
+        return mMaxContentDepth;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mActiveRestrictions);
+        dest.writeLong(mTimeStamp);
+        dest.writeInt(mRequiresDistractionOptimization ? 1 : 0);
+        dest.writeInt(mMaxStringLength);
+        dest.writeInt(mMaxCumulativeContentItems);
+        dest.writeInt(mMaxContentDepth);
+    }
+
+    public static final Parcelable.Creator<CarUxRestrictions> CREATOR
+            = new Parcelable.Creator<CarUxRestrictions>() {
+        public CarUxRestrictions createFromParcel(Parcel in) {
+            return new CarUxRestrictions(in);
+        }
+
+        public CarUxRestrictions[] newArray(int size) {
+            return new CarUxRestrictions[size];
+        }
+    };
+
+    public CarUxRestrictions(CarUxRestrictions uxRestrictions) {
+        mTimeStamp = uxRestrictions.getTimeStamp();
+        mRequiresDistractionOptimization = uxRestrictions.isRequiresDistractionOptimization();
+        mActiveRestrictions = uxRestrictions.getActiveRestrictions();
+        mMaxStringLength = uxRestrictions.mMaxStringLength;
+        mMaxCumulativeContentItems = uxRestrictions.mMaxCumulativeContentItems;
+        mMaxContentDepth = uxRestrictions.mMaxContentDepth;
+    }
+
+    private CarUxRestrictions(Builder builder) {
+        mTimeStamp = builder.mTimeStamp;
+        mActiveRestrictions = builder.mActiveRestrictions;
+        mRequiresDistractionOptimization = builder.mRequiresDistractionOptimization;
+        mMaxStringLength = builder.mMaxStringLength;
+        mMaxCumulativeContentItems = builder.mMaxCumulativeContentItems;
+        mMaxContentDepth = builder.mMaxContentDepth;
+    }
+
+    private CarUxRestrictions(Parcel in) {
+        mActiveRestrictions = in.readInt();
+        mTimeStamp = in.readLong();
+        mRequiresDistractionOptimization = in.readInt() != 0;
+        mMaxStringLength = in.readInt();
+        mMaxCumulativeContentItems = in.readInt();
+        mMaxContentDepth = in.readInt();
+    }
+
+    @Override
+    public String toString() {
+        return "DO: " + mRequiresDistractionOptimization + " UxR: " + mActiveRestrictions
+                + " time: " + mTimeStamp;
+    }
+
+    /**
+     * Compares if the restrictions are the same.  Doesn't compare the timestamps.
+     *
+     * @param other the other CarUxRestrictions object
+     * @return true if the restrictions are same, false otherwise
+     */
+    public boolean isSameRestrictions(CarUxRestrictions other) {
+        if (other == null) {
+            return false;
+        }
+        if (other == this) {
+            return true;
+        }
+        return other.mRequiresDistractionOptimization == mRequiresDistractionOptimization
+                && other.mActiveRestrictions == mActiveRestrictions;
+    }
+}
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
new file mode 100644
index 0000000..57e7d60
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.ICarUxRestrictionsManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * API to register and get the User Experience restrictions imposed based on the car's driving
+ * state.
+ */
+public final class CarUxRestrictionsManager implements CarManagerBase {
+    private static final String TAG = "CarUxRManager";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+    private static final int MSG_HANDLE_UX_RESTRICTIONS_CHANGE = 0;
+
+    private final Context mContext;
+    private final ICarUxRestrictionsManager mUxRService;
+    private final EventCallbackHandler mEventCallbackHandler;
+    private OnUxRestrictionsChangedListener mUxRListener;
+    private CarUxRestrictionsChangeListenerToService mListenerToService;
+
+
+    /** @hide */
+    public CarUxRestrictionsManager(IBinder service, Context context, Handler handler) {
+        mContext = context;
+        mUxRService = ICarUxRestrictionsManager.Stub.asInterface(service);
+        mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
+    }
+
+    /** @hide */
+    @Override
+    public synchronized void onCarDisconnected() {
+        mListenerToService = null;
+        mUxRListener = null;
+    }
+
+    /**
+     * Listener Interface for clients to implement to get updated on driving state related
+     * changes.
+     */
+    public interface OnUxRestrictionsChangedListener {
+        /**
+         * Called when the UX restrictions due to a car's driving state changes.
+         *
+         * @param restrictionInfo The new UX restriction information
+         */
+        void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo);
+    }
+
+    /**
+     * Register a {@link OnUxRestrictionsChangedListener} for listening to changes in the
+     * UX Restrictions to adhere to.
+     * <p>
+     * If a listener has already been registered, it has to be unregistered before registering
+     * the new one.
+     *
+     * @param listener {@link OnUxRestrictionsChangedListener}
+     */
+    public synchronized void registerListener(@NonNull OnUxRestrictionsChangedListener listener)
+            throws CarNotConnectedException, IllegalArgumentException {
+        if (listener == null) {
+            if (VDBG) {
+                Log.v(TAG, "registerListener(): null listener");
+            }
+            throw new IllegalArgumentException("Listener is null");
+        }
+        // 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);
+            }
+            // register to the Service to listen for changes.
+            mUxRService.registerUxRestrictionsChangeListener(mListenerToService);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not register a listener to CarUxRestrictionsManagerService " + e);
+            throw new CarNotConnectedException(e);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Could not register a listener to CarUxRestrictionsManagerService " + e);
+            Car.checkCarNotConnectedExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Unregister the registered {@link OnUxRestrictionsChangedListener}
+     */
+    public synchronized void unregisterListener()
+            throws CarNotConnectedException {
+        if (mUxRListener == null) {
+            if (DBG) {
+                Log.d(TAG, "Listener was not previously registered");
+            }
+            return;
+        }
+        try {
+            mUxRService.unregisterUxRestrictionsChangeListener(mListenerToService);
+            mUxRListener = null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not unregister listener from Driving State Service " + e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Get the current UX restrictions {@link CarUxRestrictions} in place.
+     *
+     * @return current UX restrictions that is in effect.
+     */
+    @Nullable
+    public CarUxRestrictions getCurrentCarUxRestrictions()
+            throws CarNotConnectedException {
+        try {
+            return mUxRService.getCurrentUxRestrictions();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not get current UX restrictions " + e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Class that implements the listener interface and gets called back from the
+     * {@link com.android.car.CarDrivingStateService} across the binder interface.
+     */
+    private static class CarUxRestrictionsChangeListenerToService extends
+            ICarUxRestrictionsChangeListener.Stub {
+        private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
+
+        public CarUxRestrictionsChangeListenerToService(CarUxRestrictionsManager manager) {
+            mUxRestrictionsManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
+            CarUxRestrictionsManager manager = mUxRestrictionsManager.get();
+            if (manager != null) {
+                manager.handleUxRestrictionsChanged(restrictionInfo);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link CarUxRestrictions} from the service listener
+     * {@link CarUxRestrictionsChangeListenerToService} and dispatches it to a handler provided
+     * to the manager
+     *
+     * @param restrictionInfo {@link CarUxRestrictions} that has been registered to listen on
+     */
+    private void handleUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
+        // send a message to the handler
+        mEventCallbackHandler.sendMessage(mEventCallbackHandler.obtainMessage(
+                MSG_HANDLE_UX_RESTRICTIONS_CHANGE, restrictionInfo));
+    }
+
+    /**
+     * Callback Handler to handle dispatching the UX restriction changes to the corresponding
+     * listeners
+     */
+    private static final class EventCallbackHandler extends Handler {
+        private final WeakReference<CarUxRestrictionsManager> mUxRestrictionsManager;
+
+        public EventCallbackHandler(CarUxRestrictionsManager manager, Looper looper) {
+            super(looper);
+            mUxRestrictionsManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            CarUxRestrictionsManager mgr = mUxRestrictionsManager.get();
+            if (mgr != null) {
+                mgr.dispatchUxRChangeToClient((CarUxRestrictions) msg.obj);
+            }
+        }
+
+    }
+
+    /**
+     * Checks for the listeners to list of {@link CarUxRestrictions} and calls them back
+     * in the callback handler thread
+     *
+     * @param restrictionInfo {@link CarUxRestrictions}
+     */
+    private void dispatchUxRChangeToClient(CarUxRestrictions restrictionInfo) {
+        if (restrictionInfo == null) {
+            return;
+        }
+        OnUxRestrictionsChangedListener listener;
+        synchronized (this) {
+            listener = mUxRListener;
+        }
+        if (listener != null) {
+            listener.onUxRestrictionsChanged(restrictionInfo);
+        }
+    }
+}
diff --git a/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
new file mode 100644
index 0000000..30f1542
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/ICarDrivingState.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.ICarDrivingStateChangeListener;
+
+/**
+ * Binder interface for {@link android.car.drivingstate.CarDrivingStateManager}.
+ * Check {@link android.car.drivingstate.CarDrivingStateManager} APIs for expected behavior of
+ * each call.
+ *
+ * @hide
+ */
+
+interface ICarDrivingState {
+    void registerDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 0;
+    void unregisterDrivingStateChangeListener(in ICarDrivingStateChangeListener listener) = 1;
+    CarDrivingStateEvent getCurrentDrivingState() = 2;
+}
diff --git a/libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl b/car-lib/src/android/car/drivingstate/ICarDrivingStateChangeListener.aidl
similarity index 65%
copy from libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl
copy to car-lib/src/android/car/drivingstate/ICarDrivingStateChangeListener.aidl
index ca0ac83..357d7d6 100644
--- a/libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarDrivingStateChangeListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.car.vehiclemonitor;
+package android.car.drivingstate;
+
+import android.car.drivingstate.CarDrivingStateEvent;
 
 /**
- * Listener for vehicle monitor service.
+ * Binder callback for onDrivingStateChange.
  * @hide
  */
-oneway interface IVehicleMonitorListener {
-    void onAppViolation(int pid, int uid, int action, int violation) = 0;
+oneway interface ICarDrivingStateChangeListener {
+    void onDrivingStateChanged(in CarDrivingStateEvent event) = 0;
 }
diff --git a/car-lib/src/android/car/media/ICarAudioCallback.aidl b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsChangeListener.aidl
similarity index 64%
copy from car-lib/src/android/car/media/ICarAudioCallback.aidl
copy to car-lib/src/android/car/drivingstate/ICarUxRestrictionsChangeListener.aidl
index 7e01c71..cf3f89f 100644
--- a/car-lib/src/android/car/media/ICarAudioCallback.aidl
+++ b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsChangeListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
-package android.car.media;
+package android.car.drivingstate;
 
-/** @hide */
-oneway interface ICarAudioCallback {
-    void onParameterChange(in String params) = 0;
+import android.car.drivingstate.CarUxRestrictions;
+
+/**
+ * Binder callback for onUxRestrictionsChanged.
+ */
+oneway interface ICarUxRestrictionsChangeListener {
+    void onUxRestrictionsChanged(in CarUxRestrictions event) = 0;
 }
diff --git a/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
new file mode 100644
index 0000000..e5c69b8
--- /dev/null
+++ b/car-lib/src/android/car/drivingstate/ICarUxRestrictionsManager.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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 android.car.drivingstate;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.ICarUxRestrictionsChangeListener;
+
+/**
+ * Binder interface for {@link android.car.drivingstate.CarUxRestrictionsManager}.
+ * Check {@link android.car.drivingstate.CarUxRestrictionsManager} APIs for expected behavior of
+ * each call.
+ *
+ * @hide
+ */
+interface ICarUxRestrictionsManager {
+    void registerUxRestrictionsChangeListener(in ICarUxRestrictionsChangeListener listener) = 0;
+    void unregisterUxRestrictionsChangeListener(in ICarUxRestrictionsChangeListener listener) = 1;
+    CarUxRestrictions getCurrentUxRestrictions() = 2;
+}
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index 36a3858..be2b86c 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -24,6 +24,9 @@
 import android.util.SparseArray;
 
 import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Represents general information about car property such as data type and min/max ranges for car
@@ -38,26 +41,64 @@
  */
 @SystemApi
 public class CarPropertyConfig<T> implements Parcelable {
-    private final int mPropertyId;
-    private final Class<T> mType;
+    private final int mAccess;
     private final int mAreaType;
+    private final int mChangeMode;
+    private final ArrayList<Integer> mConfigArray;
+    private final String mConfigString;
+    private final float mMaxSampleRate;
+    private final float mMinSampleRate;
+    private final int mPropertyId;
     private final SparseArray<AreaConfig<T>> mSupportedAreas;
+    private final Class<T> mType;
 
-    private CarPropertyConfig(Class<T> type, int propertyId, int areaType,
-            SparseArray<AreaConfig<T>> supportedAreas) {
-        mPropertyId = propertyId;
-        mType = type;
+    private CarPropertyConfig(int access, int areaType, int changeMode,
+            ArrayList<Integer> configArray, String configString,
+            float maxSampleRate, float minSampleRate, int propertyId,
+            SparseArray<AreaConfig<T>> supportedAreas, Class<T> type) {
+        mAccess = access;
         mAreaType = areaType;
+        mChangeMode = changeMode;
+        mConfigArray = configArray;
+        mConfigString = configString;
+        mMaxSampleRate = maxSampleRate;
+        mMinSampleRate = minSampleRate;
+        mPropertyId = propertyId;
         mSupportedAreas = supportedAreas;
+        mType = type;
     }
 
-    public int getPropertyId() { return mPropertyId; }
-    public Class<T> getPropertyType() { return mType; }
-    public @VehicleAreaType.VehicleAreaTypeValue int getAreaType() { return mAreaType; }
+    public int getAccess() {
+        return mAccess;
+    }
+    public @VehicleAreaType.VehicleAreaTypeValue int getAreaType() {
+        return mAreaType;
+    }
+    public int getChangeMode() {
+        return mChangeMode;
+    }
+    public List<Integer> getConfigArray() {
+        return Collections.unmodifiableList(mConfigArray);
+    }
+    public String getConfigString() {
+        return mConfigString;
+    }
+    public float getMaxSampleRate() {
+        return mMaxSampleRate;
+    }
+    public float getMinSampleRate() {
+        return mMinSampleRate;
+    }
+    public int getPropertyId() {
+        return mPropertyId;
+    }
+    public Class<T> getPropertyType() {
+        return mType;
+    }
 
     /** Returns true if this property doesn't hold car area-specific configuration */
     public boolean isGlobalProperty() {
-        return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
+        return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
     }
 
     public int getAreaCount() {
@@ -119,26 +160,39 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mPropertyId);
-        dest.writeString(mType.getName());
+        dest.writeInt(mAccess);
         dest.writeInt(mAreaType);
+        dest.writeInt(mChangeMode);
+        dest.writeInt(mConfigArray.size());
+        for (int i = 0; i < mConfigArray.size(); i++) {
+            dest.writeInt(mConfigArray.get(i));
+        }
+        dest.writeString(mConfigString);
+        dest.writeFloat(mMaxSampleRate);
+        dest.writeFloat(mMinSampleRate);
+        dest.writeInt(mPropertyId);
         dest.writeInt(mSupportedAreas.size());
         for (int i = 0; i < mSupportedAreas.size(); i++) {
             dest.writeInt(mSupportedAreas.keyAt(i));
             dest.writeParcelable(mSupportedAreas.valueAt(i), flags);
         }
+        dest.writeString(mType.getName());
     }
 
     @SuppressWarnings("unchecked")
     private CarPropertyConfig(Parcel in) {
-        mPropertyId = in.readInt();
-        String className = in.readString();
-        try {
-            mType = (Class<T>) Class.forName(className);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalArgumentException("Class not found: " + className);
-        }
+        mAccess = in.readInt();
         mAreaType = in.readInt();
+        mChangeMode = in.readInt();
+        int configArraySize = in.readInt();
+        mConfigArray = new ArrayList<Integer>(configArraySize);
+        for (int i = 0; i < configArraySize; i++) {
+            mConfigArray.add(in.readInt());
+        }
+        mConfigString = in.readString();
+        mMaxSampleRate = in.readFloat();
+        mMinSampleRate = in.readFloat();
+        mPropertyId = in.readInt();
         int areaSize = in.readInt();
         mSupportedAreas = new SparseArray<>(areaSize);
         for (int i = 0; i < areaSize; i++) {
@@ -146,6 +200,12 @@
             AreaConfig<T> area = in.readParcelable(getClass().getClassLoader());
             mSupportedAreas.put(areaId, area);
         }
+        String className = in.readString();
+        try {
+            mType = (Class<T>) Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Class not found: " + className);
+        }
     }
 
     public static final Creator<CarPropertyConfig> CREATOR = new Creator<CarPropertyConfig>() {
@@ -162,12 +222,18 @@
 
     @Override
     public String toString() {
-        return "CarPropertyConfig{" +
-                "mPropertyId=" + mPropertyId +
-                ", mType=" + mType +
-                ", mAreaType=" + mAreaType +
-                ", mSupportedAreas=" + mSupportedAreas +
-                '}';
+        return "CarPropertyConfig{"
+                + "mPropertyId=" + mPropertyId
+                + ", mAccess=" + mAccess
+                + ", mAreaType=" + mAreaType
+                + ", mChangeMode=" + mChangeMode
+                + ", mConfigArray=" + mConfigArray
+                + ", mConfigString=" + mConfigString
+                + ", mMaxSampleRate=" + mMaxSampleRate
+                + ", mMinSampleRate=" + mMinSampleRate
+                + ", mSupportedAreas=" + mSupportedAreas
+                + ", mType=" + mType
+                + '}';
     }
 
     public static class AreaConfig<T> implements Parcelable {
@@ -225,55 +291,150 @@
         }
     }
 
-    public static <T> Builder<T> newBuilder(Class<T> clazz, int propertyId, int areaType,
-            int areaCapacity) {
-        return new Builder<>(clazz, propertyId, areaType, areaCapacity);
+    /**
+     * Prepare an instance of CarPropertyConfig
+     *
+     * @return Builder<T>
+     */
+    public static <T> Builder<T> newBuilder(Class<T> type, int propertyId, int areaType,
+                                            int areaCapacity) {
+        return new Builder<>(areaCapacity, areaType, propertyId, type);
     }
 
 
-    public static <T> Builder<T> newBuilder(Class<T> clazz, int propertyId, int areaType) {
-        return newBuilder(clazz, propertyId, areaType, 0);
+    /**
+     * Prepare an instance of CarPropertyConfig
+     *
+     * @return Builder<T>
+     */
+    public static <T> Builder<T> newBuilder(Class<T> type, int propertyId, int areaType) {
+        return new Builder<>(0, areaType, propertyId, type);
     }
 
     public static class Builder<T> {
-        private final Class<T> mType;
-        private final int mPropertyId;
+        private int mAccess;
         private final int mAreaType;
-        private final SparseArray<AreaConfig<T>> mAreas;
+        private int mChangeMode;
+        private final ArrayList<Integer> mConfigArray;
+        private String mConfigString;
+        private float mMaxSampleRate;
+        private float mMinSampleRate;
+        private final int mPropertyId;
+        private final SparseArray<AreaConfig<T>> mSupportedAreas;
+        private final Class<T> mType;
 
-        private Builder(Class<T> type, int propertyId, int areaType, int areaCapacity) {
-            mType = type;
-            mPropertyId = propertyId;
+        private Builder(int areaCapacity, int areaType, int propertyId, Class<T> type) {
             mAreaType = areaType;
+            mConfigArray = new ArrayList<>();
+            mPropertyId = propertyId;
             if (areaCapacity != 0) {
-                mAreas = new SparseArray<>(areaCapacity);
+                mSupportedAreas = new SparseArray<>(areaCapacity);
             } else {
-                mAreas = new SparseArray<>();
+                mSupportedAreas = new SparseArray<>();
             }
+            mType = type;
         }
 
+        /**
+         * Add supported areas parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
         public Builder<T> addAreas(int[] areaIds) {
             for (int id : areaIds) {
-                mAreas.put(id, null);
+                mSupportedAreas.put(id, null);
             }
             return this;
         }
 
+        /**
+         * Add area to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
         public Builder<T> addArea(int areaId) {
             return addAreaConfig(areaId, null, null);
         }
 
+        /**
+         * Add areaConfig to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
         public Builder<T> addAreaConfig(int areaId, T min, T max) {
             if (min == null && max == null) {
-                mAreas.put(areaId, null);
+                mSupportedAreas.put(areaId, null);
             } else {
-                mAreas.put(areaId, new AreaConfig<>(min, max));
+                mSupportedAreas.put(areaId, new AreaConfig<>(min, max));
             }
             return this;
         }
 
+        /**
+         * Set access parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setAccess(int access) {
+            mAccess = access;
+            return this;
+        }
+
+        /**
+         * Set changeMode parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setChangeMode(int changeMode) {
+            mChangeMode = changeMode;
+            return this;
+        }
+
+        /**
+         * Set configArray parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setConfigArray(ArrayList<Integer> configArray) {
+            mConfigArray.clear();
+            mConfigArray.addAll(configArray);
+            return this;
+        }
+
+        /**
+         * Set configString parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setConfigString(String configString) {
+            mConfigString = configString;
+            return this;
+        }
+
+        /**
+         * Set maxSampleRate parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setMaxSampleRate(float maxSampleRate) {
+            mMaxSampleRate = maxSampleRate;
+            return this;
+        }
+
+        /**
+         * Set minSampleRate parameter to CarPropertyConfig
+         *
+         * @return Builder<T>
+         */
+        public Builder<T> setMinSampleRate(float minSampleRate) {
+            mMinSampleRate = minSampleRate;
+            return this;
+        }
+
         public CarPropertyConfig<T> build() {
-            return new CarPropertyConfig<>(mType, mPropertyId, mAreaType, mAreas);
+            return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray,
+                                           mConfigString, mMaxSampleRate, mMinSampleRate,
+                                           mPropertyId, mSupportedAreas, mType);
         }
     }
 }
diff --git a/car-lib/src/android/car/hardware/CarPropertyValue.java b/car-lib/src/android/car/hardware/CarPropertyValue.java
index cd26fba..b54ac4c 100644
--- a/car-lib/src/android/car/hardware/CarPropertyValue.java
+++ b/car-lib/src/android/car/hardware/CarPropertyValue.java
@@ -18,10 +18,13 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.Charset;
 
 /**
@@ -34,20 +37,41 @@
  */
 @SystemApi
 public class CarPropertyValue<T> implements Parcelable {
-
     private final static Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     private final int mPropertyId;
     private final int mAreaId;
+    private final int mStatus;
+    private final long mTimestamp;
     private final T mValue;
 
-    public CarPropertyValue(int propertyId, T value) {
-        this(propertyId, 0, value);
-    }
+    /** @hide */
+    @IntDef({
+        STATUS_AVAILABLE,
+        STATUS_UNAVAILABLE,
+        STATUS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PropertyStatus {}
+
+    /** @hide */
+    public static final int STATUS_AVAILABLE = 0;
+
+    /** @hide */
+    public static final int STATUS_UNAVAILABLE = 1;
+
+    /** @hide */
+    public static final int STATUS_ERROR = 2;
 
     public CarPropertyValue(int propertyId, int areaId, T value) {
+        this(propertyId, areaId, 0, 0, value);
+    }
+
+    public CarPropertyValue(int propertyId, int areaId, int status, long timestamp, T value) {
         mPropertyId = propertyId;
         mAreaId = areaId;
+        mStatus = status;
+        mTimestamp = timestamp;
         mValue = value;
     }
 
@@ -55,6 +79,8 @@
     public CarPropertyValue(Parcel in) {
         mPropertyId = in.readInt();
         mAreaId = in.readInt();
+        mStatus = in.readInt();
+        mTimestamp = in.readLong();
         String valueClassName = in.readString();
         Class<?> valueClass;
         try {
@@ -94,6 +120,8 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mPropertyId);
         dest.writeInt(mAreaId);
+        dest.writeInt(mStatus);
+        dest.writeLong(mTimestamp);
 
         Class<?> valueClass = mValue == null ? null : mValue.getClass();
         dest.writeString(valueClass == null ? null : valueClass.getName());
@@ -116,6 +144,14 @@
         return mAreaId;
     }
 
+    public @PropertyStatus int getStatus() {
+        return mStatus;
+    }
+
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
     public T getValue() {
         return mValue;
     }
@@ -125,6 +161,8 @@
         return "CarPropertyValue{" +
                 "mPropertyId=0x" + toHexString(mPropertyId) +
                 ", mAreaId=0x" + toHexString(mAreaId) +
+                ", mStatus=" + mStatus +
+                ", mTimestamp=" + mTimestamp +
                 ", mValue=" + mValue +
                 '}';
     }
diff --git a/car-lib/src/android/car/hardware/CarSensorConfig.java b/car-lib/src/android/car/hardware/CarSensorConfig.java
index 8ba456b..77f8dc5 100644
--- a/car-lib/src/android/car/hardware/CarSensorConfig.java
+++ b/car-lib/src/android/car/hardware/CarSensorConfig.java
@@ -29,7 +29,7 @@
     /** List of property specific mapped elements in bundle for WHEEL_TICK_DISTANCE sensor*/
     /** @hide */
     public final static String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS =
-        "android.car.wheelTickDistanceSupportedWhheels";
+        "android.car.wheelTickDistanceSupportedWheels";
     /** @hide */
     public final static String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK =
         "android.car.wheelTickDistanceFrontLeftUmPerTick";
diff --git a/car-lib/src/android/car/hardware/CarSensorEvent.java b/car-lib/src/android/car/hardware/CarSensorEvent.java
index 52f363d..86af063 100644
--- a/car-lib/src/android/car/hardware/CarSensorEvent.java
+++ b/car-lib/src/android/car/hardware/CarSensorEvent.java
@@ -33,59 +33,43 @@
 public class CarSensorEvent implements Parcelable {
 
     /**
-     * Index in {@link #floatValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
-     * sensor. This value is fuel level in percentile.
-     */
-    public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0;
-    /**
-     * Index in {@link #floatValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
-     * sensor. This value is fuel level in coverable distance. The unit is Km.
-     */
-    public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1;
-    /**
-     * Index in {@link #intValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
-     * sensor. This value is set to 1 if fuel low level warning is on.
-     */
-    public static final int INDEX_FUEL_LOW_WARNING = 0;
-
-    /**
      *  GEAR_* represents meaning of intValues[0] for {@link CarSensorManager#SENSOR_TYPE_GEAR}
      *  sensor type.
      *  GEAR_NEUTRAL means transmission gear is in neutral state, and the car may be moving.
      */
-    public static final int GEAR_NEUTRAL    = 0;
+    public static final int GEAR_NEUTRAL    = 0x0001;
     /**
      * intValues[0] from 1 to 99 represents transmission gear number for moving forward.
      * GEAR_FIRST is for gear number 1.
      */
-    public static final int GEAR_FIRST      = 1;
+    public static final int GEAR_FIRST      = 0x0010;
     /** Gear number 2. */
-    public static final int GEAR_SECOND     = 2;
+    public static final int GEAR_SECOND     = 0x0020;
     /** Gear number 3. */
-    public static final int GEAR_THIRD      = 3;
+    public static final int GEAR_THIRD      = 0x0040;
     /** Gear number 4. */
-    public static final int GEAR_FOURTH     = 4;
+    public static final int GEAR_FOURTH     = 0x0080;
     /** Gear number 5. */
-    public static final int GEAR_FIFTH      = 5;
+    public static final int GEAR_FIFTH      = 0x0100;
     /** Gear number 6. */
-    public static final int GEAR_SIXTH      = 6;
+    public static final int GEAR_SIXTH      = 0x0200;
     /** Gear number 7. */
-    public static final int GEAR_SEVENTH    = 7;
+    public static final int GEAR_SEVENTH    = 0x0400;
     /** Gear number 8. */
-    public static final int GEAR_EIGHTH     = 8;
+    public static final int GEAR_EIGHTH     = 0x0800;
     /** Gear number 9. */
-    public static final int GEAR_NINTH      = 9;
+    public static final int GEAR_NINTH      = 0x1000;
     /** Gear number 10. */
-    public static final int GEAR_TENTH      = 10;
+    public static final int GEAR_TENTH      = 0x2000;
     /**
      * This is for transmission without specific gear number for moving forward like CVT. It tells
      * that car is in a transmission state to move it forward.
      */
-    public static final int GEAR_DRIVE      = 100;
+    public static final int GEAR_DRIVE      = 0x0008;
     /** Gear in parking state */
-    public static final int GEAR_PARK       = 101;
+    public static final int GEAR_PARK       = 0x0004;
     /** Gear in reverse */
-    public static final int GEAR_REVERSE    = 102;
+    public static final int GEAR_REVERSE    = 0x0002;
 
     /**
      * Ignition state is unknown.
@@ -108,26 +92,6 @@
     public static final int IGNITION_STATE_START = 5;
 
     /**
-     * Bitmask of driving restrictions.
-     */
-    /** No restrictions. */
-    public static final int DRIVE_STATUS_UNRESTRICTED = 0;
-    /** No video playback allowed. */
-    public static final int DRIVE_STATUS_NO_VIDEO = 0x1;
-    /** No keyboard or rotary controller input allowed. */
-    public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 0x2;
-    /** No voice input allowed. */
-    public static final int DRIVE_STATUS_NO_VOICE_INPUT = 0x4;
-    /** No setup / configuration allowed. */
-    public static final int DRIVE_STATUS_NO_CONFIG = 0x8;
-    /** Limit displayed message length. */
-    public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 0x10;
-    /** represents case where all of the above items are restricted */
-    public static final int DRIVE_STATUS_FULLY_RESTRICTED = DRIVE_STATUS_NO_VIDEO |
-            DRIVE_STATUS_NO_KEYBOARD_INPUT | DRIVE_STATUS_NO_VOICE_INPUT | DRIVE_STATUS_NO_CONFIG |
-            DRIVE_STATUS_LIMIT_MESSAGE_LEN;
-
-    /**
      * Index for {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT} in floatValues.
      * Temperature in Celsius degrees.
      */
@@ -358,12 +322,8 @@
     /** @hide */
     public static class FuelLevelData {
         public long timestamp;
-        /** Fuel level in %. If unsupported by the car, this value is -1. */
-        public int level;
-        /** Fuel as possible range in Km. If unsupported by the car, this value is -1. */
-        public float range;
-        /** If unsupported by the car, this value is false. */
-        public boolean lowFuelWarning;
+        /** Fuel level in milliliters.  Negative values indicate this property is unsupported. */
+        public float level;
 
         /** @hide */
         private FuelLevelData() {};
@@ -385,21 +345,14 @@
         }
         data.timestamp = timestamp;
         if (floatValues == null) {
-            data.level = -1;
-            data.range = -1;
+            data.level = -1.0f;
         } else {
-            if (floatValues[INDEX_FUEL_LEVEL_IN_PERCENTILE] < 0) {
-                data.level = -1;
+            if (floatValues[0] < 0) {
+                data.level = -1.0f;
             } else {
-                data.level = (int) floatValues[INDEX_FUEL_LEVEL_IN_PERCENTILE];
-            }
-            if (floatValues[INDEX_FUEL_LEVEL_IN_DISTANCE] < 0) {
-                data.range = -1;
-            } else {
-                data.range = floatValues[INDEX_FUEL_LEVEL_IN_DISTANCE];
+                data.level = floatValues[0];
             }
         }
-        data.lowFuelWarning = intValues[0] == 1;
         return data;
     }
 
@@ -488,33 +441,6 @@
     }
 
     /** @hide */
-    public static class DrivingStatusData {
-        public long timestamp;
-        public int status;
-
-        /** @hide */
-        private DrivingStatusData() {};
-    }
-
-    /**
-     * Convenience method for obtaining a {@link DrivingStatusData} object from a CarSensorEvent
-     * object with type {@link CarSensorManager#SENSOR_TYPE_DRIVING_STATUS}.
-     *
-     * @param data an optional output parameter which, if non-null, will be used by this method
-     *     instead of a newly created object.
-     * @return a DrivingStatusData object corresponding to the data contained in the CarSensorEvent.
-     * @hide
-     */
-    public DrivingStatusData getDrivingStatusData(DrivingStatusData data) {
-        checkType(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
-        if (data == null) {
-            data = new DrivingStatusData();
-        }
-        data.status = intValues[0];
-        return data;
-    }
-
-    /** @hide */
     public static class CarWheelTickDistanceData {
         public long timestamp;
         public long sensorResetCount;
@@ -609,6 +535,195 @@
     }
 
     /** @hide */
+    public static class CarFuelDoorOpenData {
+        public long timestamp;
+        public boolean fuelDoorIsOpen;
+
+        /** @hide */
+        private CarFuelDoorOpenData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarFuelDoorOpenData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_DOOR_OPEN}.
+     *
+     * @param data an optional output parameter which, if non-null, will be used by this method
+     *     instead of a newly created object.
+     * @return a CarFuelDoorOpenData object corresponding to data contained in the
+     *     CarSensorEvent.
+     * @hide
+     */
+    public CarFuelDoorOpenData getCarFuelDoorOpenData(
+        CarFuelDoorOpenData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN);
+        if (data == null) {
+            data = new CarFuelDoorOpenData();
+        }
+        data.timestamp = timestamp;
+        data.fuelDoorIsOpen = intValues[0] == 1;
+        return data;
+    }
+
+    /** @hide */
+    public static class CarEvBatteryLevelData {
+        public long timestamp;
+        /** Battery Level in Watt-hours */
+        public float evBatteryLevel;
+
+        /** @hide */
+        private CarEvBatteryLevelData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarEvBatteryLevelData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_LEVEL}.
+     *
+     * @param data an optional output parameter which, if non-null, will be used by this method
+     *     instead of a newly created object.
+     * @return a CarEvBatteryLevelData object corresponding to data contained in the
+     *     CarSensorEvent.
+     * @hide
+     */
+    public CarEvBatteryLevelData getCarEvBatteryLevelData(
+        CarEvBatteryLevelData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL);
+        if (data == null) {
+            data = new CarEvBatteryLevelData();
+        }
+        data.timestamp = timestamp;
+        if (floatValues == null) {
+            data.evBatteryLevel = -1.0f;
+        } else {
+            if (floatValues[0] < 0) {
+                data.evBatteryLevel = -1.0f;
+            } else {
+                data.evBatteryLevel = floatValues[0];
+            }
+        }
+        return data;
+    }
+
+    /** @hide */
+    public static class CarEvChargePortOpenData {
+        public long timestamp;
+        public boolean evChargePortIsOpen;
+
+        /** @hide */
+        private CarEvChargePortOpenData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarEvChargePortOpenData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_OPEN}.
+     *
+     * @param data an optional output parameter which, if non-null, will be used by this method
+     *     instead of a newly created object.
+     * @return a CarEvChargePortOpenData object corresponding to data contained in the
+     *     CarSensorEvent.
+     * @hide
+     */
+    public CarEvChargePortOpenData getCarEvChargePortOpenData(
+        CarEvChargePortOpenData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN);
+        if (data == null) {
+            data = new CarEvChargePortOpenData();
+        }
+        data.timestamp = timestamp;
+        data.evChargePortIsOpen = intValues[0] == 1;
+        return data;
+    }
+
+    /** @hide */
+    public static class CarEvChargePortConnectedData {
+        public long timestamp;
+        public boolean evChargePortIsConnected;
+
+        /** @hide */
+        private CarEvChargePortConnectedData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarEvChargePortConnectedData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED}.
+     *
+     * @param data an optional output parameter which, if non-null, will be used by this method
+     *     instead of a newly created object.
+     * @return a CarEvChargePortConnectedData object corresponding to data contained in the
+     *     CarSensorEvent.
+     * @hide
+     */
+    public CarEvChargePortConnectedData getCarEvChargePortConnectedData(
+        CarEvChargePortConnectedData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED);
+        if (data == null) {
+            data = new CarEvChargePortConnectedData();
+        }
+        data.timestamp = timestamp;
+        data.evChargePortIsConnected = intValues[0] == 1;
+        return data;
+    }
+
+    /** @hide */
+    public static class CarEvBatteryChargeRateData {
+        public long timestamp;
+        /** EV battery charging rate in mW.
+         * Positive values indicates battery being charged.  Negative values indicate discharge */
+        public float evChargeRate;
+
+        /** @hide */
+        private CarEvBatteryChargeRateData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarEvBatteryChargeRateData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_CHARGE_RATE}.
+     *
+     * @param data an optional output parameter which, if non-null, will be used by this method
+     *     instead of a newly created object.
+     * @return a CarEvBatteryChargeRateData object corresponding to data contained in the
+     *     CarSensorEvent.
+     * @hide
+     */
+    public CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(
+        CarEvBatteryChargeRateData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE);
+        if (data == null) {
+            data = new CarEvBatteryChargeRateData();
+        }
+        data.timestamp = timestamp;
+        data.evChargeRate = floatValues[0];
+        return data;
+    }
+
+    /** @hide */
+    public static class CarEngineOilLevelData {
+        public long timestamp;
+        public int engineOilLevel;
+
+        /** @hide */
+        private CarEngineOilLevelData() {};
+    }
+
+    /**
+     * Convenience method for obtaining a {@link CarEngineOilLevelData} object from a
+     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL}.
+     *
+     * @param data an optional output parameter, which, if non-null, will be used by this method
+     *      instead of a newly created object.
+     * @return a CarEngineOilLEvelData object corresponding to data contained in the CarSensorEvent.
+     * @hide
+     */
+    public CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData data) {
+        checkType(CarSensorManager.SENSOR_TYPE_ENGINE_OIL_LEVEL);
+        if (data == null) {
+            data = new CarEngineOilLevelData();
+        }
+        data.timestamp = timestamp;
+        data.engineOilLevel = intValues[0];
+        return data;
+    }
+
+    /** @hide */
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/car-lib/src/android/car/hardware/CarSensorManager.java b/car-lib/src/android/car/hardware/CarSensorManager.java
index e2bce11..2536604 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -24,30 +24,31 @@
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
+import android.car.VehiclePropertyType;
+import android.car.hardware.property.CarPropertyManager;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import com.android.car.internal.CarRatedListeners;
-import com.android.car.internal.SingleMessageHandler;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
-import java.util.function.Consumer;
+
 
 /**
  *  API for monitoring car sensor data.
  */
 public final class CarSensorManager implements CarManagerBase {
+    private static final  boolean DBG = false;
+    private static final String TAG = "CarSensorManager";
+    private final CarPropertyManager mCarPropertyMgr;
     /** @hide */
     public static final int SENSOR_TYPE_RESERVED1                   = 1;
     /**
@@ -55,53 +56,45 @@
      * Sensor data in {@link CarSensorEvent} is a float which will be >= 0.
      * This requires {@link Car#PERMISSION_SPEED} permission.
      */
-    public static final int SENSOR_TYPE_CAR_SPEED                   = 2;
+    public static final int SENSOR_TYPE_CAR_SPEED                   = 0x11600207;
     /**
      * Represents engine RPM of the car. Sensor data in {@link CarSensorEvent} is a float.
      */
-    public static final int SENSOR_TYPE_RPM                         = 3;
+    public static final int SENSOR_TYPE_RPM                         = 0x11600305;
     /**
      * Total travel distance of the car in Kilometer. Sensor data is a float.
      * This requires {@link Car#PERMISSION_MILEAGE} permission.
      */
-    public static final int SENSOR_TYPE_ODOMETER                    = 4;
+    public static final int SENSOR_TYPE_ODOMETER                    = 0x11600204;
     /**
      * Indicates fuel level of the car.
-     * In {@link CarSensorEvent}, floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_PERCENTILE}]
-     * represents fuel level in percentile (0 to 100) while
-     * floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_DISTANCE}] represents estimated range
-     * in Kilometer with the remaining fuel.
-     * Note that the gas mileage used for the estimation may not represent the current driving
-     * condition.
-     * This requires {@link Car#PERMISSION_FUEL} permission.
+     * In {@link CarSensorEvent}, represents fuel level in milliliters.
+     * This requires {@link Car#PERMISSION_ENERGY} permission.
      */
-    public static final int SENSOR_TYPE_FUEL_LEVEL                  = 5;
+    public static final int SENSOR_TYPE_FUEL_LEVEL                  = 0x11600307;
     /**
      * Represents the current status of parking brake. Sensor data in {@link CarSensorEvent} is an
      * intValues[0]. Value of 1 represents parking brake applied while 0 means the other way
      * around. For this sensor, rate in {@link #registerListener(OnSensorChangedListener, int, int)}
      * will be ignored and all changes will be notified.
      */
-    public static final int SENSOR_TYPE_PARKING_BRAKE               = 6;
+    public static final int SENSOR_TYPE_PARKING_BRAKE               = 0x11200402;
     /**
      * This represents the current position of transmission gear. Sensor data in
      * {@link CarSensorEvent} is an intValues[0]. For the meaning of the value, check
      * {@link CarSensorEvent#GEAR_NEUTRAL} and other GEAR_*.
      */
-    public static final int SENSOR_TYPE_GEAR                        = 7;
+    public static final int SENSOR_TYPE_GEAR                        = 0x11400400;
     /** @hide */
     public static final int SENSOR_TYPE_RESERVED8                   = 8;
     /**
      * Day/night sensor. Sensor data is intValues[0].
      */
-    public static final int SENSOR_TYPE_NIGHT                       = 9;
+    public static final int SENSOR_TYPE_NIGHT                       = 0x11200407;
     /** @hide */
     public static final int SENSOR_TYPE_RESERVED10                  = 10;
-    /**
-     * Represents the current driving status of car. Different user interaction should be used
-     * depending on the current driving status. Driving status is intValues[0].
-     */
-    public static final int SENSOR_TYPE_DRIVING_STATUS              = 11;
+    /** @hide */
+    public static final int SENSOR_TYPE_RESERVED11                  = 11;
     /**
      * Environment like temperature and pressure.
      */
@@ -128,7 +121,7 @@
      * Represents ignition state. The value should be one of the constants that starts with
      * IGNITION_STATE_* in {@link CarSensorEvent}.
      */
-    public static final int SENSOR_TYPE_IGNITION_STATE              = 22;
+    public static final int SENSOR_TYPE_IGNITION_STATE              = 0x11400409;
     /**
      * Represents wheel distance in millimeters.  Some cars may not have individual sensors on each
      * wheel.  If a value is not available, Long.MAX_VALUE will be reported.  The wheel distance
@@ -136,115 +129,180 @@
      * distance shall be reset to zero each time a vehicle is started by the user.
      * This requires {@link Car#PERMISSION_SPEED} permission.
      */
-    public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE         = 23;
+    public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE         = 0x11510306;
     /**
      * Set to true when ABS is active.  This sensor is event driven.
-     * This requires {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} permission.
+     * This requires {@link Car#PERMISSION_CAR_DYNAMICS_STATE} permission.
      */
-    public static final int SENSOR_TYPE_ABS_ACTIVE                  = 24;
+    public static final int SENSOR_TYPE_ABS_ACTIVE                  = 0x1120040a;
     /**
      * Set to true when traction control is active.  This sensor is event driven.
-     * This requires {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} permission.
+     * This requires {@link Car#PERMISSION_CAR_DYNAMICS_STATE} permission.
      */
-    public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE     = 25;
+    public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE     = 0x1120040b;
+    /** @hide */
+    public static final int SENSOR_TYPE_RESERVED26                  = 26;
+    /**
+     * Set to true if the fuel door is open.
+     */
+    public static final int SENSOR_TYPE_FUEL_DOOR_OPEN              = 0x11200308;
 
     /**
-     * Sensor type bigger than this is invalid. Always update this after adding a new sensor.
-     * @hide
+     * Indicates battery level of the car.
+     * In {@link CarSensorEvent}, represents battery level in WH.  floatValues[{@link
+     * CarSensorEvent#INDEX_EV_BATTERY_CAPACITY_ACTUAL}] represents the actual battery capacity in
+     * WH.  The battery degrades over time, so this value is expected to drop slowly over the life
+     * of the vehicle.
+     * This requires {@link Car#PERMISSION_ENERGY} permission.
      */
-    private static final int SENSOR_TYPE_MAX = SENSOR_TYPE_TRACTION_CONTROL_ACTIVE;
-
+    public static final int SENSOR_TYPE_EV_BATTERY_LEVEL            = 0x11600309;
     /**
-     * Sensors defined in this range [{@link #SENSOR_TYPE_VENDOR_EXTENSION_START},
-     * {@link #SENSOR_TYPE_VENDOR_EXTENSION_END}] is for each car vendor's to use.
-     * This should be only used for system app to access sensors not defined as standard types.
-     * So the sensor supported in this range can vary depending on car models / manufacturers.
-     * 3rd party apps should not use sensors in this range as they are not compatible across
-     * different cars. Additionally 3rd party apps trying to access sensor in this range will get
-     * security exception as their access is restricted to system apps.
-     *
+     * Set to true if EV charging port is open.
+     */
+    public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN         = 0x1120030a;
+    /**
+     * Set to true if EV charging port is connected.
+     */
+    public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED    = 0x1120030b;
+    /**
+     *  Indicates the instantaneous battery charging rate in mW.
+     *  This requires {@link Car#PERMISSION_ENERGY} permission.
+     */
+    public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE      = 0x1160030c;
+    /**
+     * Oil level sensor.
+     * This requires {@link Car#PERMISSION_CAR_ENGINE_DETAILED} permission
      * @hide
      */
-    public static final int SENSOR_TYPE_VENDOR_EXTENSION_START = 0x60000000;
-    public static final int SENSOR_TYPE_VENDOR_EXTENSION_END   = 0x6fffffff;
+    public static final int SENSOR_TYPE_ENGINE_OIL_LEVEL            = 0x11400303;
+
 
     /** @hide */
     @IntDef({
-        SENSOR_TYPE_CAR_SPEED,
-        SENSOR_TYPE_RPM,
-        SENSOR_TYPE_ODOMETER,
-        SENSOR_TYPE_FUEL_LEVEL,
-        SENSOR_TYPE_PARKING_BRAKE,
-        SENSOR_TYPE_GEAR,
-        SENSOR_TYPE_NIGHT,
-        SENSOR_TYPE_DRIVING_STATUS,
-        SENSOR_TYPE_ENVIRONMENT,
-        SENSOR_TYPE_IGNITION_STATE,
-        SENSOR_TYPE_WHEEL_TICK_DISTANCE,
-        SENSOR_TYPE_ABS_ACTIVE,
-        SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
+            SENSOR_TYPE_CAR_SPEED,
+            SENSOR_TYPE_RPM,
+            SENSOR_TYPE_ODOMETER,
+            SENSOR_TYPE_FUEL_LEVEL,
+            SENSOR_TYPE_PARKING_BRAKE,
+            SENSOR_TYPE_GEAR,
+            SENSOR_TYPE_NIGHT,
+            SENSOR_TYPE_ENVIRONMENT,
+            SENSOR_TYPE_IGNITION_STATE,
+            SENSOR_TYPE_WHEEL_TICK_DISTANCE,
+            SENSOR_TYPE_ABS_ACTIVE,
+            SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
+            SENSOR_TYPE_FUEL_DOOR_OPEN,
+            SENSOR_TYPE_EV_BATTERY_LEVEL,
+            SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
+            SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
+            SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
+            SENSOR_TYPE_ENGINE_OIL_LEVEL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SensorType {}
 
+    private final ArraySet<Integer> mSensorConfigIds = new ArraySet<>(Arrays.asList(new Integer[]{
+            SENSOR_TYPE_CAR_SPEED,
+            SENSOR_TYPE_RPM,
+            SENSOR_TYPE_ODOMETER,
+            SENSOR_TYPE_FUEL_LEVEL,
+            SENSOR_TYPE_PARKING_BRAKE,
+            SENSOR_TYPE_GEAR,
+            SENSOR_TYPE_NIGHT,
+            SENSOR_TYPE_ENVIRONMENT,
+            SENSOR_TYPE_IGNITION_STATE,
+            SENSOR_TYPE_WHEEL_TICK_DISTANCE,
+            SENSOR_TYPE_ABS_ACTIVE,
+            SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
+            SENSOR_TYPE_FUEL_DOOR_OPEN,
+            SENSOR_TYPE_EV_BATTERY_LEVEL,
+            SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
+            SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
+            SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
+            SENSOR_TYPE_ENGINE_OIL_LEVEL,
+    }));
+
     /** Read sensor in default normal rate set for each sensors. This is default rate. */
-    public static final int SENSOR_RATE_NORMAL  = 3;
-    public static final int SENSOR_RATE_UI = 2;
-    public static final int SENSOR_RATE_FAST = 1;
+    public static final int SENSOR_RATE_NORMAL  = 1;
+    public static final int SENSOR_RATE_UI = 5;
+    public static final int SENSOR_RATE_FAST = 10;
     /** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */
-    public static final int SENSOR_RATE_FASTEST = 0;
+    public static final int SENSOR_RATE_FASTEST = 100;
 
     /** @hide */
     @IntDef({
-        SENSOR_RATE_NORMAL,
-        SENSOR_RATE_UI,
-        SENSOR_RATE_FAST,
-        SENSOR_RATE_FASTEST
+            SENSOR_RATE_NORMAL,
+            SENSOR_RATE_UI,
+            SENSOR_RATE_FAST,
+            SENSOR_RATE_FASTEST
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SensorRate {}
 
-    private static final int MSG_SENSOR_EVENTS = 0;
-
-    private final ICarSensor mService;
-
-    private CarSensorEventListenerToService mCarSensorEventListenerToService;
+    private CarPropertyEventListenerToBase mCarPropertyEventListener = null;
 
     /**
-     * To keep record of locally active sensors. Key is sensor type. This is used as a basic lock
-     * for all client accesses.
+     * To keep record of CarPropertyEventListenerToBase
      */
-    private final SparseArray<CarSensorListeners> mActiveSensorListeners = new SparseArray<>();
+    private final HashMap<OnSensorChangedListener, CarPropertyEventListenerToBase> mListenerMap =
+            new HashMap<>();
+    /**
+     * Listener for car sensor data change.
+     * Callbacks are called in the Looper context.
+     */
+    public interface OnSensorChangedListener {
+        /**
+         * Called when there is a new sensor data from car.
+         * @param event Incoming sensor event for the given sensor type.
+         */
+        void onSensorChanged(CarSensorEvent event);
+    }
 
-    /** Handles call back into clients. */
-    private final SingleMessageHandler<CarSensorEvent> mHandlerCallback;
+    private static class CarPropertyEventListenerToBase implements
+            CarPropertyManager.CarPropertyEventListener{
+        private final WeakReference<CarSensorManager> mManager;
+        private final OnSensorChangedListener mListener;
+        CarPropertyEventListenerToBase(CarSensorManager manager, OnSensorChangedListener listener) {
+            mManager = new WeakReference<>(manager);
+            mListener = listener;
+        }
 
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            CarSensorManager manager = mManager.get();
+            if (manager != null) {
+                manager.handleOnChangeEvent(value, mListener);
+            }
+        }
 
+        @Override
+        public void onErrorEvent(int propertyId, int zone) {
+
+        }
+    }
+
+    private void handleOnChangeEvent(CarPropertyValue value, OnSensorChangedListener listener) {
+        synchronized (mListenerMap) {
+            CarSensorEvent event = createCarSensorEvent(value);
+            listener.onSensorChanged(event);
+        }
+    }
+
+    private void handleOnErrorEvent(int propertyId, int zone) {
+
+    }
     /** @hide */
     public CarSensorManager(IBinder service, Context context, Handler handler) {
-        mService = ICarSensor.Stub.asInterface(service);
-        mHandlerCallback = new SingleMessageHandler<CarSensorEvent>(handler.getLooper(),
-                MSG_SENSOR_EVENTS) {
-            @Override
-            protected void handleEvent(CarSensorEvent event) {
-                CarSensorListeners listeners;
-                synchronized (mActiveSensorListeners) {
-                    listeners = mActiveSensorListeners.get(event.sensorType);
-                }
-                if (listeners != null) {
-                    listeners.onSensorChanged(event);
-                }
-            }
-        };
+        mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
     }
 
     /** @hide */
     @Override
     public void onCarDisconnected() {
-        synchronized(mActiveSensorListeners) {
-            mActiveSensorListeners.clear();
-            mCarSensorEventListenerToService = null;
+        synchronized (mListenerMap) {
+            mListenerMap.clear();
         }
+        mCarPropertyMgr.onCarDisconnected();
     }
 
     /**
@@ -254,16 +312,28 @@
      */
     public int[] getSupportedSensors() throws CarNotConnectedException {
         try {
-            return mService.getSupportedSensors();
+            List<CarPropertyConfig> carPropertyConfigList = getPropertyList();
+            int[] supportedSensors = new int[carPropertyConfigList.size()];
+            for (int i = 0; i < supportedSensors.length; i++) {
+                supportedSensors[i] = carPropertyConfigList.get(i).getPropertyId();
+            }
+            return supportedSensors;
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException(e);
         }
         return new int[0];
     }
 
     /**
+     * Get list of properties represented by CarSensorManager for this car.
+     * @return List of CarPropertyConfig objects available via Car Cabin Manager.
+     * @throws CarNotConnectedException if the connection to the car service has been lost.
+     */
+    public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
+        return mCarPropertyMgr.getPropertyList(mSensorConfigIds);
+    }
+
+    /**
      * Tells if given sensor is supported or not.
      * @param sensorType
      * @return true if the sensor is supported.
@@ -295,18 +365,6 @@
     }
 
     /**
-     * Listener for car sensor data change.
-     * Callbacks are called in the Looper context.
-     */
-    public interface OnSensorChangedListener {
-        /**
-         * Called when there is a new sensor data from car.
-         * @param event Incoming sensor event for the given sensor type.
-         */
-        void onSensorChanged(final CarSensorEvent event);
-    }
-
-    /**
      * Register {@link OnSensorChangedListener} to get repeated sensor updates. Multiple listeners
      * can be registered for a single sensor or the same listener can be used for different sensors.
      * If the same listener is registered again for the same sensor, it will be either ignored or
@@ -314,8 +372,9 @@
      * <p>
      * Requires {@link Car#PERMISSION_SPEED} for {@link #SENSOR_TYPE_CAR_SPEED} and
      *  {@link #SENSOR_TYPE_WHEEL_TICK_DISTANCE}, {@link Car#PERMISSION_MILEAGE} for
-     *  {@link #SENSOR_TYPE_ODOMETER}, {@link Car#PERMISSION_FUEL} for
-     *  {@link #SENSOR_TYPE_FUEL_LEVEL}, or {@link Car#PERMISSION_VEHICLE_DYNAMICS_STATE} for
+     *  {@link #SENSOR_TYPE_ODOMETER}, {@link Car#PERMISSION_ENERGY} for
+     *  {@link #SENSOR_TYPE_FUEL_LEVEL} and (@link #SENSOR_TYPE_EV_BATTERY_LEVEL and
+     *  {@link #SENSOR_TYPE_EV_CHARGE_RATE}, {@link Car#PERMISSION_CAR_DYNAMICS_STATE} for
      *  {@link #SENSOR_TYPE_ABS_ACTIVE} and {@link #SENSOR_TYPE_TRACTION_CONTROL_ACTIVE}
      *
      * @param listener
@@ -333,37 +392,25 @@
      * @throws SecurityException if missing the appropriate permission
      */
     @RequiresPermission(anyOf={Manifest.permission.ACCESS_FINE_LOCATION, Car.PERMISSION_SPEED,
-            Car.PERMISSION_MILEAGE, Car.PERMISSION_FUEL, Car.PERMISSION_VEHICLE_DYNAMICS_STATE},
+            Car.PERMISSION_MILEAGE, Car.PERMISSION_ENERGY, Car.PERMISSION_CAR_DYNAMICS_STATE},
             conditional=true)
     public boolean registerListener(OnSensorChangedListener listener, @SensorType int sensorType,
             @SensorRate int rate) throws CarNotConnectedException, IllegalArgumentException {
-        assertSensorType(sensorType);
         if (rate != SENSOR_RATE_FASTEST && rate != SENSOR_RATE_NORMAL
                 && rate != SENSOR_RATE_UI && rate != SENSOR_RATE_FAST) {
             throw new IllegalArgumentException("wrong rate " + rate);
         }
-        synchronized(mActiveSensorListeners) {
-            if (mCarSensorEventListenerToService == null) {
-                mCarSensorEventListenerToService = new CarSensorEventListenerToService(this);
-            }
-            boolean needsServerUpdate = false;
-            CarSensorListeners listeners;
-            listeners = mActiveSensorListeners.get(sensorType);
-            if (listeners == null) {
-                listeners = new CarSensorListeners(rate);
-                mActiveSensorListeners.put(sensorType, listeners);
-                needsServerUpdate = true;
-            }
-            if (listeners.addAndUpdateRate(listener, rate)) {
-                needsServerUpdate = true;
-            }
-            if (needsServerUpdate) {
-                if (!registerOrUpdateSensorListener(sensorType, rate)) {
-                    return false;
-                }
-            }
+        if (mListenerMap.get(listener) == null) {
+            mCarPropertyEventListener = new CarPropertyEventListenerToBase(this, listener);
+        } else {
+            mCarPropertyEventListener = mListenerMap.get(listener);
         }
-        return true;
+        if (mCarPropertyMgr.registerListener(mCarPropertyEventListener, sensorType, rate)) {
+            mListenerMap.put(listener, mCarPropertyEventListener);
+            return true;
+        } else {
+            return false;
+        }
     }
 
     /**
@@ -373,10 +420,10 @@
      */
     public void unregisterListener(OnSensorChangedListener listener) {
         //TODO: removing listener should reset update rate, bug: 32060307
-        synchronized(mActiveSensorListeners) {
-            for (int i = 0; i < mActiveSensorListeners.size(); i++) {
-                doUnregisterListenerLocked(listener, mActiveSensorListeners.keyAt(i));
-            }
+        synchronized (mListenerMap) {
+            mCarPropertyEventListener = mListenerMap.get(listener);
+            mCarPropertyMgr.unregisterListener(mCarPropertyEventListener);
+            mListenerMap.remove(listener);
         }
     }
 
@@ -387,49 +434,10 @@
      * @param sensorType
      */
     public void unregisterListener(OnSensorChangedListener listener, @SensorType int sensorType) {
-        synchronized(mActiveSensorListeners) {
-            doUnregisterListenerLocked(listener, sensorType);
+        synchronized (mListenerMap) {
+            mCarPropertyEventListener = mListenerMap.get(listener);
         }
-    }
-
-    private void doUnregisterListenerLocked(OnSensorChangedListener listener, Integer sensor) {
-        CarSensorListeners listeners = mActiveSensorListeners.get(sensor);
-        if (listeners != null) {
-            boolean needsServerUpdate = false;
-            if (listeners.contains(listener)) {
-                needsServerUpdate = listeners.remove(listener);
-            }
-            if (listeners.isEmpty()) {
-                try {
-                    mService.unregisterSensorListener(sensor.intValue(),
-                            mCarSensorEventListenerToService);
-                } catch (RemoteException e) {
-                    //ignore
-                }
-                mActiveSensorListeners.remove(sensor);
-            } else if (needsServerUpdate) {
-                try {
-                    registerOrUpdateSensorListener(sensor, listeners.getRate());
-                } catch (CarNotConnectedException e) {
-                    // ignore
-                }
-            }
-        }
-    }
-
-    private boolean registerOrUpdateSensorListener(int sensor, int rate)
-            throws CarNotConnectedException {
-        try {
-            if (!mService.registerOrUpdateSensorListener(sensor, rate,
-                    mCarSensorEventListenerToService)) {
-                return false;
-            }
-        } catch (IllegalStateException e) {
-            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException(e);
-        }
-        return true;
+        mCarPropertyMgr.unregisterListener(mCarPropertyEventListener, sensorType);
     }
 
     /**
@@ -442,13 +450,11 @@
      */
     public CarSensorEvent getLatestSensorEvent(@SensorType int type)
             throws CarNotConnectedException {
-        assertSensorType(type);
         try {
-            return mService.getLatestSensorEvent(type);
+            CarPropertyValue propertyValue = mCarPropertyMgr.getProperty(type, 0);
+            return createCarSensorEvent(propertyValue);
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch(RemoteException e) {
-            handleCarServiceRemoteExceptionAndThrow(e);
         }
         return null;
     }
@@ -461,58 +467,38 @@
         throw new CarNotConnectedException();
     }
 
-    private void assertSensorType(int sensorType) {
-        if (sensorType == 0 || !((sensorType <= SENSOR_TYPE_MAX) ||
-                ((sensorType >= SENSOR_TYPE_VENDOR_EXTENSION_START) &&
-                        (sensorType <= SENSOR_TYPE_VENDOR_EXTENSION_END)))) {
-            throw new IllegalArgumentException("invalid sensor type " + sensorType);
-        }
-    }
-
-    private void handleOnSensorChanged(List<CarSensorEvent> events) {
-        mHandlerCallback.sendEvents(events);
-    }
-
-    private static class CarSensorEventListenerToService extends ICarSensorEventListener.Stub {
-        private final WeakReference<CarSensorManager> mManager;
-
-        public CarSensorEventListenerToService(CarSensorManager manager) {
-            mManager = new WeakReference<>(manager);
-        }
-
-        @Override
-        public void onSensorChanged(List<CarSensorEvent> events) {
-            CarSensorManager manager = mManager.get();
-            if (manager != null) {
-                manager.handleOnSensorChanged(events);
-            }
-        }
-    }
-
-    private class CarSensorListeners extends CarRatedListeners<OnSensorChangedListener> {
-        CarSensorListeners(int rate) {
-            super(rate);
-        }
-
-        void onSensorChanged(final CarSensorEvent event) {
-            // throw away old sensor data as oneway binder call can change order.
-            long updateTime = event.timestamp;
-            if (updateTime < mLastUpdateTime) {
-                Log.w(CarLibLog.TAG_SENSOR, "dropping old sensor data");
-                return;
-            }
-            mLastUpdateTime = updateTime;
-            List<OnSensorChangedListener> listeners;
-            synchronized (mActiveSensorListeners) {
-                listeners = new ArrayList<>(getListeners());
-            }
-            listeners.forEach(new Consumer<OnSensorChangedListener>() {
-                @Override
-                public void accept(OnSensorChangedListener listener) {
-                    listener.onSensorChanged(event);
+    private CarSensorEvent createCarSensorEvent(CarPropertyValue propertyValue) {
+        CarSensorEvent event = null;
+        switch (propertyValue.getPropertyId() & VehiclePropertyType.MASK) {
+            case VehiclePropertyType.FLOAT:
+                event = new CarSensorEvent(propertyValue.getPropertyId(),
+                        propertyValue.getTimestamp(), 1, 0, 0);
+                event.floatValues[0] = (float) propertyValue.getValue();
+                break;
+            case VehiclePropertyType.INT32:
+                event = new CarSensorEvent(propertyValue.getPropertyId(),
+                        propertyValue.getTimestamp(), 0, 1, 0);
+                event.intValues[0] = (int) propertyValue.getValue();
+                break;
+            case VehiclePropertyType.BOOLEAN:
+                event = new CarSensorEvent(propertyValue.getPropertyId(),
+                        propertyValue.getTimestamp(), 0, 1, 0);
+                event.intValues[0] = (boolean) propertyValue.getValue() ? 1 : 0;
+                break;
+            case VehiclePropertyType.INT64_VEC:
+                Object[] value = (Object[]) propertyValue.getValue();
+                event = new CarSensorEvent(propertyValue.getPropertyId(),
+                        propertyValue.getTimestamp(), 0, 0, value.length);
+                for (int i = 0; i < value.length; i++) {
+                    event.longValues[i] = (Long) value[i];
                 }
-            });
+                break;
+            default:
+                Log.e(TAG, "unhandled VehiclePropertyType for propId="
+                        + propertyValue.getPropertyId());
+                break;
         }
+        return event;
     }
 
     /**
@@ -527,15 +513,44 @@
      * @hide
      */
     public CarSensorConfig getSensorConfig(@SensorType int type)
-        throws CarNotConnectedException {
-        assertSensorType(type);
-        try {
-            return mService.getSensorConfig(type);
-        } catch (IllegalStateException e) {
-            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
-        } catch(RemoteException e) {
-            handleCarServiceRemoteExceptionAndThrow(e);
+            throws CarNotConnectedException {
+        Bundle b = null;
+        switch (type) {
+            case SENSOR_TYPE_WHEEL_TICK_DISTANCE:
+                List<CarPropertyConfig> propertyConfigs = mCarPropertyMgr.getPropertyList();
+                for (CarPropertyConfig p : propertyConfigs) {
+                    if (p.getPropertyId() == type) {
+                        b = createWheelDistanceTickBundle(p.getConfigArray());
+                        break;
+                    }
+                }
+                break;
+            default:
+                b = Bundle.EMPTY;
+                break;
         }
-        return new CarSensorConfig(0, Bundle.EMPTY);
+        return new CarSensorConfig(type, b);
+    }
+
+    private static final int INDEX_WHEEL_DISTANCE_ENABLE_FLAG = 0;
+    private static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
+    private static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
+    private static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
+    private static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
+    private static final int WHEEL_TICK_DISTANCE_BUNDLE_SIZE = 6;
+
+    private Bundle createWheelDistanceTickBundle(List<Integer> configArray) {
+        Bundle b = new Bundle(WHEEL_TICK_DISTANCE_BUNDLE_SIZE);
+        b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS,
+                configArray.get(INDEX_WHEEL_DISTANCE_ENABLE_FLAG));
+        b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK,
+                configArray.get(INDEX_WHEEL_DISTANCE_FRONT_LEFT));
+        b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK,
+                configArray.get(INDEX_WHEEL_DISTANCE_FRONT_RIGHT));
+        b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK,
+                configArray.get(INDEX_WHEEL_DISTANCE_REAR_RIGHT));
+        b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK,
+                configArray.get(INDEX_WHEEL_DISTANCE_REAR_LEFT));
+        return b;
     }
 }
diff --git a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
index b153d22..9f06764 100644
--- a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
+++ b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
@@ -20,15 +20,16 @@
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.util.ArraySet;
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -43,12 +44,36 @@
 
     private final static boolean DBG = false;
     private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
-    private final CarPropertyManagerBase mPropertyManager;
+    private final CarPropertyManager mPropertyManager;
 
     @GuardedBy("mLock")
-    private ArraySet<CarVendorExtensionCallback> mCallbacks;
+    private final ArraySet<CarVendorExtensionCallback> mCallbacks = new ArraySet<>();
     private final Object mLock = new Object();
 
+    @GuardedBy("mLock")
+    private CarPropertyEventListenerToBase mListenerToBase = null;
+
+    private void handleOnChangeEvent(CarPropertyValue value) {
+        Collection<CarVendorExtensionCallback> callbacks;
+        synchronized (mLock) {
+            callbacks = new ArrayList<>(mCallbacks);
+        }
+        for (CarVendorExtensionCallback l: callbacks) {
+            l.onChangeEvent(value);
+        }
+    }
+
+    private void handleOnErrorEvent(int propertyId, int zone) {
+        Collection<CarVendorExtensionCallback> listeners;
+        synchronized (mLock) {
+            listeners = new ArrayList<>(mCallbacks);
+        }
+        for (CarVendorExtensionCallback l: listeners) {
+            l.onErrorEvent(propertyId, zone);
+        }
+
+    }
+
     /**
      * Creates an instance of the {@link CarVendorExtensionManager}.
      *
@@ -56,7 +81,7 @@
      * @hide
      */
     public CarVendorExtensionManager(IBinder service, Handler handler) {
-        mPropertyManager = new CarPropertyManagerBase(service, handler, DBG, TAG);
+        mPropertyManager = new CarPropertyManager(service, handler, DBG, TAG);
     }
 
     /**
@@ -78,51 +103,50 @@
     public void registerCallback(CarVendorExtensionCallback callback)
             throws CarNotConnectedException {
         synchronized (mLock) {
-            if (mCallbacks == null) {
-                mPropertyManager.registerCallback(new CarPropertyEventCallback() {
-                    @Override
-                    public void onChangeEvent(CarPropertyValue value) {
-                        for (CarVendorExtensionCallback listener: getCallbacks()) {
-                            listener.onChangeEvent(value);
-                        }
-                    }
+            if (mCallbacks.isEmpty()) {
+                mListenerToBase = new CarPropertyEventListenerToBase(this);
+            }
 
-                    @Override
-                    public void onErrorEvent(int propertyId, int zone) {
-                        for (CarVendorExtensionCallback listener: getCallbacks()) {
-                            listener.onErrorEvent(propertyId, zone);
-                        }
-                    }
-                });
-                mCallbacks = new ArraySet<>(1 /* We expect at least one element */);
+            List<CarPropertyConfig> configs = mPropertyManager.getPropertyList();
+            for (CarPropertyConfig c : configs) {
+                // Register each individual propertyId
+                mPropertyManager.registerListener(mListenerToBase, c.getPropertyId(), 0);
             }
             mCallbacks.add(callback);
         }
     }
 
     /** Unregisters listener that was previously registered. */
-    public void unregisterCallback(CarVendorExtensionCallback callback) {
+    public void unregisterCallback(CarVendorExtensionCallback callback)
+            throws CarNotConnectedException {
         synchronized (mLock) {
             mCallbacks.remove(callback);
+            List<CarPropertyConfig> configs = mPropertyManager.getPropertyList();
+            for (CarPropertyConfig c : configs) {
+                // Register each individual propertyId
+                mPropertyManager.unregisterListener(mListenerToBase, c.getPropertyId());
+            }
             if (mCallbacks.isEmpty()) {
-                mPropertyManager.unregisterCallback();
-                mCallbacks = null;
+                mListenerToBase = null;
             }
         }
     }
 
-    /** Returns copy of listeners. Thread safe. */
-    private CarVendorExtensionCallback[] getCallbacks() {
-        synchronized (mLock) {
-            return mCallbacks.toArray(new CarVendorExtensionCallback[mCallbacks.size()]);
-        }
-    }
-
+    /** Get list of properties represented by CarVendorExtensionManager for this car. */
     public List<CarPropertyConfig> getProperties() throws CarNotConnectedException {
         return mPropertyManager.getPropertyList();
     }
 
     /**
+     * Check whether a given property is available or disabled based on the cars current state.
+     * @return true if the property is AVAILABLE, false otherwise
+     */
+    public boolean isPropertyAvailable(int propertyId, int area)
+            throws CarNotConnectedException {
+        return mPropertyManager.isPropertyAvailable(propertyId, area);
+    }
+
+    /**
      * Returns property value. Use this function for global vehicle properties.
      *
      * @param propertyClass - data type of the given property, for example property that was
@@ -144,7 +168,7 @@
      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
      *        {@code Integer.class}.
      * @param propId - property id which is matched with the one defined in vehicle HAL
-     * @param area - vehicle area (e.g. {@code VehicleAreaZone.ROW_1_LEFT}
+     * @param area - vehicle area (e.g. {@code VehicleAreaSeat.ROW_1_LEFT}
      *        or {@code VEHICLE_MIRROR_DRIVER_LEFT}
      *
      * @throws CarNotConnectedException if the connection to the car service has been lost.
@@ -178,7 +202,7 @@
      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
      *        {@code Integer.class}.
      * @param propId - property id which is matched with the one defined in vehicle HAL
-     * @param area - vehicle area (e.g. {@code VehicleAreaZone.ROW_1_LEFT}
+     * @param area - vehicle area (e.g. {@code VehicleAreaSeat.ROW_1_LEFT}
      *        or {@code VEHICLE_MIRROR_DRIVER_LEFT}
      * @param value - new value, this object should match a class provided in {@code propertyClass}
      *        argument.
@@ -195,4 +219,28 @@
     public void onCarDisconnected() {
         mPropertyManager.onCarDisconnected();
     }
+    private static class CarPropertyEventListenerToBase implements
+            CarPropertyManager.CarPropertyEventListener {
+        private final WeakReference<CarVendorExtensionManager> mManager;
+
+        CarPropertyEventListenerToBase(CarVendorExtensionManager manager) {
+            mManager = new WeakReference<>(manager);
+        }
+
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            CarVendorExtensionManager manager = mManager.get();
+            if (manager != null) {
+                manager.handleOnChangeEvent(value);
+            }
+        }
+
+        @Override
+        public void onErrorEvent(int propertyId, int zone) {
+            CarVendorExtensionManager manager = mManager.get();
+            if (manager != null) {
+                manager.handleOnErrorEvent(propertyId, zone);
+            }
+        }
+    }
 }
diff --git a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
index b925984..1dee2b0 100644
--- a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
+++ b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
@@ -23,17 +23,16 @@
 import android.car.CarNotConnectedException;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.util.ArraySet;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -43,7 +42,7 @@
  *
  * The MOVE parameter will start moving the device in the indicated direction.  Magnitude
  * indicates relative speed.  For instance, setting the WINDOW_MOVE parameter to +1 rolls
- * the window up.  Setting it to +2 (if available) will roll it up faster.
+ * the window down.  Setting it to +2 (if available) will roll it down faster.
  *
  * POSITION parameter will move the device to the desired position.  For instance, if the
  * WINDOW_POS has a range of 0-100, setting this parameter to 50 will open the window
@@ -58,11 +57,11 @@
 public final class CarCabinManager implements CarManagerBase {
     private final static boolean DBG = false;
     private final static String TAG = "CarCabinManager";
-    private final CarPropertyManagerBase mMgr;
+    private final CarPropertyManager mCarPropertyMgr;
     private final ArraySet<CarCabinEventCallback> mCallbacks = new ArraySet<>();
     private CarPropertyEventListenerToBase mListenerToBase = null;
 
-    /** Door properties are zoned by VehicleDoor */
+    /** Door properties are zoned by VehicleAreaDoor */
     /**
      * door position, int type
      * Max value indicates fully open, min value (0) indicates fully closed.
@@ -70,47 +69,47 @@
      * Some vehicles (minivans) can open the door electronically.  Hence, the ability
      * to write this property.
      */
-    public static final int ID_DOOR_POS = 0x0001;
+    public static final int ID_DOOR_POS = 0x16400b00;
     /** door move, int type
      * Positive values open the door, negative values close it.
      */
-    public static final int ID_DOOR_MOVE = 0x0002;
+    public static final int ID_DOOR_MOVE = 0x16400b01;
     /** door lock, bool type
      * 'true' indicates door is locked.
      */
-    public static final int ID_DOOR_LOCK = 0x0003;
+    public static final int ID_DOOR_LOCK = 0x16200b02;
 
-    /** Mirror properties are zoned by VehicleMirror */
+    /** Mirror properties are zoned by VehicleAreaMirror */
     /**
      * mirror z position, int type
      * Positive value indicates tilt upwards, negative value tilt downwards.
      */
-    public static final int ID_MIRROR_Z_POS = 0x1001;
+    public static final int ID_MIRROR_Z_POS = 0x14400b40;
     /** mirror z move, int type
      * Positive value tilts the mirror upwards, negative value tilts downwards.
      */
-    public static final int ID_MIRROR_Z_MOVE = 0x1002;
+    public static final int ID_MIRROR_Z_MOVE = 0x14400b41;
     /**
      * mirror y position, int type
      * Positive value indicates tilt right, negative value tilt left
      */
-    public static final int ID_MIRROR_Y_POS = 0x1003;
+    public static final int ID_MIRROR_Y_POS = 0x14400b42;
     /** mirror y move, int type
      * Positive value tilts the mirror right, negative value tilts left.
      */
-    public static final int ID_MIRROR_Y_MOVE = 0x1004;
+    public static final int ID_MIRROR_Y_MOVE = 0x14400b43;
     /**
      * mirror lock, bool type
      * True indicates mirror positions are locked and not changeable.
      */
-    public static final int ID_MIRROR_LOCK = 0x1005;
+    public static final int ID_MIRROR_LOCK = 0x11200b44;
     /**
      * mirror fold, bool type
      * True indicates mirrors are folded.
      */
-    public static final int ID_MIRROR_FOLD = 0x1006;
+    public static final int ID_MIRROR_FOLD = 0x11200b45;
 
-    /** Seat properties are zoned by VehicleSeat */
+    /** Seat properties are zoned by VehicleAreaSeat */
     /**
      * seat memory select, int type
      * This parameter selects the memory preset to use to select the seat position.
@@ -121,251 +120,277 @@
      * When the user wants to select a preset, the desired preset number (1, 2, or 3)
      * is set.
      */
-    public static final int ID_SEAT_MEMORY_SELECT = 0x2001;
+    public static final int ID_SEAT_MEMORY_SELECT = 0x15400b80;
     /**
      * seat memory set, int type
      * This setting allows the user to save the current seat position settings into
      * the selected preset slot.  The maxValue for each seat position shall match
      * the maxValue for VEHICLE_PROPERTY_SEAT_MEMORY_SELECT.
      */
-    public static final int ID_SEAT_MEMORY_SET = 0x2002;
+    public static final int ID_SEAT_MEMORY_SET = 0x15400b81;
     /**
      * seat belt buckled, bool type
      * True indicates belt is buckled.
      */
-    public static final int ID_SEAT_BELT_BUCKLED = 0x2003;
+    public static final int ID_SEAT_BELT_BUCKLED = 0x15200b82;
     /**
      * seat belt height position, int type
      * Adjusts the shoulder belt anchor point.
      * Max value indicates highest position.
      * Min value indicates lowest position.
      */
-    public static final int ID_SEAT_BELT_HEIGHT_POS = 0x2004;
+    public static final int ID_SEAT_BELT_HEIGHT_POS = 0x15400b83;
     /** seat belt height move, int type
      * Adjusts the shoulder belt anchor point.
      * Positive value moves towards highest point.
      * Negative value moves towards lowest point.
      */
-    public static final int ID_SEAT_BELT_HEIGHT_MOVE = 0x2005;
+    public static final int ID_SEAT_BELT_HEIGHT_MOVE = 0x15400b84;
     /**
      * seat fore/aft position, int type
      * Sets the seat position forward (closer to steering wheel) and backwards.
      * Max value indicates closest to wheel, min value indicates most rearward position.
      */
-    public static final int ID_SEAT_FORE_AFT_POS = 0x2006;
+    public static final int ID_SEAT_FORE_AFT_POS = 0x15400b85;
     /**
      * seat fore/aft move, int type
      * Positive value moves seat forward (closer to steering wheel).
      * Negative value moves seat rearward.
      */
-    public static final int ID_SEAT_FORE_AFT_MOVE = 0x2007;
+    public static final int ID_SEAT_FORE_AFT_MOVE = 0x15400b86;
     /**
      * seat backrest angle #1 position, int type
      * Backrest angle 1 is the actuator closest to the bottom of the seat.
      * Max value indicates angling forward towards the steering wheel.
      * Min value indicates full recline.
      */
-    public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 0x2008;
+    public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 0x15400b87;
     /** seat backrest angle #1 move, int type
      * Backrest angle 1 is the actuator closest to the bottom of the seat.
      * Positive value angles seat towards the steering wheel.
      * Negatie value angles away from steering wheel.
      */
-    public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x2009;
+    public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x15400b88;
     /**
      * seat backrest angle #2 position, int type
      * Backrest angle 2 is the next actuator up from the bottom of the seat.
      * Max value indicates angling forward towards the steering wheel.
      * Min value indicates full recline.
      */
-    public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 0x200A;
+    public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 0x15400b89;
     /** seat backrest angle #2 move, int type
      * Backrest angle 2 is the next actuator up from the bottom of the seat.
      * Positive value tilts forward towards the steering wheel.
      * Negative value tilts backwards.
      */
-    public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x200B;
+    public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x15400b8a;
     /**
      * seat height position, int type
      * Sets the seat height.
      * Max value indicates highest position.
      * Min value indicates lowest position.
      */
-    public static final int ID_SEAT_HEIGHT_POS = 0x200C;
+    public static final int ID_SEAT_HEIGHT_POS = 0x15400b8b;
     /** seat height move, int type
      * Sets the seat height.
      * Positive value raises the seat.
      * Negative value lowers the seat.
      * */
-    public static final int ID_SEAT_HEIGHT_MOVE = 0x200D;
+    public static final int ID_SEAT_HEIGHT_MOVE = 0x15400b8c;
     /**
      * seat depth position, int type
      * Sets the seat depth, distance from back rest to front edge of seat.
      * Max value indicates longest depth position.
      * Min value indicates shortest position.
      */
-    public static final int ID_SEAT_DEPTH_POS = 0x200E;
+    public static final int ID_SEAT_DEPTH_POS = 0x15400b8d;
     /** seat depth move, int type
      * Adjusts the seat depth, distance from back rest to front edge of seat.
      * Positive value increases the distance from back rest to front edge of seat.
      * Negative value decreases this distance.
      */
-    public static final int ID_SEAT_DEPTH_MOVE = 0x200F;
+    public static final int ID_SEAT_DEPTH_MOVE = 0x15400b8e;
     /**
      * seat tilt position, int type
      * Sets the seat tilt.
      * Max value indicates front edge of seat higher than back edge.
      * Min value indicates front edge of seat lower than back edge.
      */
-    public static final int ID_SEAT_TILT_POS = 0x2010;
+    public static final int ID_SEAT_TILT_POS = 0x15400b8f;
     /** seat tilt move, int type
      * Adjusts the seat tilt.
      * Positive value lifts front edge of seat higher than back edge.
      * Negative value lowers front edge of seat in relation to back edge.
      */
-    public static final int ID_SEAT_TILT_MOVE = 0x2011;
+    public static final int ID_SEAT_TILT_MOVE = 0x15400b90;
     /**
      * seat lumbar fore/aft position, int type
      * Pushes the lumbar support forward and backwards.
      * Max value indicates most forward position.
      * Min value indicates most rearward position.
      */
-    public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x2012;
+    public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x15400b91;
     /** seat lumbar fore/aft move, int type
      * Adjusts the lumbar support forwards and backwards.
      * Positive value moves lumbar support forward.
      * Negative value moves lumbar support rearward.
      */
-    public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x2013;
+    public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x15400b92;
     /**
      * seat lumbar side support position, int type
      * Sets the amount of lateral lumbar support.
      * Max value indicates widest lumbar setting (i.e. least support)
      * Min value indicates thinnest lumbar setting.
      */
-    public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x2014;
+    public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x15400b93;
     /** seat lumbar side support move, int type
      * Adjusts the amount of lateral lumbar support.
      * Positive value widens the lumbar area.
      * Negative value makes the lumbar area thinner.
      */
-    public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x2015;
+    public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x15400b94;
     /**
      * seat headrest height position, int type
      * Sets the headrest height.
      * Max value indicates tallest setting.
      * Min value indicates shortest setting.
      */
-    public static final int ID_SEAT_HEADREST_HEIGHT_POS = 0x2016;
+    public static final int ID_SEAT_HEADREST_HEIGHT_POS = 0x15400b95;
     /** seat headrest height move, int type
      * Postive value moves the headrest higher.
      * Negative value moves the headrest lower.
      */
-    public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x2017;
+    public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x15400b96;
     /**
      * seat headrest angle position, int type
      * Sets the angle of the headrest.
      * Max value indicates most upright angle.
      * Min value indicates shallowest headrest angle.
      */
-    public static final int ID_SEAT_HEADREST_ANGLE_POS = 0x2018;
+    public static final int ID_SEAT_HEADREST_ANGLE_POS = 0x15400b97;
     /** seat headrest angle move, int type
      * Adjusts the angle of the headrest.
      * Positive value angles headrest towards most upright angle.
      * Negative value angles headrest towards shallowest headrest angle.
      */
-    public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 0x2019;
+    public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 0x15400b98;
     /**
      * seat headrest fore/aft position, int type
      * Sets the headrest forwards and backwards.
      * Max value indicates position closest to front of car.
      * Min value indicates position closest to rear of car.
      */
-    public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 0x201A;
+    public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 0x15400b99;
     /** seat headrest fore/aft move, int type
      * Adjsuts the headrest forwards and backwards.
      * Positive value moves the headrest closer to front of car.
      * Negative value moves the headrest closer to rear of car.
      */
-    public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x201B;
+    public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x15400b9a;
 
-    /** Window properties are zoned by VehicleWindow */
+    /** Window properties are zoned by VehicleAreaWindow */
     /**
      * window position, int type
-     * Max = window up / closed.
-     * Min = window down / open.
+     * Max = window down / open.
+     * Min = window up / closed.
      */
-    public static final int ID_WINDOW_POS = 0x3001;
+    public static final int ID_WINDOW_POS = 0x13400bc0;
     /** window move, int type
-     * Positive value moves window up / closes window.
-     * Negative value moves window down / opens window.
+     * Positive value moves window down / opens window.
+     * Negative value moves window up / closes window.
      */
-    public static final int ID_WINDOW_MOVE = 0x3002;
-    /**
-     * window vent position, int type
-     * This feature is used to control the vent feature on a sunroof.
-     * Max = vent open.
-     * Min = vent closed.
-     */
-    public static final int ID_WINDOW_VENT_POS = 0x3003;
-    /** window vent move, int type
-     * This feature is used to control the vent feature on a sunroof.
-     * Positive value opens the vent.
-     * Negative value closes the vent.
-     */
-    public static final int ID_WINDOW_VENT_MOVE = 0x3004;
+    public static final int ID_WINDOW_MOVE = 0x13400bc1;
     /**
      * window lock, bool type
      * True indicates windows are locked and can't be moved.
      */
-    public static final int ID_WINDOW_LOCK = 0x3005;
+    public static final int ID_WINDOW_LOCK = 0x13400bc4;
 
     /** @hide */
     @IntDef({
-        ID_DOOR_POS,
-        ID_DOOR_MOVE,
-        ID_DOOR_LOCK,
-        ID_MIRROR_Z_POS,
-        ID_MIRROR_Z_MOVE,
-        ID_MIRROR_Y_POS,
-        ID_MIRROR_Y_MOVE,
-        ID_MIRROR_LOCK,
-        ID_MIRROR_FOLD,
-        ID_SEAT_MEMORY_SELECT,
-        ID_SEAT_MEMORY_SET,
-        ID_SEAT_BELT_BUCKLED,
-        ID_SEAT_BELT_HEIGHT_POS,
-        ID_SEAT_BELT_HEIGHT_MOVE,
-        ID_SEAT_FORE_AFT_POS,
-        ID_SEAT_FORE_AFT_MOVE,
-        ID_SEAT_BACKREST_ANGLE_1_POS,
-        ID_SEAT_BACKREST_ANGLE_1_MOVE,
-        ID_SEAT_BACKREST_ANGLE_2_POS,
-        ID_SEAT_BACKREST_ANGLE_2_MOVE,
-        ID_SEAT_HEIGHT_POS,
-        ID_SEAT_HEIGHT_MOVE,
-        ID_SEAT_DEPTH_POS,
-        ID_SEAT_DEPTH_MOVE,
-        ID_SEAT_TILT_POS,
-        ID_SEAT_TILT_MOVE,
-        ID_SEAT_LUMBAR_FORE_AFT_POS,
-        ID_SEAT_LUMBAR_FORE_AFT_MOVE,
-        ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
-        ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
-        ID_SEAT_HEADREST_HEIGHT_POS,
-        ID_SEAT_HEADREST_HEIGHT_MOVE,
-        ID_SEAT_HEADREST_ANGLE_POS,
-        ID_SEAT_HEADREST_ANGLE_MOVE,
-        ID_SEAT_HEADREST_FORE_AFT_POS,
-        ID_SEAT_HEADREST_FORE_AFT_MOVE,
-        ID_WINDOW_POS,
-        ID_WINDOW_MOVE,
-        ID_WINDOW_VENT_POS,
-        ID_WINDOW_VENT_MOVE,
-        ID_WINDOW_LOCK
+            ID_DOOR_POS,
+            ID_DOOR_MOVE,
+            ID_DOOR_LOCK,
+            ID_MIRROR_Z_POS,
+            ID_MIRROR_Z_MOVE,
+            ID_MIRROR_Y_POS,
+            ID_MIRROR_Y_MOVE,
+            ID_MIRROR_LOCK,
+            ID_MIRROR_FOLD,
+            ID_SEAT_MEMORY_SELECT,
+            ID_SEAT_MEMORY_SET,
+            ID_SEAT_BELT_BUCKLED,
+            ID_SEAT_BELT_HEIGHT_POS,
+            ID_SEAT_BELT_HEIGHT_MOVE,
+            ID_SEAT_FORE_AFT_POS,
+            ID_SEAT_FORE_AFT_MOVE,
+            ID_SEAT_BACKREST_ANGLE_1_POS,
+            ID_SEAT_BACKREST_ANGLE_1_MOVE,
+            ID_SEAT_BACKREST_ANGLE_2_POS,
+            ID_SEAT_BACKREST_ANGLE_2_MOVE,
+            ID_SEAT_HEIGHT_POS,
+            ID_SEAT_HEIGHT_MOVE,
+            ID_SEAT_DEPTH_POS,
+            ID_SEAT_DEPTH_MOVE,
+            ID_SEAT_TILT_POS,
+            ID_SEAT_TILT_MOVE,
+            ID_SEAT_LUMBAR_FORE_AFT_POS,
+            ID_SEAT_LUMBAR_FORE_AFT_MOVE,
+            ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
+            ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+            ID_SEAT_HEADREST_HEIGHT_POS,
+            ID_SEAT_HEADREST_HEIGHT_MOVE,
+            ID_SEAT_HEADREST_ANGLE_POS,
+            ID_SEAT_HEADREST_ANGLE_MOVE,
+            ID_SEAT_HEADREST_FORE_AFT_POS,
+            ID_SEAT_HEADREST_FORE_AFT_MOVE,
+            ID_WINDOW_POS,
+            ID_WINDOW_MOVE,
+            ID_WINDOW_LOCK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PropertyId {}
+    private final ArraySet<Integer> mCabinPropertyIds = new ArraySet<>(Arrays.asList(new Integer[]{
+            ID_DOOR_POS,
+            ID_DOOR_MOVE,
+            ID_DOOR_LOCK,
+            ID_MIRROR_Z_POS,
+            ID_MIRROR_Z_MOVE,
+            ID_MIRROR_Y_POS,
+            ID_MIRROR_Y_MOVE,
+            ID_MIRROR_LOCK,
+            ID_MIRROR_FOLD,
+            ID_SEAT_MEMORY_SELECT,
+            ID_SEAT_MEMORY_SET,
+            ID_SEAT_BELT_BUCKLED,
+            ID_SEAT_BELT_HEIGHT_POS,
+            ID_SEAT_BELT_HEIGHT_MOVE,
+            ID_SEAT_FORE_AFT_POS,
+            ID_SEAT_FORE_AFT_MOVE,
+            ID_SEAT_BACKREST_ANGLE_1_POS,
+            ID_SEAT_BACKREST_ANGLE_1_MOVE,
+            ID_SEAT_BACKREST_ANGLE_2_POS,
+            ID_SEAT_BACKREST_ANGLE_2_MOVE,
+            ID_SEAT_HEIGHT_POS,
+            ID_SEAT_HEIGHT_MOVE,
+            ID_SEAT_DEPTH_POS,
+            ID_SEAT_DEPTH_MOVE,
+            ID_SEAT_TILT_POS,
+            ID_SEAT_TILT_MOVE,
+            ID_SEAT_LUMBAR_FORE_AFT_POS,
+            ID_SEAT_LUMBAR_FORE_AFT_MOVE,
+            ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
+            ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+            ID_SEAT_HEADREST_HEIGHT_POS,
+            ID_SEAT_HEADREST_HEIGHT_MOVE,
+            ID_SEAT_HEADREST_ANGLE_POS,
+            ID_SEAT_HEADREST_ANGLE_MOVE,
+            ID_SEAT_HEADREST_FORE_AFT_POS,
+            ID_SEAT_HEADREST_FORE_AFT_MOVE,
+            ID_WINDOW_POS,
+            ID_WINDOW_MOVE,
+            ID_WINDOW_LOCK
+    }));
 
     /**
      * Application registers CarCabinEventCallback object to receive updates and changes to
@@ -386,7 +411,8 @@
         void onErrorEvent(@PropertyId int propertyId, int zone);
     }
 
-    private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
+    private static class CarPropertyEventListenerToBase implements
+            CarPropertyManager.CarPropertyEventListener{
         private final WeakReference<CarCabinManager> mManager;
 
         public CarPropertyEventListenerToBase(CarCabinManager manager) {
@@ -442,7 +468,7 @@
      * @hide
      */
     public CarCabinManager(IBinder service, Context context, Handler handler) {
-        mMgr = new CarPropertyManagerBase(service, handler, DBG, TAG);
+        mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
     }
 
     /**
@@ -463,9 +489,15 @@
             CarNotConnectedException {
         if (mCallbacks.isEmpty()) {
             mListenerToBase = new CarPropertyEventListenerToBase(this);
-            mMgr.registerCallback(mListenerToBase);
+        }
+        List<CarPropertyConfig> configs = getPropertyList();
+        for (CarPropertyConfig c : configs) {
+            // Register each individual propertyId
+            mCarPropertyMgr.registerListener(mListenerToBase, c.getPropertyId(), 0);
         }
         mCallbacks.add(callback);
+
+
     }
 
     /**
@@ -473,21 +505,26 @@
      * this listener, all listening will be stopped.
      * @param callback
      */
-    public synchronized void unregisterCallback(CarCabinEventCallback callback) {
+    public synchronized void unregisterCallback(CarCabinEventCallback callback)
+            throws CarNotConnectedException {
         mCallbacks.remove(callback);
+        List<CarPropertyConfig> configs = getPropertyList();
+        for (CarPropertyConfig c : configs) {
+            // Register each individual propertyId
+            mCarPropertyMgr.unregisterListener(mListenerToBase, c.getPropertyId());
+        }
         if (mCallbacks.isEmpty()) {
-            mMgr.unregisterCallback();
             mListenerToBase = null;
         }
     }
 
     /**
-     * Get list of properties available to Car Cabin Manager
+     * Get list of properties represented by CarCabinManager for this car.
      * @return List of CarPropertyConfig objects available via Car Cabin Manager.
      * @throws CarNotConnectedException if the connection to the car service has been lost.
      */
     public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
-        return mMgr.getPropertyList();
+        return mCarPropertyMgr.getPropertyList(mCabinPropertyIds);
     }
 
     /**
@@ -499,7 +536,7 @@
      */
     public boolean getBooleanProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getBooleanProperty(propertyId, area);
+        return mCarPropertyMgr.getBooleanProperty(propertyId, area);
     }
 
     /**
@@ -511,7 +548,7 @@
      */
     public float getFloatProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getFloatProperty(propertyId, area);
+        return mCarPropertyMgr.getFloatProperty(propertyId, area);
     }
 
     /**
@@ -523,7 +560,7 @@
      */
     public int getIntProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getIntProperty(propertyId, area);
+        return mCarPropertyMgr.getIntProperty(propertyId, area);
     }
 
     /**
@@ -535,7 +572,9 @@
      */
     public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val)
             throws CarNotConnectedException {
-        mMgr.setBooleanProperty(propertyId, area, val);
+        if (mCabinPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
+        }
     }
 
     /**
@@ -547,7 +586,9 @@
      */
     public void setFloatProperty(@PropertyId int propertyId, int area, float val)
             throws CarNotConnectedException {
-        mMgr.setFloatProperty(propertyId, area, val);
+        if (mCabinPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setFloatProperty(propertyId, area, val);
+        }
     }
 
     /**
@@ -559,12 +600,14 @@
      */
     public void setIntProperty(@PropertyId int propertyId, int area, int val)
             throws CarNotConnectedException {
-        mMgr.setIntProperty(propertyId, area, val);
+        if (mCabinPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setIntProperty(propertyId, area, val);
+        }
     }
 
     /** @hide */
     @Override
     public void onCarDisconnected() {
-        mMgr.onCarDisconnected();
+        mCarPropertyMgr.onCarDisconnected();
     }
 }
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index a2f6e6d..c953d6f 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -23,16 +23,17 @@
 import android.car.CarNotConnectedException;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.util.ArraySet;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -44,10 +45,11 @@
 public final class CarHvacManager implements CarManagerBase {
     private final static boolean DBG = false;
     private final static String TAG = "CarHvacManager";
-    private final CarPropertyManagerBase mMgr;
+    private final CarPropertyManager mCarPropertyMgr;
     private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>();
     private CarPropertyEventListenerToBase mListenerToBase = null;
 
+
     /**
      * HVAC property IDs for get/set methods
      */
@@ -59,31 +61,24 @@
      * Mirror defrosters state, bool type
      * true indicates mirror defroster is on
      */
-    public static final int ID_MIRROR_DEFROSTER_ON = 0x0001;
+    public static final int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
     /**
      * Steering wheel temp, int type
      * Positive values indicate heating.
      * Negative values indicate cooling
      */
-    public static final int ID_STEERING_WHEEL_TEMP = 0x0002;
+    public static final int ID_STEERING_WHEEL_HEAT = 0x1140050d;
     /**
      * Outside air temperature, float type
-     * Value is in degrees of ID_TEMPERATURE_UNITS
+     * Value is in degrees Celsius
      */
-    public static final int ID_OUTSIDE_AIR_TEMP = 0x0003;
+    public static final int ID_OUTSIDE_AIR_TEMP = 0x11600703;
     /**
      * Temperature units being used, int type
      *  0x30 = Celsius
      *  0x31 = Fahrenheit
      */
-    public static final int ID_TEMPERATURE_UNITS = 0x0004;
-
-
-    /**
-     * The maximum id that can be assigned to global (non-zoned) property.
-     * @hide
-     */
-    public static final int ID_MAX_GLOBAL_PROPERTY_ID = 0x3fff;
+    public static final int ID_TEMPERATURE_DISPLAY_UNITS = 0x1140050e;
 
     /**
      * ID_ZONED_* represents properties available on a per-zone basis.  All zones in a car are
@@ -91,99 +86,100 @@
      */
     /**
      * Temperature setpoint, float type
-     * Temperature set by the user, units are determined by ID_TEMPERTURE_UNITS property.
+     * Temperature set by the user, units are in degrees Celsius.
      */
-    public static final int ID_ZONED_TEMP_SETPOINT = 0x4001;
+    public static final int ID_ZONED_TEMP_SETPOINT = 0x15600503;
     /**
      * Actual temperature, float type
      * Actual zone temperature is read only value, in terms of F or C.
      */
-    public static final int ID_ZONED_TEMP_ACTUAL = 0x4002;
+    public static final int ID_ZONED_TEMP_ACTUAL = 0x15600502;
     /**
      * HVAC system powered on / off, bool type
      * In many vehicles, if the HVAC system is powered off, the SET and GET command will
      * throw an IllegalStateException.  To correct this, need to turn on the HVAC module first
      * before manipulating a parameter.
      */
-    public static final int ID_ZONED_HVAC_POWER_ON = 0x4003;
+    public static final int ID_ZONED_HVAC_POWER_ON = 0x15200510;
     /**
      * Fan speed setpoint, int type
      * Fan speed is an integer from 0-n, depending on number of fan speeds available.
      */
-    public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x4004;
+    public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x15400500;
     /**
      * Actual fan speed, int type
      * Actual fan speed is a read-only value, expressed in RPM.
      */
-    public static final int ID_ZONED_FAN_SPEED_RPM = 0x4005;
-    /** Fan position available, int type
-     *  Fan position is a bitmask of positions available for each zone.
-     */
-    public static final int ID_ZONED_FAN_POSITION_AVAILABLE = 0x4006;
+    public static final int ID_ZONED_FAN_SPEED_RPM = 0x1540050f;
     /**
-     * Current fan position setting, int type. The value must be one of the FAN_POSITION_*
-     * constants declared in {@link CarHvacManager}.
+     *  Fan direction available, int vector type
+     *  Fan direction is a bitmask of directions available for each zone.
      */
-    public static final int ID_ZONED_FAN_POSITION = 0x4007;
+    public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x15410511;
+    /**
+     * Current fan direction setting, int type. The value must be one of the FAN_DIRECTION_AVAILABLE
+     * values declared above.
+     */
+    public static final int ID_ZONED_FAN_DIRECTION = 0x15400501;
     /**
      * Seat temperature, int type
      * Seat temperature is negative for cooling, positive for heating.  Temperature is a
      * setting, i.e. -3 to 3 for 3 levels of cooling and 3 levels of heating.
      */
-    public static final int ID_ZONED_SEAT_TEMP = 0x4008;
+    public static final int ID_ZONED_SEAT_TEMP = 0x1540050b;
     /**
      * Air ON, bool type
      * true indicates AC is ON.
      */
-    public static final int ID_ZONED_AC_ON = 0x4009;
+    public static final int ID_ZONED_AC_ON = 0x15200505;
     /**
      * Automatic Mode ON, bool type
      * true indicates HVAC is in automatic mode
      */
-    public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x400A;
+    public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x1520050A;
     /**
      * Air recirculation ON, bool type
      * true indicates recirculation is active.
      */
-    public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x400B;
+    public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x15200508;
     /**
      * Max AC ON, bool type
      * true indicates MAX AC is ON
      */
-    public static final int ID_ZONED_MAX_AC_ON = 0x400C;
+    public static final int ID_ZONED_MAX_AC_ON = 0x15200506;
     /** Dual zone ON, bool type
      * true indicates dual zone mode is ON
      */
-    public static final int ID_ZONED_DUAL_ZONE_ON = 0x400D;
+    public static final int ID_ZONED_DUAL_ZONE_ON = 0x15200509;
     /**
      * Max Defrost ON, bool type
      * true indicates max defrost is active.
      */
-    public static final int ID_ZONED_MAX_DEFROST_ON = 0x400E;
+    public static final int ID_ZONED_MAX_DEFROST_ON = 0x15200507;
     /**
      * Automatic recirculation mode ON
      * true indicates recirculation is in automatic mode
      */
-    public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x400F;
+    public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x15200512;
     /**
      * Defroster ON, bool type
      * Defroster controls are based on window position.
      * True indicates the defroster is ON.
      */
-    public static final int ID_WINDOW_DEFROSTER_ON = 0x5001;
+    public static final int ID_WINDOW_DEFROSTER_ON = 0x13200504;
 
     /** @hide */
     @IntDef({
             ID_MIRROR_DEFROSTER_ON,
-            ID_STEERING_WHEEL_TEMP,
+            ID_STEERING_WHEEL_HEAT,
             ID_OUTSIDE_AIR_TEMP,
-            ID_TEMPERATURE_UNITS,
+            ID_TEMPERATURE_DISPLAY_UNITS,
             ID_ZONED_TEMP_SETPOINT,
             ID_ZONED_TEMP_ACTUAL,
             ID_ZONED_FAN_SPEED_SETPOINT,
             ID_ZONED_FAN_SPEED_RPM,
-            ID_ZONED_FAN_POSITION_AVAILABLE,
-            ID_ZONED_FAN_POSITION,
+            ID_ZONED_FAN_DIRECTION_AVAILABLE,
+            ID_ZONED_FAN_DIRECTION,
             ID_ZONED_SEAT_TEMP,
             ID_ZONED_AC_ON,
             ID_ZONED_AUTOMATIC_MODE_ON,
@@ -193,36 +189,49 @@
             ID_ZONED_MAX_DEFROST_ON,
             ID_ZONED_HVAC_POWER_ON,
             ID_ZONED_HVAC_AUTO_RECIRC_ON,
-            ID_WINDOW_DEFROSTER_ON,
+            ID_WINDOW_DEFROSTER_ON
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PropertyId {}
+    private final ArraySet<Integer> mHvacPropertyIds = new ArraySet<>(Arrays.asList(new Integer [] {
+            ID_MIRROR_DEFROSTER_ON,
+            ID_STEERING_WHEEL_HEAT,
+            ID_OUTSIDE_AIR_TEMP,
+            ID_TEMPERATURE_DISPLAY_UNITS,
+            ID_ZONED_TEMP_SETPOINT,
+            ID_ZONED_TEMP_ACTUAL,
+            ID_ZONED_FAN_SPEED_SETPOINT,
+            ID_ZONED_FAN_SPEED_RPM,
+            ID_ZONED_FAN_DIRECTION_AVAILABLE,
+            ID_ZONED_FAN_DIRECTION,
+            ID_ZONED_SEAT_TEMP,
+            ID_ZONED_AC_ON,
+            ID_ZONED_AUTOMATIC_MODE_ON,
+            ID_ZONED_AIR_RECIRCULATION_ON,
+            ID_ZONED_MAX_AC_ON,
+            ID_ZONED_DUAL_ZONE_ON,
+            ID_ZONED_MAX_DEFROST_ON,
+            ID_ZONED_HVAC_POWER_ON,
+            ID_ZONED_HVAC_AUTO_RECIRC_ON,
+            ID_WINDOW_DEFROSTER_ON
+    }));
+
 
     /**
-     * Represents fan position when air flows through face directed vents.
-     * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property.
+     * Represents fan direction when air flows through face directed vents.
+     * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
-    public static final int FAN_POSITION_FACE = 1;
+    public static final int FAN_DIRECTION_FACE = 0x1;
     /**
-     * Represents fan position when air flows through floor directed vents.
-     * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property.
+     * Represents fan direction when air flows through floor directed vents.
+     * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
-    public static final int FAN_POSITION_FLOOR = 2;
+    public static final int FAN_DIRECTION_FLOOR = 0x2;
     /**
-     * Represents fan position when air flows through face and floor directed vents.
-     * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property.
+     * Represents fan direction when air flows through defrost vents.
+     * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
      */
-    public static final int FAN_POSITION_FACE_AND_FLOOR = 3;
-    /**
-     * Represents fan position when air flows through defrost vents.
-     * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property.
-     */
-    public static final int FAN_POSITION_DEFROST = 4;
-    /**
-     * Represents fan position when air flows through defrost and floor directed vents.
-     * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property.
-     */
-    public static final int FAN_POSITION_DEFROST_AND_FLOOR = 5;
+    public static final int FAN_DIRECTION_DEFROST = 0x4;
 
     /**
      * Application registers {@link CarHvacEventCallback} object to receive updates and changes to
@@ -243,7 +252,8 @@
         void onErrorEvent(@PropertyId int propertyId, int zone);
     }
 
-    private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
+    private static class CarPropertyEventListenerToBase implements
+            CarPropertyManager.CarPropertyEventListener {
         private final WeakReference<CarHvacManager> mManager;
 
         public CarPropertyEventListenerToBase(CarHvacManager manager) {
@@ -301,28 +311,22 @@
      * @hide
      */
     public CarHvacManager(IBinder service, Context context, Handler handler) {
-        mMgr = new CarPropertyManagerBase(service, handler, DBG, TAG);
+        mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
     }
-
     /**
-     * Determine if a property is zoned or not.
-     * @param propertyId
-     * @return true if property is a zoned type.
-     */
-    public static boolean isZonedProperty(@PropertyId int propertyId) {
-        return propertyId > ID_MAX_GLOBAL_PROPERTY_ID;
-    }
-
-    /**
-     * Implement wrappers for contained CarPropertyManagerBase object
+     * Implement wrappers for contained CarPropertyManager object
      * @param callback
      * @throws CarNotConnectedException
      */
-    public synchronized void registerCallback(CarHvacEventCallback callback) throws
-            CarNotConnectedException {
+    public synchronized void registerCallback(CarHvacEventCallback callback)
+            throws CarNotConnectedException {
         if (mCallbacks.isEmpty()) {
             mListenerToBase = new CarPropertyEventListenerToBase(this);
-            mMgr.registerCallback(mListenerToBase);
+        }
+        List<CarPropertyConfig> configs = getPropertyList();
+        for (CarPropertyConfig c : configs) {
+            // Register each individual propertyId
+            mCarPropertyMgr.registerListener(mListenerToBase, c.getPropertyId(), 0);
         }
         mCallbacks.add(callback);
     }
@@ -334,19 +338,37 @@
      */
     public synchronized void unregisterCallback(CarHvacEventCallback callback) {
         mCallbacks.remove(callback);
+        try {
+            List<CarPropertyConfig> configs = getPropertyList();
+            for (CarPropertyConfig c : configs) {
+                // Register each individual propertyId
+                mCarPropertyMgr.unregisterListener(mListenerToBase, c.getPropertyId());
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "getPropertyList exception ", e);
+        }
         if (mCallbacks.isEmpty()) {
-            mMgr.unregisterCallback();
+            mCarPropertyMgr.unregisterListener(mListenerToBase);
             mListenerToBase = null;
         }
     }
 
     /**
-     * Get list of properties available to Car Hvac Manager
+     * Get list of properties represented by Car Hvac Manager for this car.
      * @return List of CarPropertyConfig objects available via Car Hvac Manager.
      * @throws CarNotConnectedException if the connection to the car service has been lost.
      */
     public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
-        return mMgr.getPropertyList();
+        return mCarPropertyMgr.getPropertyList(mHvacPropertyIds);
+    }
+
+    /**
+     * Check whether a given property is available or disabled based on the cars current state.
+     * @return true if the property is AVAILABLE, false otherwise
+     */
+    public boolean isPropertyAvailable(@PropertyId int propertyId, int area)
+            throws CarNotConnectedException {
+        return mCarPropertyMgr.isPropertyAvailable(propertyId, area);
     }
 
     /**
@@ -358,7 +380,7 @@
      */
     public boolean getBooleanProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getBooleanProperty(propertyId, area);
+        return mCarPropertyMgr.getBooleanProperty(propertyId, area);
     }
 
     /**
@@ -370,7 +392,7 @@
      */
     public float getFloatProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getFloatProperty(propertyId, area);
+        return mCarPropertyMgr.getFloatProperty(propertyId, area);
     }
 
     /**
@@ -382,7 +404,7 @@
      */
     public int getIntProperty(@PropertyId int propertyId, int area)
             throws CarNotConnectedException {
-        return mMgr.getIntProperty(propertyId, area);
+        return mCarPropertyMgr.getIntProperty(propertyId, area);
     }
 
     /**
@@ -394,7 +416,9 @@
      */
     public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val)
             throws CarNotConnectedException {
-        mMgr.setBooleanProperty(propertyId, area, val);
+        if (mHvacPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
+        }
     }
 
     /**
@@ -406,7 +430,9 @@
      */
     public void setFloatProperty(@PropertyId int propertyId, int area, float val)
             throws CarNotConnectedException {
-        mMgr.setFloatProperty(propertyId, area, val);
+        if (mHvacPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setFloatProperty(propertyId, area, val);
+        }
     }
 
     /**
@@ -418,12 +444,13 @@
      */
     public void setIntProperty(@PropertyId int propertyId, int area, int val)
             throws CarNotConnectedException {
-        mMgr.setIntProperty(propertyId, area, val);
+        if (mHvacPropertyIds.contains(propertyId)) {
+            mCarPropertyMgr.setIntProperty(propertyId, area, val);
+        }
     }
 
     /** @hide */
-    @Override
     public void onCarDisconnected() {
-        mMgr.onCarDisconnected();
+        mCarPropertyMgr.onCarDisconnected();
     }
 }
diff --git a/car-lib/src/android/car/hardware/power/CarPowerManager.java b/car-lib/src/android/car/hardware/power/CarPowerManager.java
new file mode 100644
index 0000000..38c5cd1
--- /dev/null
+++ b/car-lib/src/android/car/hardware/power/CarPowerManager.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2018 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 android.car.hardware.power;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+
+import com.android.internal.annotations.GuardedBy;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * API for receiving power state change notifications.
+ * @hide
+ */
+@SystemApi
+public class CarPowerManager implements CarManagerBase {
+    private final static boolean DBG = false;
+    private final static String TAG = "CarPowerManager";
+    private CarPowerStateListener mListener;
+    private final ICarPower mService;
+    private Executor mExecutor;
+
+    @GuardedBy("mLock")
+    private ICarPowerStateListener mListenerToService;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Power boot up reasons, returned by {@link getBootReason}
+     */
+    /**
+     * User powered on the vehicle.  These definitions must match the ones located in the native
+     * CarPowerManager:  packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.h
+     *
+     */
+    public static final int BOOT_REASON_USER_POWER_ON = 1;
+    /**
+     * Door unlock caused device to boot
+     */
+    public static final int BOOT_REASON_DOOR_UNLOCK = 2;
+    /**
+     * Timer expired and vehicle woke up the AP
+     */
+    public static final int BOOT_REASON_TIMER = 3;
+    /**
+     * Door open caused device to boot
+     */
+    public static final int BOOT_REASON_DOOR_OPEN = 4;
+    /**
+     * User activated remote start
+     */
+    public static final int BOOT_REASON_REMOTE_START = 5;
+
+    /** @hide */
+    @IntDef({
+        BOOT_REASON_USER_POWER_ON,
+        BOOT_REASON_DOOR_UNLOCK,
+        BOOT_REASON_TIMER,
+        BOOT_REASON_DOOR_OPEN,
+        BOOT_REASON_REMOTE_START,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BootReason{}
+
+    /**
+     *  Applications set a {@link CarPowerStateListener} for power state event updates.
+     */
+    public interface CarPowerStateListener {
+        /**
+         * onStateChanged() states.  These definitions must match the ones located in the native
+         * CarPowerManager:  packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.h
+         *
+         */
+        /**
+         * Shutdown is cancelled, return to normal state.
+         */
+        public static final int SHUTDOWN_CANCELLED = 0;
+        /**
+         * Enter shutdown state.  Application is expected to cleanup and be ready to shutdown.
+         */
+        public static final int SHUTDOWN_ENTER = 1;
+        /**
+         * Enter suspend state.  Application is expected to cleanup and be ready to suspend.
+         */
+        public static final int SUSPEND_ENTER = 2;
+        /**
+         * Wake up from suspend, or resume from a cancelled suspend.  Application transitions to
+         * normal state.
+         */
+        public static final int SUSPEND_EXIT = 3;
+
+        /**
+         *  Called when power state changes
+         *  @param state New power state of device.
+         *  @param token Opaque identifier to keep track of listener events.
+         */
+        void onStateChanged(int state);
+    }
+
+    /**
+     * Get an instance of the CarPowerManager.
+     *
+     * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
+     * @param service
+     * @param context
+     * @param handler
+     * @hide
+     */
+    public CarPowerManager(IBinder service, Context context, Handler handler) {
+        mService = ICarPower.Stub.asInterface(service);
+    }
+
+    /**
+     * Returns the current {@link BootReason}.  This value does not change until the device goes
+     * through a suspend/resume cycle.
+     * @return int
+     * @throws CarNotConnectedException
+     * @hide
+     */
+    public int getBootReason() throws CarNotConnectedException {
+        try {
+            return mService.getBootReason();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception in getBootReason", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Request power manager to shutdown in lieu of suspend at the next opportunity.
+     * @throws CarNotConnectedException
+     * @hide
+     */
+    public void requestShutdownOnNextSuspend() throws CarNotConnectedException {
+        try {
+            mService.requestShutdownOnNextSuspend();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception in requestShutdownOnNextSuspend", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Sets a listener to receive power state changes.  Only one listener may be set at a time.
+     * Caller may add an Executor to allow the callback to run in a seperate thread of execution
+     * if the {@link onStateChanged} method will take some time.  If no Executor is passed in,
+     * the listener will run in the Binder thread and should finish quickly.  After
+     * {@link onStateChanged} is called, the {@link finished} method will automatically be called
+     * to notify {@link CarPowerManagementService} that the application has handled the
+     * {@link #SHUTDOWN_ENTER} or {@link #SUSPEND_ENTER} state transitions.  Only these two states
+     * require a confirmation from the application.
+     *
+     * @param executor
+     * @param listener
+     * @throws CarNotConnectedException, IllegalStateException
+     * @hide
+     */
+    public void setListener(CarPowerStateListener listener, Executor executor) throws
+            CarNotConnectedException, IllegalStateException {
+        synchronized(mLock) {
+            if (mListenerToService == null) {
+                ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() {
+                    @Override
+                    public void onStateChanged(int state, int token) throws RemoteException {
+                        handleEvent(state, token);
+                    }
+                };
+                try {
+                    mService.registerListener(listenerToService);
+                    mListenerToService = listenerToService;
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Could not connect: ", ex);
+                    throw new CarNotConnectedException(ex);
+                } catch (IllegalStateException ex) {
+                    Car.checkCarNotConnectedExceptionFromCarService(ex);
+                }
+            }
+            if ((mExecutor == null) && (mListener == null)) {
+                // Update listener and executor
+                mExecutor = executor;
+                mListener = listener;
+            } else {
+                throw new IllegalStateException("Listener must be cleared first");
+            }
+        }
+    }
+
+    /**
+     * Removes the listener from {@link CarPowerManagementService}
+     * @hide
+     */
+    public void clearListener() {
+        ICarPowerStateListener listenerToService;
+        synchronized (mLock) {
+            listenerToService = mListenerToService;
+            mListenerToService = null;
+            mListener = null;
+            mExecutor = null;
+        }
+
+        if (listenerToService == null) {
+            Log.w(TAG, "unregisterListener: listener was not registered");
+            return;
+        }
+
+        try {
+            mService.unregisterListener(listenerToService);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to unregister listener", ex);
+            //ignore
+        } catch (IllegalStateException ex) {
+            Car.hideCarNotConnectedExceptionFromCarService(ex);
+        }
+    }
+
+    private void handleEvent(int state, int token) {
+        Executor executor;
+        synchronized (mLock) {
+            executor = mExecutor;
+        }
+        if (executor != null) {
+            executor.execute(() -> {
+                handleEventInternal(state, token);
+            });
+        } else {
+            // If no executor provided, run in binder thread.  This should only be done for
+            //  trivial listener logic.
+            handleEventInternal(state, token);
+        }
+    }
+
+    private void handleEventInternal(int state, int token) {
+        mListener.onStateChanged(state);
+        if ((state == CarPowerStateListener.SHUTDOWN_ENTER) ||
+            (state == CarPowerStateListener.SUSPEND_ENTER)) {
+            // Notify service that state change is complete for SHUTDOWN_ENTER and SUSPEND_ENTER
+            //  states only.
+            try {
+                mService.finished(mListenerToService, token);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Exception in finished", e);
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        ICarPowerStateListener listenerToService;
+        synchronized (mLock) {
+            listenerToService = mListenerToService;
+        }
+
+        if (listenerToService != null) {
+            clearListener();
+        }
+    }
+}
diff --git a/car-lib/src/android/car/hardware/power/ICarPower.aidl b/car-lib/src/android/car/hardware/power/ICarPower.aidl
new file mode 100644
index 0000000..851ed0c
--- /dev/null
+++ b/car-lib/src/android/car/hardware/power/ICarPower.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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 android.car.hardware.power;
+
+import android.car.hardware.power.ICarPowerStateListener;
+
+/** @hide */
+interface ICarPower {
+    void registerListener(in ICarPowerStateListener listener) = 0;
+
+    void unregisterListener(in ICarPowerStateListener listener) = 1;
+
+    void requestShutdownOnNextSuspend() = 2;
+
+    int getBootReason() = 3;
+
+    void finished(in ICarPowerStateListener listener, int token) = 4;
+}
diff --git a/libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl b/car-lib/src/android/car/hardware/power/ICarPowerStateListener.aidl
similarity index 66%
rename from libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl
rename to car-lib/src/android/car/hardware/power/ICarPowerStateListener.aidl
index ca0ac83..a738b98 100644
--- a/libvehiclemonitor/java/src/com/android/car/vehiclemonitor/IVehicleMonitorListener.aidl
+++ b/car-lib/src/android/car/hardware/power/ICarPowerStateListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.car.vehiclemonitor;
+package android.car.hardware.power;
 
 /**
- * Listener for vehicle monitor service.
+ * Binder callback for CarPowerStateListener.
  * @hide
  */
-oneway interface IVehicleMonitorListener {
-    void onAppViolation(int pid, int uid, int action, int violation) = 0;
+oneway interface ICarPowerStateListener {
+    /**
+     * Called when a power state change occurs
+     */
+    void onStateChanged(int state, int token) = 0;
 }
+
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
new file mode 100644
index 0000000..5c094e7
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2018 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 android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+import android.car.CarApiUtil;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.car.internal.CarRatedFloatListeners;
+import com.android.car.internal.SingleMessageHandler;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+
+/**
+ * API for creating Car*Manager
+ * @hide
+ */
+public class CarPropertyManager implements CarManagerBase {
+    private final boolean mDbg;
+    private final SingleMessageHandler<CarPropertyEvent> mHandler;
+    private final ICarProperty mService;
+    private final String mTag;
+    private static final int MSG_GENERIC_EVENT = 0;
+
+    private CarPropertyEventListenerToService mCarPropertyEventToService;
+
+
+    /** Record of locally active properties. Key is propertyId */
+    private final SparseArray<CarPropertyListeners> mActivePropertyListener =
+            new SparseArray<>();
+
+    /** Callback functions for property events */
+    public interface CarPropertyEventListener {
+        /** Called when a property is updated */
+        void onChangeEvent(CarPropertyValue value);
+
+        /** Called when an error is detected with a property */
+        void onErrorEvent(int propId, int zone);
+    }
+
+    /**
+     * Get an instance of the CarPropertyManager.
+     */
+    public CarPropertyManager(IBinder service, Handler handler, boolean dbg, String tag) {
+        mDbg = dbg;
+        mTag = tag;
+        mService = ICarProperty.Stub.asInterface(service);
+        mHandler = new SingleMessageHandler<CarPropertyEvent>(handler.getLooper(),
+                MSG_GENERIC_EVENT) {
+            @Override
+            protected void handleEvent(CarPropertyEvent event) {
+                CarPropertyListeners listeners;
+                synchronized (mActivePropertyListener) {
+                    listeners = mActivePropertyListener.get(
+                            event.getCarPropertyValue().getPropertyId());
+                }
+                if (listeners != null) {
+                    switch (event.getEventType()) {
+                        case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
+                            listeners.onPropertyChanged(event);
+                            break;
+                        case CarPropertyEvent.PROPERTY_EVENT_ERROR:
+                            listeners.onErrorEvent(event);
+                            break;
+                        default:
+                            throw new IllegalArgumentException();
+                    }
+                }
+            }
+        };
+    }
+
+    /** Use to register or update Callback for properties */
+    public boolean registerListener(CarPropertyEventListener listener, int propertyId, float rate)
+            throws CarNotConnectedException {
+        synchronized (mActivePropertyListener) {
+            if (mCarPropertyEventToService == null) {
+                mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
+            }
+            boolean needsServerUpdate = false;
+            CarPropertyListeners listeners;
+            listeners = mActivePropertyListener.get(propertyId);
+            if (listeners == null) {
+                listeners = new CarPropertyListeners(rate);
+                mActivePropertyListener.put(propertyId, listeners);
+                needsServerUpdate = true;
+            }
+            if (listeners.addAndUpdateRate(listener, rate)) {
+                needsServerUpdate = true;
+            }
+            if (needsServerUpdate) {
+                if (!registerOrUpdatePropertyListener(propertyId, rate)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean registerOrUpdatePropertyListener(int propertyId, float rate)
+            throws CarNotConnectedException {
+        try {
+            mService.registerListener(propertyId, rate, mCarPropertyEventToService);
+        } catch (IllegalStateException e) {
+            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+        return true;
+    }
+
+    private class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub{
+        private final WeakReference<CarPropertyManager> mMgr;
+
+        CarPropertyEventListenerToService(CarPropertyManager mgr) {
+            mMgr = new WeakReference<>(mgr);
+        }
+
+        @Override
+        public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+            CarPropertyManager manager = mMgr.get();
+            if (manager != null) {
+                manager.handleEvent(events);
+            }
+        }
+    }
+
+    private void handleEvent(List<CarPropertyEvent> events) {
+        mHandler.sendEvents(events);
+    }
+
+    /**
+     * Stop getting sensor update for the given listener. If there are multiple registrations for
+     * this listener, all listening will be stopped.
+     * @param listener
+     */
+    public void unregisterListener(CarPropertyEventListener listener) {
+        synchronized (mActivePropertyListener) {
+            for (int i = 0; i < mActivePropertyListener.size(); i++) {
+                doUnregisterListenerLocked(listener, mActivePropertyListener.keyAt(i));
+            }
+        }
+    }
+
+    /**
+     * Stop getting sensor update for the given listener and sensor. If the same listener is used
+     * for other sensors, those subscriptions will not be affected.
+     * @param listener
+     * @param propertyId
+     */
+    public void unregisterListener(CarPropertyEventListener listener, int propertyId) {
+        synchronized (mActivePropertyListener) {
+            doUnregisterListenerLocked(listener, propertyId);
+        }
+    }
+
+    private void doUnregisterListenerLocked(CarPropertyEventListener listener, int propertyId) {
+        CarPropertyListeners listeners = mActivePropertyListener.get(propertyId);
+        if (listeners != null) {
+            boolean needsServerUpdate = false;
+            if (listeners.contains(listener)) {
+                needsServerUpdate = listeners.remove(listener);
+            }
+            if (listeners.isEmpty()) {
+                try {
+                    mService.unregisterListener(propertyId, mCarPropertyEventToService);
+                } catch (RemoteException e) {
+                    //ignore
+                }
+                mActivePropertyListener.remove(propertyId);
+            } else if (needsServerUpdate) {
+                try {
+                    registerOrUpdatePropertyListener(propertyId, listeners.getRate());
+                } catch (CarNotConnectedException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the list of properties implemented by this car.
+     *
+     * @return Caller must check the property type and typecast to the appropriate subclass
+     * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
+     */
+    public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
+        try {
+            return mService.getPropertyList();
+        } catch (RemoteException e) {
+            Log.e(mTag, "getPropertyList exception ", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Returns the list of properties implemented by this car in given property id list.
+     *
+     * @return Caller must check the property type and typecast to the appropriate subclass
+     * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
+     */
+    public List<CarPropertyConfig> getPropertyList(ArraySet<Integer> propertyIds)
+            throws CarNotConnectedException {
+        try {
+            List<CarPropertyConfig> configs = new ArrayList<>();
+            for (CarPropertyConfig c : mService.getPropertyList()) {
+                if (propertyIds.contains(c.getPropertyId())) {
+                    configs.add(c);
+                }
+            }
+            return configs;
+        } catch (RemoteException e) {
+            Log.e(mTag, "getPropertyList exception ", e);
+            throw new CarNotConnectedException(e);
+        }
+
+    }
+
+    /**
+     * Check whether a given property is available or disabled based on the car's current state.
+     * @return true if STATUS_AVAILABLE, false otherwise (eg STATUS_UNAVAILABLE)
+     * @throws CarNotConnectedException
+     */
+    public boolean isPropertyAvailable(int propId, int area) throws CarNotConnectedException {
+        try {
+            CarPropertyValue propValue = mService.getProperty(propId, area);
+            return (propValue != null)
+                    && (propValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE);
+        } catch (RemoteException e) {
+            Log.e(mTag, "isPropertyAvailable failed with " + e.toString()
+                    + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Returns value of a bool property
+     *
+     * @param prop Property ID to get
+     * @param area Area of the property to get
+     */
+    public boolean getBooleanProperty(int prop, int area) throws CarNotConnectedException {
+        CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
+        return carProp != null ? carProp.getValue() : false;
+    }
+
+    /**
+     * Returns value of a float property
+     *
+     * @param prop Property ID to get
+     * @param area Area of the property to get
+     */
+    public float getFloatProperty(int prop, int area) throws CarNotConnectedException {
+        CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
+        return carProp != null ? carProp.getValue() : 0f;
+    }
+
+    /**
+     * Returns value of a integer property
+     *
+     * @param prop Property ID to get
+     * @param area Zone of the property to get
+     */
+    public int getIntProperty(int prop, int area) throws CarNotConnectedException {
+        CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
+        return carProp != null ? carProp.getValue() : 0;
+    }
+
+    /** Return CarPropertyValue */
+    @SuppressWarnings("unchecked")
+    public <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
+            throws CarNotConnectedException {
+        if (mDbg) {
+            Log.d(mTag, "getProperty, propId: 0x" + toHexString(propId)
+                    + ", area: 0x" + toHexString(area) + ", class: " + clazz);
+        }
+        try {
+            CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+            if (propVal != null && propVal.getValue() != null) {
+                Class<?> actualClass = propVal.getValue().getClass();
+                if (actualClass != clazz) {
+                    throw new IllegalArgumentException("Invalid property type. " + "Expected: "
+                            + clazz + ", but was: " + actualClass);
+                }
+            }
+            return propVal;
+        } catch (RemoteException e) {
+            Log.e(mTag, "getProperty failed with " + e.toString()
+                    + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /** Return raw CarPropertyValue */
+    public <E> CarPropertyValue<E> getProperty(int propId, int area)
+            throws CarNotConnectedException {
+        try {
+            CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+            return propVal;
+        } catch (RemoteException e) {
+            Log.e(mTag, "getProperty failed with " + e.toString()
+                    + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /** Set CarPropertyValue */
+    public <E> void setProperty(Class<E> clazz, int propId, int area, E val)
+            throws CarNotConnectedException {
+        if (mDbg) {
+            Log.d(mTag, "setProperty, propId: 0x" + toHexString(propId)
+                    + ", area: 0x" + toHexString(area) + ", class: " + clazz + ", val: " + val);
+        }
+        try {
+            mService.setProperty(new CarPropertyValue<>(propId, area, val));
+        } catch (RemoteException e) {
+            Log.e(mTag, "setProperty failed with " + e.toString(), e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Modifies a property.  If the property modification doesn't occur, an error event shall be
+     * generated and propagated back to the application.
+     *
+     * @param prop Property ID to modify
+     * @param area Area to apply the modification.
+     * @param val Value to set
+     */
+    public void setBooleanProperty(int prop, int area, boolean val)
+            throws CarNotConnectedException {
+        setProperty(Boolean.class, prop, area, val);
+    }
+
+    /** Set float value of property*/
+    public void setFloatProperty(int prop, int area, float val) throws CarNotConnectedException {
+        setProperty(Float.class, prop, area, val);
+    }
+    /** Set int value of property*/
+    public void setIntProperty(int prop, int area, int val) throws CarNotConnectedException {
+        setProperty(Integer.class, prop, area, val);
+    }
+
+
+    private class CarPropertyListeners extends CarRatedFloatListeners<CarPropertyEventListener> {
+        CarPropertyListeners(float rate) {
+            super(rate);
+        }
+        void onPropertyChanged(final CarPropertyEvent event) {
+            // throw away old sensor data as oneway binder call can change order.
+            long updateTime = event.getCarPropertyValue().getTimestamp();
+            if (updateTime < mLastUpdateTime) {
+                Log.w(mTag, "dropping old property data");
+                return;
+            }
+            mLastUpdateTime = updateTime;
+            List<CarPropertyEventListener> listeners;
+            synchronized (mActivePropertyListener) {
+                listeners = new ArrayList<>(getListeners());
+            }
+            listeners.forEach(new Consumer<CarPropertyEventListener>() {
+                @Override
+                public void accept(CarPropertyEventListener listener) {
+                    listener.onChangeEvent(event.getCarPropertyValue());
+                }
+            });
+        }
+
+        void onErrorEvent(final CarPropertyEvent event) {
+            List<CarPropertyEventListener> listeners;
+            CarPropertyValue value = event.getCarPropertyValue();
+            synchronized (mActivePropertyListener) {
+                listeners = new ArrayList<>(getListeners());
+            }
+            listeners.forEach(new Consumer<CarPropertyEventListener>() {
+                @Override
+                public void accept(CarPropertyEventListener listener) {
+                    listener.onErrorEvent(value.getPropertyId(), value.getAreaId());
+                }
+            });
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onCarDisconnected() {
+        synchronized (mActivePropertyListener) {
+            mActivePropertyListener.clear();
+            mCarPropertyEventToService = null;
+        }
+    }
+}
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java b/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java
deleted file mode 100644
index c666bc2..0000000
--- a/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.car.hardware.property;
-
-import static java.lang.Integer.toHexString;
-
-import android.annotation.Nullable;
-import android.car.Car;
-import android.car.CarNotConnectedException;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-
-/**
- * API for creating Car*Manager
- * @hide
- */
-public class CarPropertyManagerBase {
-    private final boolean mDbg;
-    private final Handler mHandler;
-    private final ICarProperty mService;
-    private final String mTag;
-
-    @GuardedBy("mLock")
-    private ICarPropertyEventListener mListenerToService;
-    @GuardedBy("mLock")
-    private CarPropertyEventCallback mCallback;
-
-    private final Object mLock = new Object();
-
-    /** Callback functions for property events */
-    public interface CarPropertyEventCallback {
-        /** Called when a property is updated */
-        void onChangeEvent(CarPropertyValue value);
-
-        /** Called when an error is detected with a property */
-        void onErrorEvent(int propertyId, int zone);
-    }
-
-    private final static class EventCallbackHandler extends Handler {
-        /** Constants handled in the handler */
-        private static final int MSG_GENERIC_EVENT = 0;
-
-        private final WeakReference<CarPropertyManagerBase> mMgr;
-
-        EventCallbackHandler(CarPropertyManagerBase mgr, Looper looper) {
-            super(looper);
-            mMgr = new WeakReference<>(mgr);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_GENERIC_EVENT:
-                    CarPropertyManagerBase mgr = mMgr.get();
-                    if (mgr != null) {
-                        mgr.dispatchEventToClient((CarPropertyEvent) msg.obj);
-                    }
-                    break;
-                default:
-                    Log.e("EventtCallbackHandler", "Event type not handled:  " + msg);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Get an instance of the CarPropertyManagerBase.
-     */
-    public CarPropertyManagerBase(IBinder service, Handler handler, boolean dbg,
-            String tag) {
-        mDbg = dbg;
-        mTag = tag;
-        mService = ICarProperty.Stub.asInterface(service);
-        mHandler = new EventCallbackHandler(this, handler.getLooper());
-    }
-
-    public void registerCallback(CarPropertyEventCallback callback)
-            throws CarNotConnectedException {
-        synchronized (mLock) {
-            if (mCallback != null) {
-                throw new IllegalStateException("Callback is already registered.");
-            }
-
-            mCallback = callback;
-            mListenerToService = new ICarPropertyEventListener.Stub() {
-                @Override
-                public void onEvent(CarPropertyEvent event) throws RemoteException {
-                    handleEvent(event);
-                }
-            };
-        }
-
-        try {
-            mService.registerListener(mListenerToService);
-        } catch (RemoteException ex) {
-            Log.e(mTag, "Could not connect: ", ex);
-            throw new CarNotConnectedException(ex);
-        } catch (IllegalStateException ex) {
-            Car.checkCarNotConnectedExceptionFromCarService(ex);
-        }
-    }
-
-    public void unregisterCallback() {
-        ICarPropertyEventListener listenerToService;
-        synchronized (mLock) {
-            listenerToService = mListenerToService;
-            mCallback = null;
-            mListenerToService = null;
-        }
-
-        if (listenerToService == null) {
-            Log.w(mTag, "unregisterListener: listener was not registered");
-            return;
-        }
-
-        try {
-            mService.unregisterListener(listenerToService);
-        } catch (RemoteException ex) {
-            Log.e(mTag, "Failed to unregister listener", ex);
-            //ignore
-        } catch (IllegalStateException ex) {
-            Car.hideCarNotConnectedExceptionFromCarService(ex);
-        }
-    }
-
-    /**
-     * Returns the list of properties available.
-     *
-     * @return Caller must check the property type and typecast to the appropriate subclass
-     * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
-     */
-    public List<CarPropertyConfig> getPropertyList()  throws CarNotConnectedException {
-        try {
-            return mService.getPropertyList();
-        } catch (RemoteException e) {
-            Log.e(mTag, "Exception in getPropertyList", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Returns value of a bool property
-     *
-     * @param prop Property ID to get
-     * @param area Area of the property to get
-     */
-    public boolean getBooleanProperty(int prop, int area) throws CarNotConnectedException {
-        CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
-        return carProp != null ? carProp.getValue() : false;
-    }
-
-    /**
-     * Returns value of a float property
-     *
-     * @param prop Property ID to get
-     * @param area Area of the property to get
-     */
-    public float getFloatProperty(int prop, int area) throws CarNotConnectedException {
-        CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
-        return carProp != null ? carProp.getValue() : 0f;
-    }
-
-    /**
-     * Returns value of a integer property
-     *
-     * @param prop Property ID to get
-     * @param area Zone of the property to get
-     */
-    public int getIntProperty(int prop, int area) throws CarNotConnectedException {
-        CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
-        return carProp != null ? carProp.getValue() : 0;
-    }
-
-    @Nullable
-    @SuppressWarnings("unchecked")
-    public <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
-            throws CarNotConnectedException {
-        if (mDbg) {
-            Log.d(mTag, "getProperty, propId: 0x" + toHexString(propId)
-                    + ", area: 0x" + toHexString(area) + ", class: " + clazz);
-        }
-        try {
-            CarPropertyValue<E> propVal = mService.getProperty(propId, area);
-            if (propVal != null && propVal.getValue() != null) {
-                Class<?> actualClass = propVal.getValue().getClass();
-                if (actualClass != clazz) {
-                    throw new IllegalArgumentException("Invalid property type. " + "Expected: "
-                            + clazz + ", but was: " + actualClass);
-                }
-            }
-            return propVal;
-        } catch (RemoteException e) {
-            Log.e(mTag, "getProperty failed with " + e.toString()
-                    + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    public <E> void setProperty(Class<E> clazz, int propId, int area, E val)
-            throws CarNotConnectedException {
-        if (mDbg) {
-            Log.d(mTag, "setProperty, propId: 0x" + toHexString(propId)
-                    + ", area: 0x" + toHexString(area) + ", class: " + clazz + ", val: " + val);
-        }
-        try {
-            mService.setProperty(new CarPropertyValue<>(propId, area, val));
-        } catch (RemoteException e) {
-            Log.e(mTag, "setProperty failed with " + e.toString(), e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Modifies a property.  If the property modification doesn't occur, an error event shall be
-     * generated and propagated back to the application.
-     *
-     * @param prop Property ID to modify
-     * @param area Area to apply the modification.
-     * @param val Value to set
-     */
-    public void setBooleanProperty(int prop, int area, boolean val)
-            throws CarNotConnectedException {
-        setProperty(Boolean.class, prop, area, val);
-    }
-
-    public void setFloatProperty(int prop, int area, float val) throws CarNotConnectedException {
-        setProperty(Float.class, prop, area, val);
-    }
-
-    public void setIntProperty(int prop, int area, int val) throws CarNotConnectedException {
-        setProperty(Integer.class, prop, area, val);
-    }
-
-    private void dispatchEventToClient(CarPropertyEvent event) {
-        CarPropertyEventCallback listener;
-        synchronized (mLock) {
-            listener = mCallback;
-        }
-
-        if (listener == null) {
-            Log.e(mTag, "Listener died, not dispatching event.");
-            return;
-        }
-
-        CarPropertyValue propVal = event.getCarPropertyValue();
-        switch(event.getEventType()) {
-            case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
-                listener.onChangeEvent(propVal);
-                break;
-            case CarPropertyEvent.PROPERTY_EVENT_ERROR:
-                listener.onErrorEvent(propVal.getPropertyId(), propVal.getAreaId());
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-    }
-
-    private void handleEvent(CarPropertyEvent event) {
-        mHandler.sendMessage(mHandler.obtainMessage(EventCallbackHandler.MSG_GENERIC_EVENT, event));
-    }
-
-    /** @hide */
-    public void onCarDisconnected() {
-
-        ICarPropertyEventListener listenerToService;
-        synchronized (mLock) {
-            listenerToService = mListenerToService;
-        }
-
-        if (listenerToService != null) {
-            unregisterCallback();
-        }
-    }
-}
diff --git a/car-lib/src/android/car/hardware/property/ICarProperty.aidl b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
index 2121ebb..3e7e5c9 100644
--- a/car-lib/src/android/car/hardware/property/ICarProperty.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
@@ -25,9 +25,9 @@
  */
 interface ICarProperty {
 
-    void registerListener(in ICarPropertyEventListener callback) = 0;
+    void registerListener(int propId, float rate, in ICarPropertyEventListener callback) = 0;
 
-    void unregisterListener(in ICarPropertyEventListener callback) = 1;
+    void unregisterListener(int propId, in ICarPropertyEventListener callback) = 1;
 
     List<CarPropertyConfig> getPropertyList() = 2;
 
diff --git a/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl b/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
index b0d57fc..ebda47c 100644
--- a/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
@@ -28,6 +28,6 @@
      * Called when an event is triggered in response to one of the calls (such as on tune) or
      * asynchronously (such as on announcement).
      */
-    void onEvent(in CarPropertyEvent event) = 0;
+    void onEvent(in List<CarPropertyEvent> events) = 0;
 }
 
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioEvent.java b/car-lib/src/android/car/hardware/radio/CarRadioEvent.java
deleted file mode 100644
index 332cb56..0000000
--- a/car-lib/src/android/car/hardware/radio/CarRadioEvent.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A CarRadioEvent object corresponds to a single radio event coming from the car.
- *
- * This works in conjunction with the callbacks already defined in {@link RadioCallback.Callback}.
- * @hide
- */
-@SystemApi
-public class CarRadioEvent implements Parcelable {
-    /**
-     * Event specifying that a radio preset has been changed.
-     */
-    public static final int RADIO_PRESET = 0;
-
-    /**
-     * Event type.
-     */
-    private final int mType;
-
-    /**
-     * CarRadioPreset for the event type EVENT_RADIO_PRESET.
-     */
-    private final CarRadioPreset mPreset;
-
-    // Getters.
-    public CarRadioPreset getPreset() {
-        return mPreset;
-    }
-
-    public int getEventType() {
-        return mType;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mType);
-        dest.writeParcelable(mPreset, 0);
-    }
-
-    public static final Parcelable.Creator<CarRadioEvent> CREATOR
-            = new Parcelable.Creator<CarRadioEvent>() {
-        public CarRadioEvent createFromParcel(Parcel in) {
-            return new CarRadioEvent(in);
-        }
-
-        public CarRadioEvent[] newArray(int size) {
-            return new CarRadioEvent[size];
-        }
-    };
-
-    public CarRadioEvent(int type, CarRadioPreset preset) {
-        mType = type;
-        mPreset = preset;
-    }
-
-    private CarRadioEvent(Parcel in) {
-        mType = in.readInt();
-        mPreset = in.readParcelable(CarRadioPreset.class.getClassLoader());
-    }
-
-    public String toString() {
-        String data = "";
-        switch (mType) {
-          case RADIO_PRESET:
-              data = mPreset.toString();
-        }
-        return mType + " " + data;
-    }
-}
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioManager.java b/car-lib/src/android/car/hardware/radio/CarRadioManager.java
deleted file mode 100644
index a590864..0000000
--- a/car-lib/src/android/car/hardware/radio/CarRadioManager.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-import android.annotation.SystemApi;
-import android.car.Car;
-import android.car.CarManagerBase;
-import android.car.CarNotConnectedException;
-import android.hardware.radio.RadioManager;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Car Radio manager.
- *
- * This API works in conjunction with the {@link RadioManager.java} and provides
- * features additional to the ones provided in there. It supports:
- *
- * 1. Capability to control presets.
- * @hide
- */
-@SystemApi
-public final class CarRadioManager implements CarManagerBase {
-    private final static boolean DBG = false;
-    private final static String TAG = "CarRadioManager";
-
-    // Constants handled in the handler (see mHandler below).
-    private final static int MSG_RADIO_EVENT = 0;
-
-    private int mCount = 0;
-    private final ICarRadio mService;
-    @GuardedBy("this")
-    private CarRadioEventListener mListener = null;
-    @GuardedBy("this")
-    private CarRadioEventListenerToService mListenerToService = null;
-    private static final class EventCallbackHandler extends Handler {
-        WeakReference<CarRadioManager> mMgr;
-
-        EventCallbackHandler(CarRadioManager mgr, Looper looper) {
-            super(looper);
-            mMgr = new WeakReference<CarRadioManager>(mgr);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_RADIO_EVENT:
-                    CarRadioManager mgr = mMgr.get();
-                    if (mgr != null) {
-                        mgr.dispatchEventToClient((CarRadioEvent) msg.obj);
-                    }
-                    break;
-                default:
-                    Log.e(TAG, "Event type not handled?" + msg);
-            }
-        }
-    }
-
-    private final Handler mHandler;
-
-    private static class CarRadioEventListenerToService extends ICarRadioEventListener.Stub {
-        private final WeakReference<CarRadioManager> mManager;
-
-        public CarRadioEventListenerToService(CarRadioManager manager) {
-            mManager = new WeakReference<CarRadioManager>(manager);
-        }
-
-        @Override
-        public void onEvent(CarRadioEvent event) {
-            CarRadioManager manager = mManager.get();
-            if (manager != null) {
-                manager.handleEvent(event);
-            }
-        }
-    }
-
-
-    /** Listener for car radio events.
-     */
-    public interface CarRadioEventListener {
-        /**
-         * Called when there is a preset value is reprogrammed.
-         */
-        void onEvent(final CarRadioEvent event);
-    }
-
-    /**
-     * Get an instance of the CarRadioManager.
-     *
-     * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
-     * @hide
-     */
-    public CarRadioManager(IBinder service, Handler handler) throws CarNotConnectedException {
-        mService = ICarRadio.Stub.asInterface(service);
-        mHandler = new EventCallbackHandler(this, handler.getLooper());
-
-        // Populate the fixed values.
-        try {
-            mCount = mService.getPresetCount();
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Could not connect: " + ex.toString());
-            throw new CarNotConnectedException(ex);
-        }
-    }
-
-    /**
-     * Register {@link CarRadioEventListener} to get radio unit changes.
-     */
-    public synchronized void registerListener(CarRadioEventListener listener)
-            throws CarNotConnectedException {
-        if (mListener != null) {
-            throw new IllegalStateException("Listener already registered. Did you call " +
-                "registerListener() twice?");
-        }
-
-        mListener = listener;
-        try {
-            mListenerToService = new CarRadioEventListenerToService(this);
-            mService.registerListener(mListenerToService);
-        } catch (RemoteException ex) {
-            // Do nothing.
-            Log.e(TAG, "Could not connect: " + ex.toString());
-            throw new CarNotConnectedException(ex);
-        } catch (IllegalStateException ex) {
-            Car.checkCarNotConnectedExceptionFromCarService(ex);
-        }
-    }
-
-    /**
-     * Unregister {@link CarRadioEventListener}.
-     */
-    public synchronized void unregisterListener() {
-        if (DBG) {
-            Log.d(TAG, "unregisterListener");
-        }
-        try {
-            mService.unregisterListener(mListenerToService);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Could not connect: " + ex.toString());
-            //ignore
-        }
-        mListenerToService = null;
-        mListener = null;
-    }
-
-    /**
-     * Get the number of (hard) presets supported by car radio unit.
-     *
-     * @return: A positive value if the call succeeded, -1 if it failed.
-     */
-    public int getPresetCount() throws CarNotConnectedException {
-        return mCount;
-    }
-
-    /**
-     * Get preset value for a specific radio preset.
-     * @return: a {@link CarRadioPreset} object, {@link null} if the call failed.
-     */
-    public CarRadioPreset getPreset(int presetNumber) throws CarNotConnectedException {
-        if (DBG) {
-            Log.d(TAG, "getPreset");
-        }
-        try {
-            CarRadioPreset preset = mService.getPreset(presetNumber);
-            return preset;
-        } catch (RemoteException ex) {
-            Log.e(TAG, "getPreset failed with " + ex.toString());
-            throw new CarNotConnectedException(ex);
-        }
-    }
-
-    /**
-     * Set the preset value to a specific radio preset.
-     *
-     * In order to ensure that the preset value indeed get updated, wait for event on the listener
-     * registered via registerListener().
-     *
-     * @return: {@link boolean} value which returns true if the request succeeded and false
-     * otherwise. Common reasons for the failure could be:
-     * a) Preset is invalid (the preset number is out of range from {@link getPresetCount()}.
-     * b) Listener is not set correctly, since otherwise the user of this API cannot confirm if the
-     * request succeeded.
-     */
-    public boolean setPreset(CarRadioPreset preset) throws IllegalArgumentException,
-            CarNotConnectedException {
-        try {
-            return mService.setPreset(preset);
-        } catch (RemoteException ex) {
-            throw new CarNotConnectedException(ex);
-         }
-    }
-
-    private void dispatchEventToClient(CarRadioEvent event) {
-        CarRadioEventListener listener;
-        synchronized (this) {
-            listener = mListener;
-        }
-        if (listener != null) {
-            listener.onEvent(event);
-        } else {
-            Log.e(TAG, "Listener died, not dispatching event.");
-        }
-    }
-
-    private void handleEvent(CarRadioEvent event) {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_RADIO_EVENT, event));
-    }
-
-    /** @hide */
-    @Override
-    public synchronized void onCarDisconnected() {
-        mListener = null;
-        mListenerToService = null;
-    }
-}
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioPreset.aidl b/car-lib/src/android/car/hardware/radio/CarRadioPreset.aidl
deleted file mode 100644
index 8a1c7b2..0000000
--- a/car-lib/src/android/car/hardware/radio/CarRadioPreset.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-parcelable CarRadioPreset;
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioPreset.java b/car-lib/src/android/car/hardware/radio/CarRadioPreset.java
deleted file mode 100644
index 38713ad..0000000
--- a/car-lib/src/android/car/hardware/radio/CarRadioPreset.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * CarPreset object corresponds to a preset that is stored on the car's Radio unit.
- * @hide
- */
-@SystemApi
-public class CarRadioPreset implements Parcelable {
-
-    /*
-     * Preset number at which this preset is stored.
-     *
-     * The value is 1 index based.
-     */
-    private final int mPresetNumber;
-    /**
-     * Radio band this preset belongs to.
-     * See {@link RadioManager.BAND_FM}, {@link RadioManager.BAND_AM} etc.
-     */
-    private final int mBand;
-    /**
-     * Channel number.
-     */
-    private final int mChannel;
-    /**
-     * Sub channel number.
-     */
-    private final int mSubChannel;
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mPresetNumber);
-        out.writeInt(mBand);
-        out.writeInt(mChannel);
-        out.writeInt(mSubChannel);
-    }
-
-    public static final Parcelable.Creator<CarRadioPreset> CREATOR
-            = new Parcelable.Creator<CarRadioPreset>() {
-        public CarRadioPreset createFromParcel(Parcel in) {
-            return new CarRadioPreset(in);
-        }
-
-        public CarRadioPreset[] newArray(int size) {
-            return new CarRadioPreset[size];
-        }
-    };
-
-    private CarRadioPreset(Parcel in) {
-        mPresetNumber = in.readInt();
-        mBand = in.readInt();
-        mChannel = in.readInt();
-        mSubChannel = in.readInt();
-    }
-
-    public CarRadioPreset(int presetNumber, int bandType, int channel, int subChannel) {
-        mPresetNumber = presetNumber;
-        mBand = bandType;
-        mChannel = channel;
-        mSubChannel = subChannel;
-    }
-
-    // Getters.
-    public int getPresetNumber() { return mPresetNumber; }
-
-    public int getBand() { return mBand; }
-
-    public int getChannel() { return mChannel; }
-
-    public int getSubChannel() { return mSubChannel; }
-
-    // Printer.
-    public String toString() {
-        return "Preset Number: " + mPresetNumber + "\n" +
-            "Band: " + mBand + "\n" +
-            "Channel: " + mChannel + "\n" +
-            "Sub channel: " + mSubChannel;
-    }
-
-    // Comparator.
-    public boolean equals(Object o) {
-        CarRadioPreset that = (CarRadioPreset) o;
-
-        return that.getPresetNumber() == mPresetNumber &&
-            that.getBand() == mBand &&
-            that.getChannel() == mChannel &&
-            that.getSubChannel() == mSubChannel;
-
-    }
-}
diff --git a/car-lib/src/android/car/hardware/radio/ICarRadio.aidl b/car-lib/src/android/car/hardware/radio/ICarRadio.aidl
deleted file mode 100644
index 4afa211..0000000
--- a/car-lib/src/android/car/hardware/radio/ICarRadio.aidl
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-import android.car.hardware.radio.CarRadioPreset;
-import android.car.hardware.radio.ICarRadioEventListener;
-
-/** @hide */
-interface ICarRadio {
-    /**
-     * Returns the number of hard presets on the radio unit that may be programmed.
-     */
-    int getPresetCount() = 0;
-
-    /**
-     * Registers the client for updates to radio changes.
-     */
-    void registerListener(in ICarRadioEventListener callback) = 1;
-
-    /**
-     * Unregisters the client for updates to radio changes.
-     */
-    void unregisterListener(in ICarRadioEventListener callback) = 2;
-
-    /**
-     * Gets the preset values stored for a particular preset number.
-     */
-    CarRadioPreset getPreset(int presetNumber) = 3;
-
-    /**
-     * Sets a specified preset (hard button) in the car. In order to check for success listen to
-     * events using {@link registerOrUpdateRadioListener}.
-     */
-    boolean setPreset(in CarRadioPreset preset) = 4;
-}
diff --git a/car-lib/src/android/car/hardware/radio/ICarRadioEventListener.aidl b/car-lib/src/android/car/hardware/radio/ICarRadioEventListener.aidl
deleted file mode 100644
index e006b65..0000000
--- a/car-lib/src/android/car/hardware/radio/ICarRadioEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 android.car.hardware.radio;
-
-import android.car.hardware.radio.CarRadioEvent;
-
-/**
- * Binder callback for CarRadioEventListener.
- * This is generated per each CarClient.
- * @hide
- */
-oneway interface ICarRadioEventListener {
-    /**
-     * Called when an event is triggered in response to one of the calls (such as on tune) or
-     * asynchronously (such as on announcement).
-     */
-    void onEvent(in CarRadioEvent event) = 0;
-}
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index 49a7ca4..c9aef74 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -15,467 +15,350 @@
  */
 package android.car.media;
 
-import android.annotation.IntDef;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.car.CarLibLog;
+import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioManager.OnAudioFocusChangeListener;
-import android.media.IVolumeController;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.car.CarManagerBase;
+import android.provider.Settings;
 import android.util.Log;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-
 /**
  * APIs for handling car specific audio stuff.
  */
 public final class CarAudioManager implements CarManagerBase {
 
-    /**
-     * Audio usage for unspecified type.
-     */
-    public static final int CAR_AUDIO_USAGE_DEFAULT = 0;
-    /**
-     * Audio usage for playing music.
-     */
-    public static final int CAR_AUDIO_USAGE_MUSIC = 1;
-    /**
-     * Audio usage for H/W radio.
-     */
-    public static final int CAR_AUDIO_USAGE_RADIO = 2;
-    /**
-     * Audio usage for playing navigation guidance.
-     */
-    public static final int CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE = 3;
-    /**
-     * Audio usage for voice call
-     */
-    public static final int CAR_AUDIO_USAGE_VOICE_CALL = 4;
-    /**
-     * Audio usage for voice search or voice command.
-     */
-    public static final int CAR_AUDIO_USAGE_VOICE_COMMAND = 5;
-    /**
-     * Audio usage for playing alarm.
-     */
-    public static final int CAR_AUDIO_USAGE_ALARM = 6;
-    /**
-     * Audio usage for notification sound.
-     */
-    public static final int CAR_AUDIO_USAGE_NOTIFICATION = 7;
-    /**
-     * Audio usage for system sound like UI feedback.
-     */
-    public static final int CAR_AUDIO_USAGE_SYSTEM_SOUND = 8;
-    /**
-     * Audio usage for playing safety alert.
-     */
-    public static final int CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT = 9;
-    /**
-     * Audio usage for the ringing of a phone call.
-     */
-    public static final int CAR_AUDIO_USAGE_RINGTONE = 10;
-    /**
-     * Audio usage for external audio usage.
-     * @hide
-     */
-    public static final int CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE = 11;
+    // The trailing slash forms a directory-liked hierarchy and
+    // allows listening for both GROUP/MEDIA and GROUP/NAVIGATION.
+    private static final String VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX = "android.car.VOLUME_GROUP/";
 
-    /** @hide */
-    public static final int CAR_AUDIO_USAGE_MAX = CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
+    /**
+     * @param groupId The volume group id
+     * @return Key to persist volume index for volume group in {@link Settings.Global}
+     */
+    public static String getVolumeSettingsKeyForGroup(int groupId) {
+        return VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX + groupId;
+    }
 
-    /** @hide */
-    @IntDef({CAR_AUDIO_USAGE_DEFAULT, CAR_AUDIO_USAGE_MUSIC, CAR_AUDIO_USAGE_RADIO,
-        CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE, CAR_AUDIO_USAGE_VOICE_CALL,
-        CAR_AUDIO_USAGE_VOICE_COMMAND, CAR_AUDIO_USAGE_ALARM, CAR_AUDIO_USAGE_NOTIFICATION,
-        CAR_AUDIO_USAGE_SYSTEM_SOUND, CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT,
-        CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CarAudioUsage {}
-
-    /** @hide */
-    public static final String CAR_RADIO_TYPE_AM_FM = "RADIO_AM_FM";
-    /** @hide */
-    public static final String CAR_RADIO_TYPE_AM_FM_HD = "RADIO_AM_FM_HD";
-    /** @hide */
-    public static final String CAR_RADIO_TYPE_DAB = "RADIO_DAB";
-    /** @hide */
-    public static final String CAR_RADIO_TYPE_SATELLITE = "RADIO_SATELLITE";
-
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_CD_DVD = "CD_DVD";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_AUX_IN0 = "AUX_IN0";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_AUX_IN1 = "AUX_IN1";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE = "EXT_NAV_GUIDANCE";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_VOICE_CALL = "EXT_VOICE_CALL";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_VOICE_COMMAND = "EXT_VOICE_COMMAND";
-    /** @hide */
-    public static final String CAR_EXTERNAL_SOURCE_TYPE_EXT_SAFETY_ALERT = "EXT_SAFETY_ALERT";
-
+    private final ContentResolver mContentResolver;
     private final ICarAudio mService;
-    private final AudioManager mAudioManager;
-    private final Handler mHandler;
-
-    private ParameterChangeCallback mParameterChangeCallback;
-    private OnParameterChangeListener mOnParameterChangeListener;
 
     /**
-     * Get {@link AudioAttributes} relevant for the given usage in car.
-     * @param carUsage
-     * @return
+     * Registers a {@link ContentObserver} to listen for volume group changes.
+     * Note that this observer is valid for bus based car audio stack only.
+     *
+     * {@link ContentObserver#onChange(boolean)} will be called on every group volume change.
+     *
+     * @param observer The {@link ContentObserver} instance to register, non-null
      */
-    public AudioAttributes getAudioAttributesForCarUsage(@CarAudioUsage int carUsage)
-            throws CarNotConnectedException {
-        try {
-            return mService.getAudioAttributesForCarUsage(carUsage);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException();
-        }
+    @SystemApi
+    public void registerVolumeChangeObserver(@NonNull ContentObserver observer) {
+        mContentResolver.registerContentObserver(
+                Settings.Global.getUriFor(VOLUME_SETTINGS_KEY_FOR_GROUP_PREFIX),
+                true, observer);
     }
 
     /**
-     * Get AudioAttributes for radio. This is necessary when there are multiple types of radio
-     * in system.
+     * Unregisters the {@link ContentObserver} which listens for volume group changes.
      *
-     * @param radioType String specifying the desired radio type. Should use only what is listed in
-     *        {@link #getSupportedRadioTypes()}.
-     * @return
-     * @throws IllegalArgumentException If not supported type is passed.
-     *
-     * @hide
+     * @param observer The {@link ContentObserver} instance to unregister, non-null
      */
-    public AudioAttributes getAudioAttributesForRadio(String radioType)
-            throws CarNotConnectedException, IllegalArgumentException {
-        try {
-            return mService.getAudioAttributesForRadio(radioType);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException();
-        }
+    @SystemApi
+    public void unregisterVolumeChangeObserver(@NonNull ContentObserver observer) {
+        mContentResolver.unregisterContentObserver(observer);
     }
 
     /**
-     * Get AudioAttributes for external audio source.
+     * Sets the volume index for a volume group.
      *
-     * @param externalSourceType String specifying the desired source type. Should use only what is
-     *        listed in {@link #getSupportedExternalSourceTypes()}.
-     * @return
-     * @throws IllegalArgumentException If not supported type is passed.
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
      *
-     * @hide
-     */
-    public AudioAttributes getAudioAttributesForExternalSource(String externalSourceType)
-            throws CarNotConnectedException, IllegalArgumentException {
-        try {
-            return mService.getAudioAttributesForExternalSource(externalSourceType);
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException();
-        }
-    }
-
-    /**
-     * List all supported external audio sources.
-     *
-     * @return
-     *
-     * @hide
-     */
-    public String[] getSupportedExternalSourceTypes() throws CarNotConnectedException {
-        try {
-            return mService.getSupportedExternalSourceTypes();
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException();
-        }
-    }
-
-    /**
-     * List all supported radio sources.
-     *
-     * @return
-     *
-     * @hide
-     */
-    public String[] getSupportedRadioTypes() throws CarNotConnectedException {
-        try {
-            return mService.getSupportedRadioTypes();
-        } catch (RemoteException e) {
-            throw new CarNotConnectedException();
-        }
-    }
-
-    /**
-     * Request audio focus.
-     * Send a request to obtain the audio focus.
-     * @param l
-     * @param requestAttributes
-     * @param durationHint
-     * @param flags
-     */
-    public int requestAudioFocus(OnAudioFocusChangeListener l,
-                                 AudioAttributes requestAttributes,
-                                 int durationHint,
-                                 int flags)
-                                         throws CarNotConnectedException, IllegalArgumentException {
-        return mAudioManager.requestAudioFocus(l, requestAttributes, durationHint, flags);
-    }
-
-    /**
-     * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
-     * @param l
-     * @param aa
-     */
-    public void abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
-        mAudioManager.abandonAudioFocus(l, aa);
-    }
-
-    /**
-     * Sets the volume index for a particular stream.
-     *
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
-     *
-     * @param streamType The stream whose volume index should be set.
+     * @param groupId The volume group id whose volume index should be set.
      * @param index The volume index to set. See
-     *            {@link #getStreamMaxVolume(int)} for the largest valid value.
+     *            {@link #getGroupMaxVolume(int)} for the largest valid value.
      * @param flags One or more flags (e.g., {@link android.media.AudioManager#FLAG_SHOW_UI},
      *              {@link android.media.AudioManager#FLAG_PLAY_SOUND})
      */
     @SystemApi
-    public void setStreamVolume(int streamType, int index, int flags)
+    public void setGroupVolume(int groupId, int index, int flags) throws CarNotConnectedException {
+        try {
+            mService.setGroupVolume(groupId, index, flags);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "setGroupVolume failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Returns the maximum volume index for a volume group.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param groupId The volume group id whose maximum volume index is returned.
+     * @return The maximum valid volume index for the given group.
+     */
+    @SystemApi
+    public int getGroupMaxVolume(int groupId) throws CarNotConnectedException {
+        try {
+            return mService.getGroupMaxVolume(groupId);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "getUsageMaxVolume failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Returns the minimum volume index for a volume group.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param groupId The volume group id whose minimum volume index is returned.
+     * @return The minimum valid volume index for the given group, non-negative
+     */
+    @SystemApi
+    public int getGroupMinVolume(int groupId) throws CarNotConnectedException {
+        try {
+            return mService.getGroupMinVolume(groupId);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "getUsageMinVolume failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Returns the current volume index for a volume group.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param groupId The volume group id whose volume index is returned.
+     * @return The current volume index for the given group.
+     *
+     * @see #getGroupMaxVolume(int)
+     * @see #setGroupVolume(int, int, int)
+     */
+    @SystemApi
+    public int getGroupVolume(int groupId) throws CarNotConnectedException {
+        try {
+            return mService.getGroupVolume(groupId);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "getUsageVolume failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Adjust the relative volume in the front vs back of the vehicle cabin.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param value in the range -1.0 to 1.0 for fully toward the back through
+     *              fully toward the front.  0.0 means evenly balanced.
+     *
+     * @see #setBalanceTowardRight(float)
+     */
+    @SystemApi
+    public void setFadeTowardFront(float value) throws CarNotConnectedException {
+        try {
+            mService.setFadeTowardFront(value);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "setFadeTowardFront failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Adjust the relative volume on the left vs right side of the vehicle cabin.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param value in the range -1.0 to 1.0 for fully toward the left through
+     *              fully toward the right.  0.0 means evenly balanced.
+     *
+     * @see #setFadeTowardFront(float)
+     */
+    @SystemApi
+    public void setBalanceTowardRight(float value) throws CarNotConnectedException {
+        try {
+            mService.setBalanceTowardRight(value);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "setBalanceTowardRight failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Queries the system configuration in order to report the available, non-microphone audio
+     * input devices.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
+     *
+     * @return An array of strings representing the available input ports.
+     * Each port is identified by it's "address" tag in the audioPolicyConfiguration xml file.
+     * Empty array if we find nothing.
+     *
+     * @see #createAudioPatch(String, int, int)
+     * @see #releaseAudioPatch(CarAudioPatchHandle)
+     */
+    @SystemApi
+    public @NonNull String[] getExternalSources() throws CarNotConnectedException {
+        try {
+            return mService.getExternalSources();
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "getExternalSources failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Given an input port identified by getExternalSources(), request that it's audio signal
+     * be routed below the HAL to the output port associated with the given usage.  For example,
+     * The output of a tuner might be routed directly to the output buss associated with
+     * AudioAttributes.USAGE_MEDIA while the tuner is playing.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
+     *
+     * @param sourceAddress the input port name obtained from getExternalSources().
+     * @param usage the type of audio represented by this source (usually USAGE_MEDIA).
+     * @param gainInMillibels How many steps above the minimum value defined for the source port to
+     *                       set the gain when creating the patch.
+     *                       This may be used for source balancing without affecting the user
+     *                       controlled volumes applied to the destination ports.  A value of
+     *                       0 indicates no gain change is requested.
+     * @return A handle for the created patch which can be used to later remove it.
+     *
+     * @see #getExternalSources()
+     * @see #releaseAudioPatch(CarAudioPatchHandle)
+     */
+    @SystemApi
+    public CarAudioPatchHandle createAudioPatch(String sourceAddress,
+            @AudioAttributes.AttributeUsage int usage, int gainInMillibels)
             throws CarNotConnectedException {
         try {
-            mService.setStreamVolume(streamType, index, flags);
+            return mService.createAudioPatch(sourceAddress, usage, gainInMillibels);
         } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "setStreamVolume failed", e);
+            Log.e(CarLibLog.TAG_CAR, "createAudioPatch failed", e);
             throw new CarNotConnectedException(e);
         }
     }
 
     /**
-     * Registers a global volume controller interface.
+     * Removes the association between an input port and an output port identified by the provided
+     * handle.
      *
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
      *
-     * @hide
+     * @param patch CarAudioPatchHandle returned from createAudioPatch().
+     *
+     * @see #getExternalSources()
+     * @see #createAudioPatch(String, int, int)
      */
     @SystemApi
-    public void setVolumeController(IVolumeController controller)
+    public void releaseAudioPatch(CarAudioPatchHandle patch) throws CarNotConnectedException {
+        try {
+            mService.releaseAudioPatch(patch);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "releaseAudioPatch failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Gets the count of available volume groups in the system.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @return Count of volume groups
+     */
+    @SystemApi
+    public int getVolumeGroupCount() throws CarNotConnectedException {
+        try {
+            return mService.getVolumeGroupCount();
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "getVolumeGroupCount failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Gets the volume group id for a given {@link AudioAttributes} usage.
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param usage The {@link AudioAttributes} usage to get a volume group from.
+     * @return The volume group id where the usage belongs to
+     */
+    @SystemApi
+    public int getVolumeGroupIdForUsage(@AudioAttributes.AttributeUsage int usage)
             throws CarNotConnectedException {
         try {
-            mService.setVolumeController(controller);
+            return mService.getVolumeGroupIdForUsage(usage);
         } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "setVolumeController failed", e);
+            Log.e(CarLibLog.TAG_CAR, "getVolumeGroupIdForUsage failed", e);
             throw new CarNotConnectedException(e);
         }
     }
 
     /**
-     * Returns the maximum volume index for a particular stream.
+     * Gets array of {@link AudioAttributes} usages for a given volume group id.
      *
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
      *
-     * @param stream The stream type whose maximum volume index is returned.
-     * @return The maximum valid volume index for the stream.
+     * @param groupId The volume group id whose associated audio usages is returned.
+     * @return Array of {@link AudioAttributes} usages for a given volume group id
      */
     @SystemApi
-    public int getStreamMaxVolume(int stream) throws CarNotConnectedException {
+    public @NonNull int[] getUsagesForVolumeGroupId(int groupId) throws CarNotConnectedException {
         try {
-            return mService.getStreamMaxVolume(stream);
+            return mService.getUsagesForVolumeGroupId(groupId);
         } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "getStreamMaxVolume failed", e);
+            Log.e(CarLibLog.TAG_CAR, "getUsagesForVolumeGroupId failed", e);
             throw new CarNotConnectedException(e);
         }
     }
 
     /**
-     * Returns the minimum volume index for a particular stream.
+     * Register {@link ICarVolumeCallback} to receive the volume key events
      *
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
      *
-     * @param stream The stream type whose maximum volume index is returned.
-     * @return The maximum valid volume index for the stream.
-     */
-    @SystemApi
-    public int getStreamMinVolume(int stream) throws CarNotConnectedException {
-        try {
-            return mService.getStreamMinVolume(stream);
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "getStreamMaxVolume failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Returns the current volume index for a particular stream.
-     *
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
-     *
-     * @param stream The stream type whose volume index is returned.
-     * @return The current volume index for the stream.
-     *
-     * @see #getStreamMaxVolume(int)
-     * @see #setStreamVolume(int, int, int)
-     */
-    @SystemApi
-    public int getStreamVolume(int stream) throws CarNotConnectedException {
-        try {
-            return mService.getStreamVolume(stream);
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "getStreamVolume failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Check if media audio is muted or not. This will include music and radio. Any application
-     * taking audio focus for media stream will get it out of mute state.
-     *
-     * @return true if media is muted.
-     * @throws CarNotConnectedException if the connection to the car service has been lost.
-     * @hide
-     */
-    @SystemApi
-    public boolean isMediaMuted() throws CarNotConnectedException {
-        try {
-            return mService.isMediaMuted();
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "isMediaMuted failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Mute or unmute media stream including radio. This can involve audio focus change to stop
-     * whatever app holding audio focus now. If requester is currently holding audio focus,
-     * it will get LOSS_TRANSIENT focus loss.
-     * This API requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
-     *
-     * @param mute
-     * @return Mute state of system after the request. Note that mute request can fail if there
-     *         is higher priority audio already being played like phone call.
-     * @throws CarNotConnectedException if the connection to the car service has been lost.
-     * @hide
-     */
-    @SystemApi
-    public boolean setMediaMute(boolean mute) throws CarNotConnectedException {
-        try {
-            return mService.setMediaMute(mute);
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "setMediaMute failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Listener to monitor audio parameter changes.
-     * @hide
-     */
-    public interface OnParameterChangeListener {
-        /**
-         * Parameter changed.
-         * @param parameters Have format of key1=value1;key2=value2;...
-         */
-        void onParameterChange(String parameters);
-    }
-
-    /**
-     * Return array of keys supported in this system.
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
-     * The list is static and will not change.
-     * @return null if there is no audio parameters supported.
+     * @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to receive
+     *                              volume key event callbacks
      * @throws CarNotConnectedException
-     *
-     * @hide
      */
-    public @Nullable String[] getParameterKeys() throws CarNotConnectedException {
-        try {
-            return mService.getParameterKeys();
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "getParameterKeys failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Set car specific audio parameters.
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
-     * Only keys listed from {@link #getParameterKeys()} should be used.
-     * @param parameters has format of key1=value1;key2=value2;...
-     * @throws CarNotConnectedException
-     *
-     * @hide
-     */
-    public void setParameters(String parameters) throws CarNotConnectedException {
-        try {
-            mService.setParameters(parameters);
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "setParameters failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Get parameters for the key passed.
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
-     * Only keys listed from {@link #getParameterKeys()} should be used.
-     * @param keys Keys to get value. Format is key1;key2;...
-     * @return Parameters in format of key1=value1;key2=value2;...
-     * @throws CarNotConnectedException
-     *
-     * @hide
-     */
-    public String getParameters(String keys) throws CarNotConnectedException {
-        try {
-            return mService.getParameters(keys);
-        } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "getParameters failed", e);
-            throw new CarNotConnectedException(e);
-        }
-    }
-
-    /**
-     * Set listener to monitor audio parameter changes.
-     * Requires {@link android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS} permission.
-     * @param listener Non-null listener will start monitoring. null listener will stop listening.
-     * @throws CarNotConnectedException
-     *
-     * @hide
-     */
-    public void setOnParameterChangeListener(OnParameterChangeListener listener)
+    @SystemApi
+    public void registerVolumeCallback(@NonNull IBinder binder)
             throws CarNotConnectedException {
-        ParameterChangeCallback oldCb = null;
-        ParameterChangeCallback newCb = null;
-        synchronized (this) {
-            if (listener != null) {
-                if (mParameterChangeCallback != null) {
-                    oldCb = mParameterChangeCallback;
-                }
-                newCb = new ParameterChangeCallback(this);
-            }
-            mParameterChangeCallback = newCb;
-            mOnParameterChangeListener = listener;
-        }
         try {
-            if (oldCb != null) {
-                mService.unregisterOnParameterChangeListener(oldCb);
-            }
-            if (newCb != null) {
-                mService.registerOnParameterChangeListener(newCb);
-            }
+            mService.registerVolumeCallback(binder);
         } catch (RemoteException e) {
-            Log.e(CarLibLog.TAG_CAR, "setOnParameterChangeListener failed", e);
+            Log.e(CarLibLog.TAG_CAR, "registerVolumeCallback failed", e);
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Unregister {@link ICarVolumeCallback} from receiving volume key events
+     *
+     * Requires {@link android.car.Car#PERMISSION_CAR_CONTROL_AUDIO_VOLUME} permission.
+     *
+     * @param binder {@link IBinder} instance of {@link ICarVolumeCallback} to stop receiving
+     *                              volume key event callbacks
+     * @throws CarNotConnectedException
+     */
+    @SystemApi
+    public void unregisterVolumeCallback(@NonNull IBinder binder)
+            throws CarNotConnectedException {
+        try {
+            mService.unregisterVolumeCallback(binder);
+        } catch (RemoteException e) {
+            Log.e(CarLibLog.TAG_CAR, "unregisterVolumeCallback failed", e);
             throw new CarNotConnectedException(e);
         }
     }
@@ -487,40 +370,7 @@
 
     /** @hide */
     public CarAudioManager(IBinder service, Context context, Handler handler) {
+        mContentResolver = context.getContentResolver();
         mService = ICarAudio.Stub.asInterface(service);
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        mHandler = handler;
-    }
-
-    private AudioAttributes createAudioAttributes(int contentType, int usage) {
-        AudioAttributes.Builder builder = new AudioAttributes.Builder();
-        return builder.setContentType(contentType).setUsage(usage).build();
-    }
-
-    private static class ParameterChangeCallback extends ICarAudioCallback.Stub {
-
-        private final WeakReference<CarAudioManager> mManager;
-
-        private ParameterChangeCallback(CarAudioManager manager) {
-            mManager = new WeakReference<>(manager);
-        }
-
-        @Override
-        public void onParameterChange(final String params) {
-            CarAudioManager manager = mManager.get();
-            if (manager == null) {
-                return;
-            }
-            final OnParameterChangeListener listener = manager.mOnParameterChangeListener;
-            if (listener == null) {
-                return;
-            }
-            manager.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    listener.onParameterChange(params);
-                }
-            });
-        }
     }
 }
diff --git a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl b/car-lib/src/android/car/media/CarAudioPatchHandle.aidl
similarity index 73%
copy from car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
copy to car-lib/src/android/car/media/CarAudioPatchHandle.aidl
index 0865646..8e2a890 100644
--- a/car-lib/src/android/car/hardware/radio/CarRadioEvent.aidl
+++ b/car-lib/src/android/car/media/CarAudioPatchHandle.aidl
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
-package android.car.hardware.radio;
+package android.car.media;
 
-parcelable CarRadioEvent;
+
+/**
+ * Container for audioPatch which facilitates automatic clean up of abandoned audioPatches
+ * if/when the original patch creator quits.
+ *
+ * @hide
+ */
+parcelable CarAudioPatchHandle;
\ No newline at end of file
diff --git a/car-lib/src/android/car/media/CarAudioPatchHandle.java b/car-lib/src/android/car/media/CarAudioPatchHandle.java
new file mode 100644
index 0000000..bbcc791
--- /dev/null
+++ b/car-lib/src/android/car/media/CarAudioPatchHandle.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 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 android.car.media;
+
+import android.media.AudioDevicePort;
+import android.media.AudioPatch;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A class to encapsulate the handle for a system level audio patch. This is used
+ * to provide a "safe" way for permitted applications to route automotive audio sources
+ * outside of android.
+ */
+public final class CarAudioPatchHandle implements Parcelable {
+
+    // This is enough information to uniquely identify a patch to the system
+    private final int mHandleId;
+    private final String mSourceAddress;
+    private final String mSinkAddress;
+
+    /**
+     * Construct a audio patch handle container given the system level handle
+     * NOTE: Assumes (as it true today), that there is exactly one device port in the source
+     * and sink arrays.
+     */
+    public CarAudioPatchHandle(AudioPatch patch) {
+        Preconditions.checkArgument(patch.sources().length == 1
+                && patch.sources()[0].port() instanceof AudioDevicePort,
+                "Accepts exactly one device port as source");
+        Preconditions.checkArgument(patch.sinks().length == 1
+                && patch.sinks()[0].port() instanceof AudioDevicePort,
+                "Accepts exactly one device port as sink");
+
+        mHandleId = patch.id();
+        mSourceAddress = ((AudioDevicePort) patch.sources()[0].port()).address();
+        mSinkAddress = ((AudioDevicePort) patch.sinks()[0].port()).address();
+    }
+
+    /**
+     * Returns true if this instance matches the provided AudioPatch object.
+     * This is intended only for use by the CarAudioManager implementation when
+     * communicating with the AudioManager API.
+     *
+     * Effectively only the {@link #mHandleId} is used for comparison,
+     * {@link android.media.AudioSystem#listAudioPatches(java.util.ArrayList, int[])}
+     * does not populate the device type and address properly.
+     *
+     * @hide
+     */
+    public boolean represents(AudioPatch patch) {
+        return patch.sources().length == 1
+                && patch.sinks().length == 1
+                && patch.id() == mHandleId;
+    }
+
+    @Override
+    public String toString() {
+        return "Patch (mHandleId=" + mHandleId + "): "
+                + mSourceAddress + " => " + mSinkAddress;
+    }
+
+    /**
+     * Given a parcel, populate our data members
+     */
+    private CarAudioPatchHandle(Parcel in) {
+        mHandleId = in.readInt();
+        mSourceAddress = in.readString();
+        mSinkAddress = in.readString();
+    }
+
+    /**
+     * Serialize our internal data to a parcel
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mHandleId);
+        out.writeString(mSourceAddress);
+        out.writeString(mSinkAddress);
+    }
+
+    public static final Parcelable.Creator<CarAudioPatchHandle> CREATOR
+            = new Parcelable.Creator<CarAudioPatchHandle>() {
+        public CarAudioPatchHandle createFromParcel(Parcel in) {
+            return new CarAudioPatchHandle(in);
+        }
+
+        public CarAudioPatchHandle[] newArray(int size) {
+            return new CarAudioPatchHandle[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/car-lib/src/android/car/media/ICarAudio.aidl b/car-lib/src/android/car/media/ICarAudio.aidl
index 6d9b3ce..353c168 100644
--- a/car-lib/src/android/car/media/ICarAudio.aidl
+++ b/car-lib/src/android/car/media/ICarAudio.aidl
@@ -16,9 +16,7 @@
 
 package android.car.media;
 
-import android.car.media.ICarAudioCallback;
-import android.media.AudioAttributes;
-import android.media.IVolumeController;
+import android.car.media.CarAudioPatchHandle;
 
 /**
  * Binder interface for {@link android.car.media.CarAudioManager}.
@@ -27,21 +25,25 @@
  * @hide
  */
 interface ICarAudio {
-    AudioAttributes getAudioAttributesForCarUsage(int carUsage) = 0;
-    void setStreamVolume(int streamType, int index, int flags) = 1;
-    void setVolumeController(IVolumeController controller) = 2;
-    int getStreamMaxVolume(int streamType) = 3;
-    int getStreamMinVolume(int streamType) = 4;
-    int getStreamVolume(int streamType) = 5;
-    boolean isMediaMuted() = 6;
-    boolean setMediaMute(boolean mute) = 7;
-    AudioAttributes getAudioAttributesForRadio(in String radioType) = 8;
-    AudioAttributes getAudioAttributesForExternalSource(in String externalSourceType) = 9;
-    String[] getSupportedExternalSourceTypes() = 10;
-    String[] getSupportedRadioTypes() = 11;
-    String[] getParameterKeys() = 12;
-    void setParameters(in String parameters) = 13;
-    String getParameters(in String keys) = 14;
-    void registerOnParameterChangeListener(in ICarAudioCallback callback) = 15;
-    void unregisterOnParameterChangeListener(in ICarAudioCallback callback) = 16;
+    void setGroupVolume(int groupId, int index, int flags);
+    int getGroupMaxVolume(int groupId);
+    int getGroupMinVolume(int groupId);
+    int getGroupVolume(int groupId);
+
+    void setFadeTowardFront(float value);
+    void setBalanceTowardRight(float value);
+
+    String[] getExternalSources();
+    CarAudioPatchHandle createAudioPatch(in String sourceAddress, int usage, int gainInMillibels);
+    void releaseAudioPatch(in CarAudioPatchHandle patch);
+
+    int getVolumeGroupCount();
+    int getVolumeGroupIdForUsage(int usage);
+    int[] getUsagesForVolumeGroupId(int groupId);
+
+    /**
+     * IBinder is ICarVolumeCallback but passed as IBinder due to aidl hidden.
+     */
+    void registerVolumeCallback(in IBinder binder);
+    void unregisterVolumeCallback(in IBinder binder);
 }
diff --git a/car-lib/src/android/car/media/ICarVolumeCallback.aidl b/car-lib/src/android/car/media/ICarVolumeCallback.aidl
new file mode 100644
index 0000000..8540680
--- /dev/null
+++ b/car-lib/src/android/car/media/ICarVolumeCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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 android.car.media;
+
+/**
+ * Binder interface to callback the volume key events.
+ *
+ * @hide
+ */
+on