new class AudioRouter manages audio routing for the phone call

This CL only has support between bluetooth/earpiece

Of Note:
- New shared class AudioMode defines different modes for audio routing
- New class AudioRouter manages between EARPIECE and Bluetooth modes.
- Add function in CallCommandService and CallHandlerService for audio
  mode

Change-Id: I52ff70e53868c45e5202b757cc80a13af3abe5f8
diff --git a/src/com/android/phone/AudioRouter.java b/src/com/android/phone/AudioRouter.java
new file mode 100644
index 0000000..2b8201c
--- /dev/null
+++ b/src/com/android/phone/AudioRouter.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import com.google.common.collect.Lists;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.phone.BluetoothManager.BluetoothIndicatorListener;
+import com.android.services.telephony.common.AudioMode;
+
+import java.util.List;
+
+/**
+ * Responsible for Routing in-call audio and maintaining routing state.
+ */
+/* package */ class AudioRouter implements BluetoothIndicatorListener {
+
+    private static String LOG_TAG = AudioRouter.class.getSimpleName();
+    private static final boolean DBG =
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
+
+    private final Context mContext;
+    private final BluetoothManager mBluetoothManager;
+    private final List<AudioModeListener> mListeners = Lists.newArrayList();
+    private int mAudioMode = AudioMode.EARPIECE;
+    private int mPreviousMode = AudioMode.EARPIECE;
+
+    public AudioRouter(Context context, BluetoothManager bluetoothManager) {
+        mContext = context;
+        mBluetoothManager = bluetoothManager;
+
+        init();
+    }
+
+    /**
+     * Return the current audio mode.
+     */
+    public int getAudioMode() {
+        return mAudioMode;
+    }
+
+    /**
+     * Add a listener to audio mode changes.
+     */
+    public void addAudioModeListener(AudioModeListener listener) {
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove  listener.
+     */
+    public void removeAudioModeListener(AudioModeListener listener) {
+        if (mListeners.contains(listener)) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Sets the audio mode to the mode that is passed in.
+     */
+    public void setAudioMode(int mode) {
+        if (AudioMode.BLUETOOTH == mode) {
+
+            // dont set mAudioMode because we will get a notificaiton through
+            // onBluetoothIndicationChange if successful
+            toggleBluetooth(true);
+        } else if (AudioMode.EARPIECE == mode) {
+            toggleBluetooth(false);
+        }
+    }
+
+    /**
+     * Called when the bluetooth connection changes.
+     * We adjust the audio mode according to the state we receive.
+     */
+    @Override
+    public void onBluetoothIndicationChange(boolean isConnected, BluetoothManager btManager) {
+        int newMode = mAudioMode;
+
+        if (isConnected) {
+            newMode = AudioMode.BLUETOOTH;
+        } else {
+            newMode = AudioMode.EARPIECE;
+        }
+
+        changeAudioModeTo(newMode);
+    }
+
+    private void toggleBluetooth(boolean on) {
+        if (on) {
+            mBluetoothManager.connectBluetoothAudio();
+        } else {
+            mBluetoothManager.disconnectBluetoothAudio();
+        }
+    }
+
+    private void init() {
+        mBluetoothManager.addBluetoothIndicatorListener(this);
+    }
+
+    private void changeAudioModeTo(int mode) {
+        if (mAudioMode != mode) {
+            Log.i(LOG_TAG, "Audio mode changing to " + AudioMode.toString(mode));
+
+            mPreviousMode = mAudioMode;
+            mAudioMode = mode;
+
+            notifyListeners();
+        }
+    }
+
+    private void notifyListeners() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAudioModeChange(mPreviousMode, mAudioMode);
+        }
+    }
+
+    public interface AudioModeListener {
+        void onAudioModeChange(int previousMode, int newMode);
+    }
+}
diff --git a/src/com/android/phone/BluetoothManager.java b/src/com/android/phone/BluetoothManager.java
index a297472..8d20c25 100644
--- a/src/com/android/phone/BluetoothManager.java
+++ b/src/com/android/phone/BluetoothManager.java
@@ -221,12 +221,18 @@
         notifyListeners(mShowBluetoothIndication);
     }
 
-    /* package */ void addBluetoothIndicatorListener(BluetoothIndicatorListener listener) {
+    public void addBluetoothIndicatorListener(BluetoothIndicatorListener listener) {
         if (!mListeners.contains(listener)) {
             mListeners.add(listener);
         }
     }
 
+    public void removeBluetoothIndicatorListener(BluetoothIndicatorListener listener) {
+        if (mListeners.contains(listener)) {
+            mListeners.remove(listener);
+        }
+    }
+
     private void notifyListeners(boolean showBluetoothOn) {
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onBluetoothIndicationChange(showBluetoothOn, this);
@@ -396,6 +402,6 @@
     }
 
     /* package */ interface BluetoothIndicatorListener {
-        public void onBluetoothIndicationChange(boolean showAsConnected, BluetoothManager manager);
+        public void onBluetoothIndicationChange(boolean isConnected, BluetoothManager manager);
     }
 }
diff --git a/src/com/android/phone/CallCommandService.java b/src/com/android/phone/CallCommandService.java
index 560e78c..35c507a 100644
--- a/src/com/android/phone/CallCommandService.java
+++ b/src/com/android/phone/CallCommandService.java
@@ -21,6 +21,7 @@
 
 import com.android.internal.telephony.CallManager;
 import com.android.phone.CallModeler.CallResult;
+import com.android.services.telephony.common.AudioMode;
 import com.android.services.telephony.common.Call;
 import com.android.services.telephony.common.ICallCommandService;
 
@@ -36,13 +37,15 @@
     private final CallManager mCallManager;
     private final CallModeler mCallModeler;
     private final DTMFTonePlayer mDtmfTonePlayer;
+    private final AudioRouter mAudioRouter;
 
     public CallCommandService(Context context, CallManager callManager, CallModeler callModeler,
-            DTMFTonePlayer dtmfTonePlayer) {
+            DTMFTonePlayer dtmfTonePlayer, AudioRouter audioRouter) {
         mContext = context;
         mCallManager = callManager;
         mCallModeler = callModeler;
         mDtmfTonePlayer = dtmfTonePlayer;
+        mAudioRouter = audioRouter;
     }
 
     /**
@@ -110,7 +113,8 @@
     @Override
     public void mute(boolean onOff) {
         try {
-            PhoneUtils.setMute(onOff);
+            //PhoneUtils.setMute(onOff);
+            mAudioRouter.setAudioMode(onOff ? AudioMode.BLUETOOTH : AudioMode.EARPIECE);
         } catch (Exception e) {
             Log.e(TAG, "Error during mute().", e);
         }
@@ -143,4 +147,13 @@
             Log.e(TAG, "Error stopping DTMF tone.", e);
         }
     }
+
+    @Override
+    public void setAudioMode(int mode) {
+        try {
+            mAudioRouter.setAudioMode(mode);
+        } catch (Exception e) {
+            Log.e(TAG, "Error setting the audio mode.", e);
+        }
+    }
 }
diff --git a/src/com/android/phone/CallHandlerServiceProxy.java b/src/com/android/phone/CallHandlerServiceProxy.java
index b134310..2762c98 100644
--- a/src/com/android/phone/CallHandlerServiceProxy.java
+++ b/src/com/android/phone/CallHandlerServiceProxy.java
@@ -28,6 +28,8 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import com.android.phone.AudioRouter.AudioModeListener;
+import com.android.services.telephony.common.AudioMode;
 import com.android.services.telephony.common.Call;
 import com.android.services.telephony.common.ICallHandlerService;
 import com.android.services.telephony.common.ICallCommandService;
@@ -37,7 +39,8 @@
 /**
  * This class is responsible for passing through call state changes to the CallHandlerService.
  */
-public class CallHandlerServiceProxy extends Handler implements CallModeler.Listener {
+public class CallHandlerServiceProxy extends Handler implements CallModeler.Listener,
+        AudioModeListener {
 
     private static final String TAG = CallHandlerServiceProxy.class.getSimpleName();
     private static final boolean DBG =
@@ -85,6 +88,21 @@
         }
     }
 
+    @Override
+    public void onAudioModeChange(int previousMode, int newMode) {
+        // Just do a simple log for now.
+        Log.i(TAG, "Updating with new audio mode: " + AudioMode.toString(newMode) +
+                " from " + AudioMode.toString(previousMode));
+
+        if (mCallHandlerService != null) {
+            try {
+                mCallHandlerService.onAudioModeChange(newMode);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception handling onAudioModeChange", e);
+            }
+        }
+    }
+
     /**
      * Sets up the connection with ICallHandlerService
      */
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 9db596b..914db15 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -169,6 +169,7 @@
     Phone phone;
     PhoneInterfaceManager phoneMgr;
 
+    private AudioRouter audioRouter;
     private BluetoothManager bluetoothManager;
     private CallCommandService callCommandService;
     private CallHandlerServiceProxy callHandlerServiceProxy;
@@ -550,8 +551,12 @@
             // Plays DTMF Tones
             dtmfTonePlayer = new DTMFTonePlayer(mCM, callModeler);
 
+            // Audio router
+            audioRouter = new AudioRouter(this, bluetoothManager);
+
             // Service used by in-call UI to control calls
-            callCommandService = new CallCommandService(this, mCM, callModeler, dtmfTonePlayer);
+            callCommandService = new CallCommandService(this, mCM, callModeler, dtmfTonePlayer,
+                    audioRouter);
 
             // Sends call state to the UI
             callHandlerServiceProxy = new CallHandlerServiceProxy(this, callModeler,