Moved BluetoothAdapter.ACTION_STATE_CHANGED broadcast from AdapterService to BluetoothManagerService

Change-Id: I88e5f3fe050cf11eae9c5cf1b7c393a178b8f9b1
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c08705c..dc18029 100755
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -464,12 +464,15 @@
             synchronized(mManagerCallback) {
                 if (mService != null)
                 {
-                    return mService.getState();
+                    int state=  mService.getState();
+                    if (DBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+                    return state;
                 }
                 // TODO(BT) there might be a small gap during STATE_TURNING_ON that
                 //          mService is null, handle that case
             }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
+        if (DBG) Log.d(TAG, "" + hashCode() + ": getState() :  mService = null. Returning STATE_OFF");
         return STATE_OFF;
     }
 
@@ -1208,7 +1211,7 @@
                 if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
                 synchronized (mManagerCallback) {
                     mService = bluetoothService;
-                    for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
                         try {
                             if (cb != null) {
                                 cb.onBluetoothServiceUp(bluetoothService);
@@ -1224,7 +1227,7 @@
                 if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
                 synchronized (mManagerCallback) {
                     mService = null;
-                    for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
                         try {
                             if (cb != null) {
                                 cb.onBluetoothServiceDown();
@@ -1368,14 +1371,14 @@
             return mManagerService;
     }
 
-    private ArrayList<IBluetoothManagerCallback> mBluetoothManagerCallbackList = new ArrayList<IBluetoothManagerCallback>();
+    private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
 
     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
         synchronized (mManagerCallback) {
             if (cb == null) {
-                Log.w(TAG, "Unable to register null state change callback", new Exception());
-            } else if (!mBluetoothManagerCallbackList.contains(cb)) {
-                mBluetoothManagerCallbackList.add(cb);
+                Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
+            } else if (!mProxyServiceStateCallbacks.contains(cb)) {
+                mProxyServiceStateCallbacks.add(cb);
             }
         }
         return mService;
@@ -1383,7 +1386,7 @@
 
     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
         synchronized (mManagerCallback) {
-            mBluetoothManagerCallbackList.remove(cb);
+            mProxyServiceStateCallbacks.remove(cb);
         }
     }
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 9653de2..eff780d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -72,6 +72,9 @@
 
     void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
 
+    void registerCallback(in IBluetoothCallback callback);
+    void unregisterCallback(in IBluetoothCallback callback);
+
     // For Socket
     ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in ParcelUuid uuid, int port, int flag);
     ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
diff --git a/core/java/android/bluetooth/IBluetoothCallback.aidl b/core/java/android/bluetooth/IBluetoothCallback.aidl
index 8edb3f4..e280978 100644
--- a/core/java/android/bluetooth/IBluetoothCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothCallback.aidl
@@ -23,5 +23,6 @@
  */
 interface IBluetoothCallback
 {
-    void onRfcommChannelFound(int channel);
+    //void onRfcommChannelFound(int channel);
+    void onBluetoothStateChange(int prevState, int newState);
 }
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 3c3b9db..32fddeb 100644
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -6,6 +6,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothCallback;
 import android.bluetooth.IBluetoothManager;
 import android.bluetooth.IBluetoothManagerCallback;
 import android.bluetooth.IBluetoothStateChangeCallback;
@@ -49,8 +50,7 @@
     private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
     private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
     private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
-    private static final int MESSAGE_BLUETOOTH_ON = 50;
-    private static final int MESSAGE_BLUETOOTH_OFF = 51;
+    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
     private static final int MESSAGE_TIMEOUT_BIND =100;
     private static final int MESSAGE_TIMEOUT_UNBIND =101;
     private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
@@ -80,20 +80,19 @@
         }
     }
 
-    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
+        @Override
+        public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
+            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
+            mHandler.sendMessage(msg);
+        }
+    };
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
-                int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
-                if (state == BluetoothAdapter.STATE_OFF) {
-                    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_OFF);
-                    mHandler.sendMessage(msg);
-                } else if (state == BluetoothAdapter.STATE_ON) {
-                    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_ON);
-                    mHandler.sendMessage(msg);
-                }
-            } else if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
+            if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
                 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
                 Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
                 if (newName != null) {
@@ -332,6 +331,14 @@
             if (mUnbinding) return;
             mUnbinding = true;
             if (isConnected()) {
+                if (!mConnection.isGetNameAddressOnly()) {
+                    //Unregister callback object
+                    try {
+                        mBluetooth.unregisterCallback(mBluetoothCallback);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Unable to register BluetoothCallback",re);
+                    }
+                }
                 if (DBG) Log.d(TAG, "Sending unbind request.");
                 mBluetooth = null;
                 //Unbind
@@ -343,7 +350,23 @@
         }
     }
 
