Merge "Process "dalvik.vm.profilebootimage" system property"
diff --git a/cmds/backup/Android.bp b/cmds/backup/Android.bp
new file mode 100644
index 0000000..287c23b
--- /dev/null
+++ b/cmds/backup/Android.bp
@@ -0,0 +1,20 @@
+// Copyright 2009 The Android Open Source Project
+
+cc_binary {
+    name: "btool",
+
+    srcs: ["backup.cpp"],
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libandroidfw",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/cmds/backup/Android.mk b/cmds/backup/Android.mk
deleted file mode 100644
index 8e1508c..0000000
--- a/cmds/backup/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2009 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= backup.cpp
-
-LOCAL_SHARED_LIBRARIES := libcutils libutils libandroidfw
-
-LOCAL_MODULE:= btool
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index a68f485..0c91a20 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -16,6 +16,7 @@
 
 package android.bluetooth;
 
+import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -633,8 +634,9 @@
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param device Bluetooth headset
-     * @return false if there is no headset connected of if the connected headset doesn't support
-     * voice recognition or on error, true otherwise
+     * @return false if there is no headset connected, or the connected headset doesn't support
+     * voice recognition, or voice recognition is already started, or audio channel is occupied,
+     * or on error, true otherwise
      */
     public boolean startVoiceRecognition(BluetoothDevice device) {
         if (DBG) log("startVoiceRecognition()");
@@ -654,10 +656,15 @@
      * Stop Bluetooth Voice Recognition mode, and shut down the
      * Bluetooth audio path.
      *
+     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
+     * If this function returns true, this intent will be broadcasted with
+     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
+     *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param device Bluetooth headset
-     * @return false if there is no headset connected or on error, true otherwise
+     * @return false if there is no headset connected, or voice recognition has not started,
+     * or voice recognition has ended on this headset, or on error, true otherwise
      */
     public boolean stopVoiceRecognition(BluetoothDevice device) {
         if (DBG) log("stopVoiceRecognition()");
@@ -798,11 +805,12 @@
     }
 
     /**
-     * Check if Bluetooth SCO audio is connected.
+     * Check if at least one headset's SCO audio is connected or connecting
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @return true if SCO is connected, false otherwise or on error
+     * @return true if at least one device's SCO audio is connected or connecting, false otherwise
+     * or on error
      * @hide
      */
     public boolean isAudioOn() {
@@ -821,11 +829,21 @@
     }
 
     /**
-     * Initiates a connection of headset audio.
-     * It setup SCO channel with remote connected headset device.
+     * Initiates a connection of headset audio to the current active device
      *
-     * @return true if successful false if there was some error such as there is no connected
-     * headset
+     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
+     * If this function returns true, this intent will be broadcasted with
+     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
+     *
+     * <p> {@link #EXTRA_STATE} will transition from
+     * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
+     * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
+     * in case of failure to establish the audio connection.
+     *
+     * Note that this intent will not be sent if {@link BluetoothHeadset#isAudioOn()} is true
+     * before calling this method
+     *
+     * @return false if there was some error such as there is no active headset
      * @hide
      */
     public boolean connectAudio() {
@@ -844,11 +862,14 @@
     }
 
     /**
-     * Initiates a disconnection of headset audio.
-     * It tears down the SCO channel from remote headset device.
+     * Initiates a disconnection of HFP SCO audio.
+     * Tear down voice recognition or virtual voice call if any.
      *
-     * @return true if successful false if there was some error such as there is no connected SCO
-     * channel
+     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
+     * If this function returns true, this intent will be broadcasted with
+     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
+     *
+     * @return false if audio is not connected, or on error, true otherwise
      * @hide
      */
     public boolean disconnectAudio() {
@@ -867,22 +888,33 @@
     }
 
     /**
-     * Initiates a SCO channel connection with the headset (if connected).
-     * Also initiates a virtual voice call for Handsfree devices as many devices
-     * do not accept SCO audio without a call.
-     * This API allows the handsfree device to be used for routing non-cellular
-     * call audio.
+     * Initiates a SCO channel connection as a virtual voice call to the current active device
+     * Active handsfree device will be notified of incoming call and connected call.
      *
-     * @param device Remote Bluetooth Device
-     * @return true if successful, false if there was some error.
+     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
+     * If this function returns true, this intent will be broadcasted with
+     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
+     *
+     * <p> {@link #EXTRA_STATE} will transition from
+     * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
+     * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
+     * in case of failure to establish the audio connection.
+     *
+     * @return true if successful, false if one of the following case applies
+     *  - SCO audio is not idle (connecting or connected)
+     *  - virtual call has already started
+     *  - there is no active device
+     *  - a Telecom managed call is going on
+     *  - binder is dead or Bluetooth is disabled or other error
      * @hide
      */
-    public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) {
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean startScoUsingVirtualVoiceCall() {
         if (DBG) log("startScoUsingVirtualVoiceCall()");
         final IBluetoothHeadset service = mService;
-        if (service != null && isEnabled() && isValidDevice(device)) {
+        if (service != null && isEnabled()) {
             try {
-                return service.startScoUsingVirtualVoiceCall(device);
+                return service.startScoUsingVirtualVoiceCall();
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -894,19 +926,24 @@
     }
 
     /**
-     * Terminates an ongoing SCO connection and the associated virtual
-     * call.
+     * Terminates an ongoing SCO connection and the associated virtual call.
      *
-     * @param device Remote Bluetooth Device
-     * @return true if successful, false if there was some error.
+     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
+     * If this function returns true, this intent will be broadcasted with
+     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
+     *
+     * @return true if successful, false if one of the following case applies
+     *  - virtual voice call is not started or has ended
+     *  - binder is dead or Bluetooth is disabled or other error
      * @hide
      */
-    public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) {
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean stopScoUsingVirtualVoiceCall() {
         if (DBG) log("stopScoUsingVirtualVoiceCall()");
         final IBluetoothHeadset service = mService;
-        if (service != null && isEnabled() && isValidDevice(device)) {
+        if (service != null && isEnabled()) {
             try {
-                return service.stopScoUsingVirtualVoiceCall(device);
+                return service.stopScoUsingVirtualVoiceCall();
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 14727f0..00060ab 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -253,7 +253,7 @@
      * @return String containing the OpenMobile API version (e.g. "3.0").
      */
     public @NonNull String getVersion() {
-        return "3.2";
+        return "3.3";
     }
 
     @NonNull ISecureElementListener getListener() {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6591497..c1608cb 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -672,8 +672,6 @@
         executionMode = kEMJitCompiler;
     }
 
-    addOption("-Xusetombstonedtraces");
-
     strcpy(jniOptsBuf, "-Xjniopts:");
     if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
         ALOGI("JNI options: '%s'\n", jniOptsBuf);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 20a5afe..45d02b1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1392,6 +1392,11 @@
     <permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows an app to bypass Private DNS.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
diff --git a/core/res/res/values-mcc405/config.xml b/core/res/res/values-mcc405/config.xml
index 6b77e9c..4cadef7 100644
--- a/core/res/res/values-mcc405/config.xml
+++ b/core/res/res/values-mcc405/config.xml
@@ -20,4 +20,6 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Whether camera shutter sound is forced or not  (country specific). -->
     <bool name="config_camera_sound_forced">true</bool>
+    <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
+    <bool name="config_showAreaUpdateInfoSettings">true</bool>
 </resources>
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
index f520b0e..c6758ce 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
@@ -80,7 +80,7 @@
         uidPoliciesToStringTest(POLICY_REJECT_METERED_BACKGROUND,
                 "1 (REJECT_METERED_BACKGROUND)");
         uidPoliciesToStringTest(POLICY_ALLOW_METERED_BACKGROUND,
-                "4 (ALLOW_BACKGROUND_BATTERY_SAVE)");
+                "4 (ALLOW_METERED_BACKGROUND)");
     }
 
     private void uidPoliciesToStringTest(int policyRules, String... expectedOptions) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a80c741..b110ccf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4276,8 +4276,7 @@
     /**
      * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
      */
-    private ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>
-        mDeviceCallbacks =
+    private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
             new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
 
     /**
@@ -4488,22 +4487,21 @@
                     calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
             AudioDeviceInfo[] removed_devices =
                     calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
-
             if (added_devices.length != 0 || removed_devices.length != 0) {
                 synchronized (mDeviceCallbacks) {
                     for (int i = 0; i < mDeviceCallbacks.size(); i++) {
                         handler = mDeviceCallbacks.valueAt(i).getHandler();
                         if (handler != null) {
-                            if (added_devices.length != 0) {
-                                handler.sendMessage(Message.obtain(handler,
-                                                                   MSG_DEVICES_DEVICES_ADDED,
-                                                                   added_devices));
-                            }
                             if (removed_devices.length != 0) {
                                 handler.sendMessage(Message.obtain(handler,
                                                                    MSG_DEVICES_DEVICES_REMOVED,
                                                                    removed_devices));
                             }
+                            if (added_devices.length != 0) {
+                                handler.sendMessage(Message.obtain(handler,
+                                                                   MSG_DEVICES_DEVICES_ADDED,
+                                                                   added_devices));
+                            }
                         }
                     }
                 }
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index f21fd88..e01e95b 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
 
     <application android:label="@string/app_name" >
         <activity
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 1cd7b61..425df71 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -25,6 +25,7 @@
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
+    <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
 
     <application
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
index dac3ed6..605a75d 100644
--- a/packages/EasterEgg/Android.mk
+++ b/packages/EasterEgg/Android.mk
@@ -2,17 +2,23 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
+
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    jsr305
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
     android-support-v4 \
     android-support-v13 \
     android-support-dynamic-animation \
     android-support-v7-recyclerview \
     android-support-v7-preference \
     android-support-v7-appcompat \
-    android-support-v14-preference \
-    jsr305
+    android-support-v14-preference
+
+LOCAL_USE_AAPT2 := true
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_PACKAGE_NAME := EasterEgg
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index 67ef6b4..e356f38 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -18,18 +18,27 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res frameworks/support/v7/recyclerview/res
-LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages android.support.v7.recyclerview
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_USE_AAPT2 := true
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += \
-        src/com/android/printspooler/renderer/IPdfRenderer.aidl \
-        src/com/android/printspooler/renderer/IPdfEditor.aidl
+    src/com/android/printspooler/renderer/IPdfRenderer.aidl \
+    src/com/android/printspooler/renderer/IPdfEditor.aidl
 
 LOCAL_PACKAGE_NAME := PrintSpooler
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    android-support-v7-recyclerview \
+    android-support-compat \
+    android-support-media-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-annotations
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index 37cb721..fd7c87e 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -3,6 +3,8 @@
 
 LOCAL_USE_AAPT2 := true
 
+LOCAL_AAPT2_ONLY := true
+
 LOCAL_MODULE := SettingsLib
 
 LOCAL_SHARED_ANDROID_LIBRARIES := \
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 46b66c4..ec7ca2e 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -13,49 +13,7 @@
 #   include frameworks/base/packages/SettingsLib/common.mk
 #
 
-ifeq ($(LOCAL_USE_AAPT2),true)
 LOCAL_STATIC_ANDROID_LIBRARIES += \
     android-support-annotations \
     android-support-v4 \
     SettingsLib
-else
-LOCAL_RESOURCE_DIR += $(call my-dir)/res
-
-
-## Include transitive dependencies below
-
-# Include support-v7-appcompat, if not already included
-ifeq (,$(findstring android-support-v7-appcompat,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
-LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
-endif
-
-# Include support-v7-recyclerview, if not already included
-ifeq (,$(findstring android-support-v7-recyclerview,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
-LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
-endif
-
-# Include android-support-v7-preference, if not already included
-ifeq (,$(findstring android-support-v7-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/preference/res
-LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference
-endif
-
-# Include android-support-v14-preference, if not already included
-ifeq (,$(findstring android-support-v14-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v14/preference/res
-LOCAL_AAPT_FLAGS += --extra-packages android.support.v14.preference
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v14-preference
-endif
-
-LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.settingslib
-
-LOCAL_STATIC_JAVA_LIBRARIES += \
-    android-support-annotations \
-    android-support-v4 \
-    SettingsLib
-endif
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 5bd9e4c..dd24be4 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -28,6 +28,8 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
+LOCAL_USE_AAPT2 := true
+
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
     espresso-core \
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index bc28863..f4ea258 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -29,6 +29,8 @@
 LOCAL_RESOURCE_DIR := \
     $(LOCAL_PATH)/res
 
+LOCAL_USE_AAPT2 := true
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4792018..8a643ed 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -487,6 +487,8 @@
     private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
     // SCO audio deactivation request waiting for headset service to connect
     private static final int SCO_STATE_DEACTIVATE_REQ = 5;
+    // SCO audio deactivation in progress, waiting for Bluetooth audio intent
+    private static final int SCO_STATE_DEACTIVATING = 6;
 
     // SCO audio state is active due to an action in BT handsfree (either voice recognition or
     // in call audio)
@@ -2466,9 +2468,13 @@
         }
 
         public void binderDied() {
+            int oldModeOwnerPid = 0;
             int newModeOwnerPid = 0;
             synchronized(mSetModeDeathHandlers) {
                 Log.w(TAG, "setMode() client died");
+                if (!mSetModeDeathHandlers.isEmpty()) {
+                    oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
+                }
                 int index = mSetModeDeathHandlers.indexOf(this);
                 if (index < 0) {
                     Log.w(TAG, "unregistered setMode() client died");
@@ -2477,8 +2483,8 @@
                 }
             }
             // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
-            // SCO connections not started by the application changing the mode
-            if (newModeOwnerPid != 0) {
+            // SCO connections not started by the application changing the mode when pid changes
+            if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
                 final long ident = Binder.clearCallingIdentity();
                 disconnectBluetoothSco(newModeOwnerPid);
                 Binder.restoreCallingIdentity(ident);
@@ -2522,17 +2528,21 @@
             return;
         }
 
+        int oldModeOwnerPid = 0;
         int newModeOwnerPid = 0;
         synchronized(mSetModeDeathHandlers) {
+            if (!mSetModeDeathHandlers.isEmpty()) {
+                oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
+            }
             if (mode == AudioSystem.MODE_CURRENT) {
                 mode = mMode;
             }
             newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
         }
         // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
-        // SCO connections not started by the application changing the mode
-        if (newModeOwnerPid != 0) {
-             disconnectBluetoothSco(newModeOwnerPid);
+        // SCO connections not started by the application changing the mode when pid changes
+        if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
+            disconnectBluetoothSco(newModeOwnerPid);
         }
     }
 
@@ -2928,7 +2938,7 @@
         }
 
         // Only enable calls from system components
-        if (Binder.getCallingUid() >= FIRST_APPLICATION_UID) {
+        if (UserHandle.getCallingAppId() >= FIRST_APPLICATION_UID) {
             mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
             return;
         }
@@ -2941,28 +2951,17 @@
     }
 
     public void setBluetoothScoOnInt(boolean on, String eventSource) {
-        if (DEBUG_DEVICES) {
-            Log.d(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
-        }
+        Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
         if (on) {
             // do not accept SCO ON if SCO audio is not connected
             synchronized (mScoClients) {
-                if (mBluetoothHeadset != null) {
-                    if (mBluetoothHeadsetDevice == null) {
-                        BluetoothDevice activeDevice = mBluetoothHeadset.getActiveDevice();
-                        if (activeDevice != null) {
-                            // setBtScoActiveDevice() might trigger resetBluetoothSco() which
-                            // will call setBluetoothScoOnInt(false, "resetBluetoothSco")
-                            setBtScoActiveDevice(activeDevice);
-                        }
-                    }
-                    if (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                            != BluetoothHeadset.STATE_AUDIO_CONNECTED) {
-                        mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
-                        Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
-                                + mBluetoothHeadsetDevice + " is not in audio connected mode");
-                        return;
-                    }
+                if ((mBluetoothHeadset != null)
+                        && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                            != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+                    mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+                    Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
+                            + mBluetoothHeadsetDevice + " is not in audio connected mode");
+                    return;
                 }
             }
             mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
@@ -3140,9 +3139,8 @@
         public int totalCount() {
             synchronized(mScoClients) {
                 int count = 0;
-                int size = mScoClients.size();
-                for (int i = 0; i < size; i++) {
-                    count += mScoClients.get(i).getCount();
+                for (ScoClient mScoClient : mScoClients) {
+                    count += mScoClient.getCount();
                 }
                 return count;
             }
@@ -3150,128 +3148,161 @@
 
         private void requestScoState(int state, int scoAudioMode) {
             checkScoAudioState();
-            if (totalCount() == 0) {
-                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
-                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
-                    // the connection.
-                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
-                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
-                    // currently controlled by the same client process.
-                    synchronized(mSetModeDeathHandlers) {
-                        if ((mSetModeDeathHandlers.isEmpty() ||
-                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
-                                (mScoAudioState == SCO_STATE_INACTIVE ||
-                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
-                            if (mScoAudioState == SCO_STATE_INACTIVE) {
-                                mScoAudioMode = scoAudioMode;
-                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
-                                    if (mBluetoothHeadsetDevice != null) {
-                                        mScoAudioMode = new Integer(Settings.Global.getInt(
-                                                                mContentResolver,
-                                                                "bluetooth_sco_channel_"+
-                                                                mBluetoothHeadsetDevice.getAddress(),
-                                                                SCO_MODE_VIRTUAL_CALL));
-                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
-                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
-                                        }
-                                    } else {
-                                        mScoAudioMode = SCO_MODE_RAW;
-                                    }
-                                }
-                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    boolean status = false;
-                                    if (mScoAudioMode == SCO_MODE_RAW) {
-                                        status = mBluetoothHeadset.connectAudio();
-                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                                                            mBluetoothHeadsetDevice);
-                                    } else if (mScoAudioMode == SCO_MODE_VR) {
-                                        status = mBluetoothHeadset.startVoiceRecognition(
-                                                                           mBluetoothHeadsetDevice);
-                                    }
-
-                                    if (status) {
-                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                    } else {
-                                        broadcastScoConnectionState(
-                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                                    }
-                                } else if (getBluetoothHeadset()) {
-                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
-                                }
-                            } else {
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
-                            }
-                        } else {
-                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                        }
+            int clientCount = totalCount();
+            if (clientCount != 0) {
+                Log.i(TAG, "requestScoState: state=" + state + ", scoAudioMode=" + scoAudioMode
+                        + ", clientCount=" + clientCount);
+                return;
+            }
+            if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+                // Make sure that the state transitions to CONNECTING even if we cannot initiate
+                // the connection.
+                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+                // Accept SCO audio activation only in NORMAL audio mode or if the mode is
+                // currently controlled by the same client process.
+                synchronized(mSetModeDeathHandlers) {
+                    int modeOwnerPid =  mSetModeDeathHandlers.isEmpty()
+                            ? 0 : mSetModeDeathHandlers.get(0).getPid();
+                    if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
+                        Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
+                                + modeOwnerPid + " != creatorPid " + mCreatorPid);
+                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        return;
                     }
-                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
-                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
-                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
-                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
-                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            boolean status = false;
-                            if (mScoAudioMode == SCO_MODE_RAW) {
-                                status = mBluetoothHeadset.disconnectAudio();
-                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                            } else if (mScoAudioMode == SCO_MODE_VR) {
-                                        status = mBluetoothHeadset.stopVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
+                    switch (mScoAudioState) {
+                        case SCO_STATE_INACTIVE:
+                            mScoAudioMode = scoAudioMode;
+                            if (scoAudioMode == SCO_MODE_UNDEFINED) {
+                                mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                if (mBluetoothHeadsetDevice != null) {
+                                    mScoAudioMode = Settings.Global.getInt(mContentResolver,
+                                            "bluetooth_sco_channel_"
+                                                    + mBluetoothHeadsetDevice.getAddress(),
+                                            SCO_MODE_VIRTUAL_CALL);
+                                    if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+                                        mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                    }
+                                }
                             }
+                            if (mBluetoothHeadset == null) {
+                                if (getBluetoothHeadset()) {
+                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                                } else {
+                                    Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
+                                            + " connection, mScoAudioMode=" + mScoAudioMode);
+                                    broadcastScoConnectionState(
+                                            AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                                }
+                                break;
+                            }
+                            if (mBluetoothHeadsetDevice == null) {
+                                Log.w(TAG, "requestScoState: no active device while connecting,"
+                                        + " mScoAudioMode=" + mScoAudioMode);
+                                broadcastScoConnectionState(
+                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                                break;
+                            }
+                            if (connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                    mBluetoothHeadsetDevice, mScoAudioMode)) {
+                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                            } else {
+                                Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
+                                        + " failed, mScoAudioMode=" + mScoAudioMode);
+                                broadcastScoConnectionState(
+                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                            }
+                            break;
+                        case SCO_STATE_DEACTIVATING:
+                            mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                            break;
+                        case SCO_STATE_DEACTIVATE_REQ:
+                            mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+                            break;
+                        default:
+                            Log.w(TAG, "requestScoState: failed to connect in state "
+                                    + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
+                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                            break;
 
-                            if (!status) {
+                    }
+                }
+            } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+                switch (mScoAudioState) {
+                    case SCO_STATE_ACTIVE_INTERNAL:
+                        if (mBluetoothHeadset == null) {
+                            if (getBluetoothHeadset()) {
+                                mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
+                            } else {
+                                Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
+                                        + " disconnection, mScoAudioMode=" + mScoAudioMode);
                                 mScoAudioState = SCO_STATE_INACTIVE;
                                 broadcastScoConnectionState(
                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                             }
-                        } else if (getBluetoothHeadset()) {
-                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
+                            break;
                         }
-                    } else {
+                        if (mBluetoothHeadsetDevice == null) {
+                            mScoAudioState = SCO_STATE_INACTIVE;
+                            broadcastScoConnectionState(
+                                    AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                            break;
+                        }
+                        if (disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, mScoAudioMode)) {
+                            mScoAudioState = SCO_STATE_DEACTIVATING;
+                        } else {
+                            mScoAudioState = SCO_STATE_INACTIVE;
+                            broadcastScoConnectionState(
+                                    AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        }
+                        break;
+                    case SCO_STATE_ACTIVATE_REQ:
                         mScoAudioState = SCO_STATE_INACTIVE;
                         broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                    }
+                        break;
+                    default:
+                        Log.w(TAG, "requestScoState: failed to disconnect in state "
+                                + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
+                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        break;
                 }
             }
         }
     }
 
     private void checkScoAudioState() {
-        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
-                mScoAudioState == SCO_STATE_INACTIVE &&
-                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+        synchronized (mScoClients) {
+            if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
+                    mScoAudioState == SCO_STATE_INACTIVE &&
+                    mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                            != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+                mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+            }
         }
     }
 
+
     private ScoClient getScoClient(IBinder cb, boolean create) {
         synchronized(mScoClients) {
-            ScoClient client = null;
-            int size = mScoClients.size();
-            for (int i = 0; i < size; i++) {
-                client = mScoClients.get(i);
-                if (client.getBinder() == cb)
-                    return client;
+            for (ScoClient existingClient : mScoClients) {
+                if (existingClient.getBinder() == cb) {
+                    return existingClient;
+                }
             }
             if (create) {
-                client = new ScoClient(cb);
-                mScoClients.add(client);
+                ScoClient newClient = new ScoClient(cb);
+                mScoClients.add(newClient);
+                return newClient;
             }
-            return client;
+            return null;
         }
     }
 
     public void clearAllScoClients(int exceptPid, boolean stopSco) {
         synchronized(mScoClients) {
             ScoClient savedClient = null;
-            int size = mScoClients.size();
-            for (int i = 0; i < size; i++) {
-                ScoClient cl = mScoClients.get(i);
+            for (ScoClient cl : mScoClients) {
                 if (cl.getPid() != exceptPid) {
                     cl.clearCount(stopSco);
                 } else {
@@ -3308,10 +3339,17 @@
                     mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
                 if (mBluetoothHeadsetDevice != null) {
                     if (mBluetoothHeadset != null) {
-                        if (!mBluetoothHeadset.stopVoiceRecognition(
-                                mBluetoothHeadsetDevice)) {
-                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
-                                    SENDMSG_REPLACE, 0, 0, null, 0);
+                        boolean status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, SCO_MODE_RAW)
+                                || disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL)
+                                || disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, SCO_MODE_VR);
+                        if (status) {
+                            mScoAudioState = SCO_STATE_DEACTIVATING;
+                        } else {
+                            clearAllScoClients(exceptPid, false);
+                            mScoAudioState = SCO_STATE_INACTIVE;
                         }
                     } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
                             getBluetoothHeadset()) {
@@ -3324,6 +3362,34 @@
         }
     }
 
+    private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
+            BluetoothDevice device, int scoAudioMode) {
+        switch (scoAudioMode) {
+            case SCO_MODE_RAW:
+                return bluetoothHeadset.disconnectAudio();
+            case SCO_MODE_VIRTUAL_CALL:
+                return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
+            case SCO_MODE_VR:
+                return bluetoothHeadset.stopVoiceRecognition(device);
+            default:
+                return false;
+        }
+    }
+
+    private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
+            BluetoothDevice device, int scoAudioMode) {
+        switch (scoAudioMode) {
+            case SCO_MODE_RAW:
+                return bluetoothHeadset.connectAudio();
+            case SCO_MODE_VIRTUAL_CALL:
+                return bluetoothHeadset.startScoUsingVirtualVoiceCall();
+            case SCO_MODE_VR:
+                return bluetoothHeadset.startVoiceRecognition(device);
+            default:
+                return false;
+        }
+    }
+
     private void resetBluetoothSco() {
         synchronized(mScoClients) {
             clearAllScoClients(0, false);
@@ -3381,11 +3447,9 @@
         return result;
     }
 
-    void setBtScoActiveDevice(BluetoothDevice btDevice) {
-        if (DEBUG_DEVICES) {
-            Log.d(TAG, "setBtScoActiveDevice(" + btDevice + ")");
-        }
+    private void setBtScoActiveDevice(BluetoothDevice btDevice) {
         synchronized (mScoClients) {
+            Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
             final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
             if (!Objects.equals(btDevice, previousActiveDevice)) {
                 if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
@@ -3465,37 +3529,36 @@
                         boolean status = false;
                         if (mBluetoothHeadsetDevice != null) {
                             switch (mScoAudioState) {
-                            case SCO_STATE_ACTIVATE_REQ:
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                if (mScoAudioMode == SCO_MODE_RAW) {
-                                    status = mBluetoothHeadset.connectAudio();
-                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                                } else if (mScoAudioMode == SCO_MODE_VR) {
-                                    status = mBluetoothHeadset.startVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
-                                }
-                                break;
-                            case SCO_STATE_DEACTIVATE_REQ:
-                                if (mScoAudioMode == SCO_MODE_RAW) {
-                                    status = mBluetoothHeadset.disconnectAudio();
-                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                                } else if (mScoAudioMode == SCO_MODE_VR) {
-                                    status = mBluetoothHeadset.stopVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
-                                }
-                                break;
-                            case SCO_STATE_DEACTIVATE_EXT_REQ:
-                                status = mBluetoothHeadset.stopVoiceRecognition(
-                                        mBluetoothHeadsetDevice);
+                                case SCO_STATE_ACTIVATE_REQ:
+                                    status = connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                            mBluetoothHeadsetDevice, mScoAudioMode);
+                                    if (status) {
+                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                    }
+                                    break;
+                                case SCO_STATE_DEACTIVATE_REQ:
+                                    status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                            mBluetoothHeadsetDevice, mScoAudioMode);
+                                    if (status) {
+                                        mScoAudioState = SCO_STATE_DEACTIVATING;
+                                    }
+                                    break;
+                                case SCO_STATE_DEACTIVATE_EXT_REQ:
+                                    status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                            mBluetoothHeadsetDevice, SCO_MODE_RAW) ||
+                                            disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                            mBluetoothHeadsetDevice, SCO_MODE_VIRTUAL_CALL) ||
+                                            disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                            mBluetoothHeadsetDevice, SCO_MODE_VR);
+                                    if (status) {
+                                        mScoAudioState = SCO_STATE_DEACTIVATING;
+                                    }
+                                    break;
                             }
                         }
                         if (!status) {
-                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
-                                    SENDMSG_REPLACE, 0, 0, null, 0);
+                            mScoAudioState = SCO_STATE_INACTIVE;
+                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                         }
                     }
                 }
@@ -5757,33 +5820,47 @@
                     if (!mScoClients.isEmpty() &&
                             (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
                              mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
-                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
+                             mScoAudioState == SCO_STATE_DEACTIVATING)) {
                         broadcast = true;
                     }
                     switch (btState) {
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                        }
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
-                        mScoAudioState = SCO_STATE_INACTIVE;
-                        clearAllScoClients(0, false);
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                        }
-                    default:
-                        // do not broadcast CONNECTING or invalid state
-                        broadcast = false;
-                        break;
+                        case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+                            scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+                            if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+                                mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+                                mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+                                mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                            }
+                            setBluetoothScoOn(true);
+                            break;
+                        case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+                            setBluetoothScoOn(false);
+                            scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+                            // startBluetoothSco called after stopBluetoothSco
+                            if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+                                        && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                        mBluetoothHeadsetDevice, mScoAudioMode)) {
+                                    mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                    broadcast = false;
+                                    break;
+                                }
+                            }
+                            // Tear down SCO if disconnected from external
+                            clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
+                            mScoAudioState = SCO_STATE_INACTIVE;
+                            break;
+                        case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+                            if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+                                mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+                                mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+                                mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                            }
+                        default:
+                            // do not broadcast CONNECTING or invalid state
+                            broadcast = false;
+                            break;
                     }
                 }
                 if (broadcast) {
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 9e95369..29d7ea9 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -64,3 +64,48 @@
     // Pin java_version until jarjar is certified to support later versions. http://b/72703434
     java_version: "1.8",
 }
+
+droiddoc {
+    name: "android-test-runner-api-stubs-gen-docs",
+    srcs: [
+        "src/**/*.java",
+    ],
+    libs: [
+        "core-oj",
+        "core-libart",
+        "framework",
+        "android.test.base",
+        "android.test.mock",
+    ],
+    custom_template: "droiddoc-templates-sdk",
+    installable: false,
+    args: "-stubpackages android.test:" +
+          "android.test.suitebuilder:" +
+          "junit.runner:" +
+          "junit.textui -stubsourceonly -nodocs",
+    api_tag_name: "ANDROID_TEST_RUNNER",
+    api_filename: "android-test-runner-current.txt",
+    removed_api_filename: "android-test-runner-removed.txt",
+}
+
+// Build the android.test.runner.stubs library
+// =========================================
+java_library_static {
+    name: "android.test.runner.stubs",
+    srcs: [
+        ":android-test-runner-api-stubs-gen-docs",
+    ],
+    libs: [
+        "android.test.base.stubs",
+        "android.test.mock.stubs",
+    ],
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+        unbundled_build: {
+            enabled: false,
+        },
+    },
+    sdk_version: "current",
+}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 706f636..b70d249 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -19,67 +19,10 @@
 # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
 ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
 
-# Generate the stub source files for android.test.runner.stubs
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
-    core-oj \
-    core-libart \
-    framework \
-    android.test.base \
-    android.test.mock \
-
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
-
-ANDROID_TEST_RUNNER_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/api.txt
-ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/removed.txt
-
 ANDROID_TEST_RUNNER_API_FILE := $(LOCAL_PATH)/api/android-test-runner-current.txt
 ANDROID_TEST_RUNNER_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-runner-removed.txt
 
-LOCAL_DROIDDOC_OPTIONS:= \
-    -stubpackages android.test:android.test.suitebuilder:junit.runner:junit.textui \
-    -stubsourceonly \
-    -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/src \
-    -nodocs \
-    -api $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) \
-    -removedApi $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := android-test-runner-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-android_test_runner_api_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(ANDROID_TEST_RUNNER_OUTPUT_API_FILE): $(full_target)
-$(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the android.test.runner.stubs library
-# ===========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.runner.stubs
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.base.stubs \
-    android.test.mock.stubs \
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SDK_VERSION := current
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_runner_api_gen_stamp)
-android_test_runner_api_gen_stamp :=
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
+full_classes_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,android.test.runner.stubs,,COMMON)/classes.jar
 # Archive a copy of the classes.jar in SDK build.
 $(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.runner.stubs.jar)
 
@@ -91,16 +34,16 @@
 $(eval $(call check-api, \
     check-android-test-runner-api-current, \
     $(ANDROID_TEST_RUNNER_API_FILE), \
-    $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_RUNNER_API_FILE), \
     $(ANDROID_TEST_RUNNER_REMOVED_API_FILE), \
-    $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_RUNNER_REMOVED_API_FILE), \
     -error 2 -error 3 -error 4 -error 5 -error 6 \
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
     -error 25 -error 26 -error 27, \
     cat $(LOCAL_PATH)/api/apicheck_msg_android_test_runner.txt, \
     check-android-test-runner-api, \
-    $(call doc-timestamp-for,android-test-runner-api-stubs-gen) \
+    $(OUT_DOCS)/android-test-runner-api-stubs-gen-docs-stubs.srcjar  \
     ))
 
 .PHONY: check-android-test-runner-api
