Move BluetoothManager to telecomm.

Copy over bluetooth manager from teleservice and add usage in
CallAudioManager (for audio routing), Ringer (ringtone routing),
InCallTonePlayer (tone routing).

Change-Id: I015961aebf42389a7f4cf3a5f89ec194d6ca64e2
Bug: 13242863
diff --git a/src/com/android/telecomm/CallAudioManager.java b/src/com/android/telecomm/CallAudioManager.java
index d9ff8a5..fb8ed9e 100644
--- a/src/com/android/telecomm/CallAudioManager.java
+++ b/src/com/android/telecomm/CallAudioManager.java
@@ -31,6 +31,7 @@
 
     private final AudioManager mAudioManager;
     private final WiredHeadsetManager mWiredHeadsetManager;
+    private final BluetoothManager mBluetoothManager;
     private CallAudioState mAudioState;
     private int mAudioFocusStreamType;
     private boolean mIsRinging;
@@ -41,7 +42,8 @@
         Context context = TelecommApp.getInstance();
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mWiredHeadsetManager = new WiredHeadsetManager(this);
-        mAudioState = getInitialAudioState();
+        mBluetoothManager = new BluetoothManager(context, this);
+        mAudioState = getInitialAudioState(null);
         mAudioFocusStreamType = STREAM_NONE;
     }
 
@@ -54,7 +56,7 @@
         updateAudioStreamAndMode();
         if (CallsManager.getInstance().getCalls().size() == 1) {
             Log.v(this, "first call added, reseting system audio to default state");
-            setInitialAudioState();
+            setInitialAudioState(call);
         } else if (!call.isIncoming()) {
             // Unmute new outgoing call.
             setSystemAudioState(false, mAudioState.route, mAudioState.supportedRouteMask);
@@ -65,7 +67,7 @@
     public void onCallRemoved(Call call) {
         if (CallsManager.getInstance().getCalls().isEmpty()) {
             Log.v(this, "all calls removed, reseting system audio to default state");
-            setInitialAudioState();
+            setInitialAudioState(null);
         }
         updateAudioStreamAndMode();
     }
@@ -77,8 +79,18 @@
 
     @Override
     public void onIncomingCallAnswered(Call call) {
-        // Unmute new incoming call.
-        setSystemAudioState(false, mAudioState.route, mAudioState.supportedRouteMask);
+        int route = mAudioState.route;
+
+        // We do two things:
+        // (1) If this is the first call, then we can to turn on bluetooth if available.
+        // (2) Unmute the audio for the new incoming call.
+        boolean isOnlyCall = CallsManager.getInstance().getCalls().size() == 1;
+        if (isOnlyCall && mBluetoothManager.isBluetoothAvailable()) {
+            mBluetoothManager.connectBluetoothAudio();
+            route = CallAudioState.ROUTE_BLUETOOTH;
+        }
+
+        setSystemAudioState(false /* isMute */, route, mAudioState.supportedRouteMask);
     }
 
     @Override
@@ -170,6 +182,30 @@
         setSystemAudioState(mAudioState.isMuted, newRoute, calculateSupportedRoutes());
     }
 
+    /**
+     * Updates the audio routing according to the bluetooth state.
+     */
+    void onBluetoothStateChange(BluetoothManager bluetoothManager) {
+        int newRoute = mAudioState.route;
+        if (bluetoothManager.isBluetoothAudioConnectedOrPending()) {
+            newRoute = CallAudioState.ROUTE_BLUETOOTH;
+        } else if (mAudioState.route == CallAudioState.ROUTE_BLUETOOTH) {
+            newRoute = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
+            // Do not switch to speaker when bluetooth disconnects.
+            mWasSpeakerOn = false;
+        }
+
+        setSystemAudioState(mAudioState.isMuted, newRoute, calculateSupportedRoutes());
+    }
+
+    boolean isBluetoothAudioOn() {
+        return mBluetoothManager.isBluetoothAudioConnected();
+    }
+
+    boolean isBluetoothDeviceAvailable() {
+        return mBluetoothManager.isBluetoothAvailable();
+    }
+
     private void setSystemAudioState(boolean isMuted, int route, int supportedRouteMask) {
         CallAudioState oldAudioState = mAudioState;
         mAudioState = new CallAudioState(isMuted, route, supportedRouteMask);
@@ -182,18 +218,16 @@
         }
 
         // Audio route.
-        if (mAudioState.route == CallAudioState.ROUTE_SPEAKER) {
-            if (!mAudioManager.isSpeakerphoneOn()) {
-                Log.i(this, "turning speaker phone on");
-                mAudioManager.setSpeakerphoneOn(true);
-            }
+        if (mAudioState.route == CallAudioState.ROUTE_BLUETOOTH) {
+            turnOnSpeaker(false);
+            turnOnBluetooth(true);
+        } else if (mAudioState.route == CallAudioState.ROUTE_SPEAKER) {
+            turnOnBluetooth(false);
+            turnOnSpeaker(true);
         } else if (mAudioState.route == CallAudioState.ROUTE_EARPIECE ||
                 mAudioState.route == CallAudioState.ROUTE_WIRED_HEADSET) {
-            // Wired headset and earpiece work the same way
-            if (mAudioManager.isSpeakerphoneOn()) {
-                Log.i(this, "turning speaker phone off");
-                mAudioManager.setSpeakerphoneOn(false);
-            }
+            turnOnBluetooth(false);
+            turnOnSpeaker(false);
         }
 
         if (!oldAudioState.equals(mAudioState)) {
@@ -202,6 +236,27 @@
         }
     }
 
+    private void turnOnSpeaker(boolean on) {
+        // Wired headset and earpiece work the same way
+        if (mAudioManager.isSpeakerphoneOn() != on) {
+            Log.i(this, "turning speaker phone off");
+            mAudioManager.setSpeakerphoneOn(on);
+        }
+    }
+
+    private void turnOnBluetooth(boolean on) {
+        if (mBluetoothManager.isBluetoothAvailable()) {
+            boolean isAlreadyOn = mBluetoothManager.isBluetoothAudioConnected();
+            if (on != isAlreadyOn) {
+                if (on) {
+                    mBluetoothManager.connectBluetoothAudio();
+                } else {
+                    mBluetoothManager.disconnectBluetoothAudio();
+                }
+            }
+        }
+    }
+
     private void updateAudioStreamAndMode() {
         Log.v(this, "updateAudioStreamAndMode, mIsRinging: %b, mIsTonePlaying: %b", mIsRinging,
                 mIsTonePlaying);
@@ -286,18 +341,45 @@
             routeMask |= CallAudioState.ROUTE_EARPIECE;
         }
 
+        if (mBluetoothManager.isBluetoothAvailable()) {
+            routeMask |=  CallAudioState.ROUTE_BLUETOOTH;
+        }
+
         return routeMask;
     }
 
-    private CallAudioState getInitialAudioState() {
+    private CallAudioState getInitialAudioState(Call call) {
         int supportedRouteMask = calculateSupportedRoutes();
-        return new CallAudioState(false,
-                selectWiredOrEarpiece(CallAudioState.ROUTE_WIRED_OR_EARPIECE, supportedRouteMask),
-                supportedRouteMask);
+        int route = selectWiredOrEarpiece(
+                CallAudioState.ROUTE_WIRED_OR_EARPIECE, supportedRouteMask);
+
+        // We want the UI to indicate that "bluetooth is in use" in two slightly different cases:
+        // (a) The obvious case: if a bluetooth headset is currently in use for an ongoing call.
+        // (b) The not-so-obvious case: if an incoming call is ringing, and we expect that audio
+        //     *will* be routed to a bluetooth headset once the call is answered. In this case, just
+        //     check if the headset is available. Note this only applies when we are dealing with
+        //     the first call.
+        if (call != null && mBluetoothManager.isBluetoothAvailable()) {
+            switch(call.getState()) {
+                case ACTIVE:
+                case ON_HOLD:
+                    if (mBluetoothManager.isBluetoothAudioConnectedOrPending()) {
+                        route = CallAudioState.ROUTE_BLUETOOTH;
+                    }
+                    break;
+                case RINGING:
+                    route = CallAudioState.ROUTE_BLUETOOTH;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return new CallAudioState(false, route, supportedRouteMask);
     }
 
-    private void setInitialAudioState() {
-        CallAudioState audioState = getInitialAudioState();
+    private void setInitialAudioState(Call call) {
+        CallAudioState audioState = getInitialAudioState(call);
         setSystemAudioState(audioState.isMuted, audioState.route, audioState.supportedRouteMask);
     }