-    private void sendBluetoothServiceDownEvent() {
+    private void sendBluetoothStateCallback(boolean isUp) {
+        int n = mStateChangeCallbacks.beginBroadcast();
+        Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
+        for (int i=0; i <n;i++) {
+            try {
+                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+            }
+        }
+        mStateChangeCallbacks.finishBroadcast();
+    }
+
+    /**
+     * Inform BluetoothAdapter instances that Adapter service is down
+     */
+    private void sendBluetoothServiceDownCallback() {
         if (!mConnection.isGetNameAddressOnly()) {
             if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
             int n = mCallbacks.beginBroadcast();
@@ -463,7 +486,7 @@
                             i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
                             i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
                             mContext.startService(i);
-                            sendBluetoothServiceDownEvent();
+                            sendBluetoothServiceDownCallback();
                             unbindAndFinish();
                         } else {
                             if (msg.arg1 < MAX_SAVE_RETRIES) {
@@ -473,7 +496,7 @@
                                 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
                             } else {
                                 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
-                                sendBluetoothServiceDownEvent();
+                                sendBluetoothServiceDownCallback();
                                 unbindAndFinish();
                             }
                         }
@@ -504,11 +527,14 @@
                             //Start bind timeout and bind
                             Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
                             mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
+                            /*
                             Intent i = new Intent(IBluetooth.class.getName());
                             i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
                             i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
                             mContext.startService(i);
+                            */
                             mConnection.setGetNameAddressOnly(false);
+                            Intent i = new Intent(IBluetooth.class.getName());
                             if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
                                 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
                                 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
@@ -603,17 +629,31 @@
                         mHandler.sendMessage(getMsg);
                         return;
                     }
-                        int n = mCallbacks.beginBroadcast();
-                        Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
-                        for (int i=0; i <n;i++) {
-                            try {
-                                mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
-                            }
-                        }
-                        mCallbacks.finishBroadcast();
 
+                    //Register callback object
+                    try {
+                        mBluetooth.registerCallback(mBluetoothCallback);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Unable to register BluetoothCallback",re);
+                    }
+
+                    //Inform BluetoothAdapter instances that service is up
+                    int n = mCallbacks.beginBroadcast();
+                    Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+                    for (int i=0; i <n;i++) {
+                        try {
+                            mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+                        }
+                    }
+                    mCallbacks.finishBroadcast();
+
+                    //Do enable request
+                    Intent i = new Intent(IBluetooth.class.getName());
+                    i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
+                    i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
+                    mContext.startService(i);
                 }
                     break;
                 case MESSAGE_TIMEOUT_BIND: {
@@ -623,42 +663,38 @@
                     }
                 }
                     break;
-                case MESSAGE_BLUETOOTH_ON:
+                case MESSAGE_BLUETOOTH_STATE_CHANGE:
                 {
-                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_ON");
-                    int n = mStateChangeCallbacks.beginBroadcast();
-                    Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
-                    for (int i=0; i <n;i++) {
-                        try {
-                            mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(true);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+                    int prevState = msg.arg1;
+                    int newState = msg.arg2;
+                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
+                    if (prevState != newState) {
+                        //Notify all proxy objects first of adapter state change
+                        if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
+                            boolean isUp = (newState==BluetoothAdapter.STATE_ON);
+                            sendBluetoothStateCallback(isUp);
+
+                            //If Bluetooth is off, send service down event to proxy objects, and unbind
+                            if (!isUp) {
+                                sendBluetoothServiceDownCallback();
+                                unbindAndFinish();
+                            }
                         }
+
+                        //Send broadcast message to everyone else
+                        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+                        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
+                        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
+                        mContext.sendBroadcast(intent,BLUETOOTH_PERM);
                     }
-                    mStateChangeCallbacks.finishBroadcast();
-                }
-                    break;
-                case MESSAGE_BLUETOOTH_OFF:
-                {
-                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_OFF");
-                    int n = mStateChangeCallbacks.beginBroadcast();
-                    Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
-                    for (int i=0; i <n;i++) {
-                        try {
-                            mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(false);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
-                        }
-                    }
-                    mStateChangeCallbacks.finishBroadcast();
-                    sendBluetoothServiceDownEvent();
-                    unbindAndFinish();
                 }
                     break;
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
                     if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
-                    sendBluetoothServiceDownEvent();
+                    sendBluetoothServiceDownCallback();
                 }
                     break;
                 case MESSAGE_TIMEOUT_UNBIND: