Merge change Ic0e32f12 into eclair-mr2

* changes:
  Add a callback for the ConnectSink Call.
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index f2e132b5..03dcf00 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -305,7 +305,11 @@
             return false;
 
         // State is DISCONNECTED
+        handleSinkStateChange(device, state, BluetoothA2dp.STATE_CONNECTING);
+
         if (!connectSinkNative(path)) {
+            // Restore previous state
+            handleSinkStateChange(device, mAudioDevices.get(device), state);
             return false;
         }
         return true;
@@ -321,7 +325,8 @@
             return false;
         }
 
-        switch (getSinkState(device)) {
+        int state = getSinkState(device);
+        switch (state) {
         case BluetoothA2dp.STATE_DISCONNECTED:
             return false;
         case BluetoothA2dp.STATE_DISCONNECTING:
@@ -329,11 +334,13 @@
         }
 
         // State is CONNECTING or CONNECTED or PLAYING
+        handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTING);
         if (!disconnectSinkNative(path)) {
+            // Restore previous state
+            handleSinkStateChange(device, mAudioDevices.get(device), state);
             return false;
-        } else {
-            return true;
         }
+        return true;
     }
 
     public synchronized boolean suspendSink(BluetoothDevice device) {
@@ -512,6 +519,19 @@
         return result;
     }
 
+    private void onConnectSinkResult(String deviceObjectPath, boolean result) {
+        // If the call was a success, ignore we will update the state
+        // when we a Sink Property Change
+        if (!result) {
+            if (deviceObjectPath != null) {
+                String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                int state = getSinkState(device);
+                handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
+            }
+        }
+    }
+
     @Override
     protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mAudioDevices.isEmpty()) return;
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 7a3bbbb..4eab4b3 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -38,6 +38,7 @@
 
 #ifdef HAVE_BLUETOOTH
 static jmethodID method_onSinkPropertyChanged;
+static jmethodID method_onConnectSinkResult;
 
 typedef struct {
     JavaVM *vm;
@@ -47,6 +48,7 @@
 } native_data_t;
 
 static native_data_t *nat = NULL;  // global native data
+static void onConnectSinkResult(DBusMessage *msg, void *user, void *n);
 
 static Properties sink_properties[] = {
         {"State", DBUS_TYPE_STRING},
@@ -133,9 +135,12 @@
     LOGV(__FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
+        int len = env->GetStringLength(path) + 1;
+        char *context_path = (char *)calloc(len, sizeof(char));
+        strlcpy(context_path, c_path, len);  // for callback
 
-        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
-                                    c_path, "org.bluez.AudioSink", "Connect",
+        bool ret = dbus_func_args_async(env, nat->conn, -1, onConnectSinkResult, context_path,
+                                    nat, c_path, "org.bluez.AudioSink", "Connect",
                                     DBUS_TYPE_INVALID);
 
         env->ReleaseStringUTFChars(path, c_path);
@@ -237,6 +242,31 @@
 
     return result;
 }
+
+void onConnectSinkResult(DBusMessage *msg, void *user, void *n) {
+    LOGV(__FUNCTION__);
+
+    native_data_t *nat = (native_data_t *)n;
+    const char *path = (const char *)user;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env;
+    nat->vm->GetEnv((void**)&env, nat->envVer);
+
+
+    bool result = JNI_TRUE;
+    if (dbus_set_error_from_message(&err, msg)) {
+        LOG_AND_FREE_DBUS_ERROR(&err);
+        result = JNI_FALSE;
+    }
+    LOGV("... Device Path = %s, result = %d", path, result);
+    env->CallVoidMethod(nat->me,
+                        method_onConnectSinkResult,
+                        env->NewStringUTF(path),
+                        result);
+    free(user);
+}
+
 #endif
 
 
@@ -244,7 +274,7 @@
     {"initNative", "()Z", (void *)initNative},
     {"cleanupNative", "()V", (void *)cleanupNative},
 
-    /* Bluez audio 4.40 API */
+    /* Bluez audio 4.47 API */
     {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
     {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
     {"suspendSinkNative", "(Ljava/lang/String;)Z", (void*)suspendSinkNative},
@@ -263,6 +293,8 @@
 #ifdef HAVE_BLUETOOTH
     method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged",
                                           "(Ljava/lang/String;[Ljava/lang/String;)V");
+    method_onConnectSinkResult = env->GetMethodID(clazz, "onConnectSinkResult",
+                                                         "(Ljava/lang/String;Z)V");
 #endif
 
     return AndroidRuntime::registerNativeMethods(env,