@@ -109,11 +52,11 @@
 .PHONY: update-android-test-runner-api
 update-api: update-android-test-runner-api
 
-update-android-test-runner-api: $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) | $(ACP)
+update-android-test-runner-api: $(INTERNAL_PLATFORM_ANDROID_TEST_RUNNER_API_FILE) | $(ACP)
 	@echo Copying current.txt
-	$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) $(ANDROID_TEST_RUNNER_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_RUNNER_API_FILE) $(ANDROID_TEST_RUNNER_API_FILE)
 	@echo Copying removed.txt
-	$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_RUNNER_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
 
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
 
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index e6af4b02..60327e5 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -10,23 +10,11 @@
 
 # use appcompat/support lib from the tree, so improvements/
 # regressions are reflected in test data
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/res \
-    frameworks/support/design/res \
-    frameworks/support/v7/appcompat/res \
-    frameworks/support/v7/cardview/res \
-    frameworks/support/v7/recyclerview/res \
-    frameworks/support/v17/leanback/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-LOCAL_AAPT_FLAGS := \
-    --auto-add-overlay \
-    --extra-packages android.support.design \
-    --extra-packages android.support.v7.appcompat \
-    --extra-packages android.support.v7.cardview \
-    --extra-packages android.support.v7.recyclerview \
-    --extra-packages android.support.v17.leanback
+LOCAL_USE_AAPT2 := true
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
     android-support-design \
     android-support-v4 \
     android-support-v7-appcompat \
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 17ca651..2fb9faf 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -963,7 +963,6 @@
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-        String callingPackage = "the.calling.package";
         long thresholdInBytes = 1L;  // very small; should be overriden by framework
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
@@ -983,7 +982,7 @@
 
         // Register and verify request and that binder was called
         DataUsageRequest request =
-                mService.registerUsageCallback(callingPackage, inputRequest,
+                mService.registerUsageCallback(mServiceContext.getOpPackageName(), inputRequest,
                         messenger, mBinder);
         assertTrue(request.requestId > 0);
         assertTrue(Objects.equals(sTemplateWifi, request.template));