Teleca 2b changes.
[android/platform/packages/apps/Phone.git] / src / com / android / phone / BluetoothHandsfree.java
index ac56f89..5780d4a 100644 (file)
@@ -20,6 +20,8 @@ import android.bluetooth.AtCommandHandler;
 import android.bluetooth.AtCommandResult;
 import android.bluetooth.AtParser;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothIntent;
 import android.bluetooth.HeadsetBase;
 import android.bluetooth.ScoSocket;
 import android.content.ActivityNotFoundException;
@@ -38,6 +40,7 @@ import android.os.PowerManager.WakeLock;
 import android.os.SystemProperties;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.util.Log;
 
 import com.android.internal.telephony.Call;
@@ -59,8 +62,8 @@ public class BluetoothHandsfree {
     public static final int TYPE_HEADSET           = 1;
     public static final int TYPE_HANDSFREE         = 2;
 
-    private Context mContext;
-    private Phone mPhone;
+    private final Context mContext;
+    private final Phone mPhone;
     private ServiceState mServiceState;
     private HeadsetBase mHeadset;  // null when not connected
     private int mHeadsetType;
@@ -108,27 +111,23 @@ public class BluetoothHandsfree {
     private int mLocalBrsf = 0;
 
     /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */
-    public static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
-    public static final int BRSF_AG_EC_NR = 1 << 1;
-    public static final int BRSF_AG_VOICE_RECOG = 1 << 2;
-    public static final int BRSF_AG_IN_BAND_RING = 1 << 3;
-    public static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
-    public static final int BRSF_AG_REJECT_CALL = 1 << 5;
-    public static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
-    public static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
-    public static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
-    // 9 - 31 reserved for future use.
-
-    public static final int BRSF_HF_EC_NR = 1 << 0;
-    public static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
-    public static final int BRSF_HF_CLIP = 1 << 2;
-    public static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
-    public static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
-    public static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
-    public static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
-    // 7 - 31 reserved for future use.
-
-    // Currently supported attributes.
+    private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
+    private static final int BRSF_AG_EC_NR = 1 << 1;
+    private static final int BRSF_AG_VOICE_RECOG = 1 << 2;
+    private static final int BRSF_AG_IN_BAND_RING = 1 << 3;
+    private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
+    private static final int BRSF_AG_REJECT_CALL = 1 << 5;
+    private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
+    private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
+    private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
+
+    private static final int BRSF_HF_EC_NR = 1 << 0;
+    private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
+    private static final int BRSF_HF_CLIP = 1 << 2;
+    private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
+    private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
+    private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
+    private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
 
     public static String typeToString(int type) {
         switch (type) {
@@ -162,15 +161,13 @@ public class BluetoothHandsfree {
                      BRSF_AG_EC_NR |
                      BRSF_AG_REJECT_CALL |
                      BRSF_AG_ENHANCED_CALL_STATUS;
-       
+
         if (sVoiceCommandIntent == null) {
             sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
             sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            sVoiceCommandIntent.putExtra(Intent.EXTRA_AUDIO_ROUTE,
-                                         AudioManager.ROUTE_BLUETOOTH_SCO);
         }
-        
-        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null) {
+        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null &&
+                !BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
             mLocalBrsf |= BRSF_AG_VOICE_RECOG;
         }
 
@@ -203,6 +200,7 @@ public class BluetoothHandsfree {
     /* package */ synchronized void onBluetoothDisabled() {
         if (mConnectedSco != null) {
             mAudioManager.setBluetoothScoOn(false);
+            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
             mConnectedSco.close();
             mConnectedSco = null;
         }
@@ -358,7 +356,7 @@ public class BluetoothHandsfree {
             updatePhoneState(false, null);
             mBattchg = 5;  // There is currently no API to get battery level
                            // on demand, so set to 5 and wait for an update
-            mSignal = asuToSignal(mPhone.getSignalStrengthASU());
+            mSignal = asuToSignal(mPhone.getSignalStrength());
 
             // register for updates
             mPhone.registerForServiceStateChanged(mStateChangeHandler,
@@ -370,6 +368,18 @@ public class BluetoothHandsfree {
             mContext.registerReceiver(mStateReceiver, filter);
         }
 
+        private void updateBtPhoneStateAfterRadioTechnologyChange() {
+            if(DBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
+
+            //Unregister all events from the old obsolete phone
+            mPhone.unregisterForServiceStateChanged(mStateChangeHandler);
+            mPhone.unregisterForPhoneStateChanged(mStateChangeHandler);
+
+            //Register all events new to the new active phone
+            mPhone.registerForServiceStateChanged(mStateChangeHandler, SERVICE_STATE_CHANGED, null);
+            mPhone.registerForPhoneStateChanged(mStateChangeHandler, PHONE_STATE_CHANGED, null);
+        }
+
         private boolean sendUpdate() {
             return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled;
         }
@@ -381,7 +391,7 @@ public class BluetoothHandsfree {
         /* convert [0,31] ASU signal strength to the [0,5] expected by
          * bluetooth devices. Scale is similar to status bar policy
          */
-        private int asuToSignal(int asu) {
+        private int gsmAsuToSignal(int asu) {
             if      (asu >= 16) return 5;
             else if (asu >= 8)  return 4;
             else if (asu >= 4)  return 3;
@@ -390,6 +400,28 @@ public class BluetoothHandsfree {
             else                return 0;
         }
 
+        /* convert cdma dBm signal strength to the [0,5] expected by
+         * bluetooth devices. Scale is similar to status bar policy
+         */
+        private int cdmaDbmToSignal(int cdmaDbm) {
+            if (cdmaDbm >= -75)       return 5;
+            else if (cdmaDbm >= -85)  return 4;
+            else if (cdmaDbm >= -95)  return 3;
+            else if (cdmaDbm >= -100) return 2;
+            else if (cdmaDbm >= -105) return 2;
+            else return 0;
+        }
+
+
+        private int asuToSignal(SignalStrength signalStrength) {
+            if (!signalStrength.isGsm()) {
+                return gsmAsuToSignal(signalStrength.getCdmaDbm());
+            } else {
+                return cdmaDbmToSignal(signalStrength.getGsmSignalStrength());
+            }
+        }
+
+
         /* convert [0,5] signal strength to a rssi signal strength for CSQ
          * which is [0,31]. Despite the same scale, this is not the same value
          * as ASU.
@@ -435,14 +467,22 @@ public class BluetoothHandsfree {
         }
 
         private synchronized void updateSignalState(Intent intent) {
+            // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent
+            // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread
+            SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras());
             int signal;
-            signal = asuToSignal(intent.getIntExtra("asu", -1));
-            mRssi = signalToRssi(signal);  // no unsolicited CSQ
-            if (signal != mSignal) {
-                mSignal = signal;
-                if (sendUpdate()) {
-                    sendURC("+CIEV: 5," + mSignal);
+
+            if (signalStrength != null) {
+                signal = asuToSignal(signalStrength);
+                mRssi = signalToRssi(signal);  // no unsolicited CSQ
+                if (signal != mSignal) {
+                    mSignal = signal;
+                    if (sendUpdate()) {
+                        sendURC("+CIEV: 5," + mSignal);
+                    }
                 }
+            } else {
+                Log.e(TAG, "Signal Strength null");
             }
         }
 
@@ -549,9 +589,14 @@ public class BluetoothHandsfree {
             if (mCallsetup != callsetup) {
                 mCallsetup = callsetup;
                 if (sendUpdate) {
-                    // don't send +CIEV for callsetup while in-call if 3way not supported
-                    if (!(mCall == 1 && mCallsetup != 0 &&
-                         (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) == 0x0)) {
+                    // If mCall = 0, send CIEV
+                    // mCall = 1, mCallsetup = 0, send CIEV
+                    // mCall = 1, mCallsetup = 1, send CIEV after CCWA,
+                    // if 3 way supported.
+                    // mCall = 1, mCallsetup = 2 / 3 -> send CIEV,
+                    // if 3 way is supported
+                    if (mCall != 1 || mCallsetup == 0 ||
+                        mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
                         result.addResponse("+CIEV: 3," + mCallsetup);
                     }
                 }
@@ -595,6 +640,7 @@ public class BluetoothHandsfree {
                     // call waiting
                     if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
                         result.addResponse("+CCWA: \"" + number + "\"," + type);
+                        result.addResponse("+CIEV: 3," + callsetup);
                     }
                 } else {
                     // regular new incoming call
@@ -679,6 +725,7 @@ public class BluetoothHandsfree {
                         Log.i(TAG, "Routing audio for incoming SCO connection");
                         mConnectedSco = (ScoSocket)msg.obj;
                         mAudioManager.setBluetoothScoOn(true);
+                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED);
                     } else {
                         Log.i(TAG, "Rejecting incoming SCO connection");
                         ((ScoSocket)msg.obj).close();
@@ -693,6 +740,7 @@ public class BluetoothHandsfree {
                     if (DBG) log("Routing audio for outgoing SCO conection");
                     mConnectedSco = (ScoSocket)msg.obj;
                     mAudioManager.setBluetoothScoOn(true);
+                    broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED);
                 } else if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
                     if (DBG) log("Rejecting new connected outgoing SCO socket");
                     ((ScoSocket)msg.obj).close();
@@ -704,6 +752,7 @@ public class BluetoothHandsfree {
                 if (mConnectedSco == (ScoSocket)msg.obj) {
                     mConnectedSco = null;
                     mAudioManager.setBluetoothScoOn(false);
+                    broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
                 } else if (mOutgoingSco == (ScoSocket)msg.obj) {
                     mOutgoingSco = null;
                 } else if (mIncomingSco == (ScoSocket)msg.obj) {
@@ -735,6 +784,25 @@ public class BluetoothHandsfree {
         return new ScoSocket(mPowerManager, mHandler, SCO_ACCEPTED, SCO_CONNECTED, SCO_CLOSED);
     }
 
+    private void broadcastAudioStateIntent(int state) {
+        if (VDBG) log("broadcastAudioStateIntent(" + state + ")");
+        Intent intent = new Intent(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION);
+        intent.putExtra(BluetoothIntent.HEADSET_AUDIO_STATE, state);
+        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
+    }
+
+
+    void updateBtHandsfreeAfterRadioTechnologyChange() {
+        if(DBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
+
+        //Get the Call references from the new active phone again
+        mRingingCall = mPhone.getRingingCall();
+        mForegroundCall = mPhone.getForegroundCall();
+        mBackgroundCall = mPhone.getBackgroundCall();
+
+        mPhoneState.updateBtPhoneStateAfterRadioTechnologyChange();
+    }
+
     /** Request to establish SCO (audio) connection to bluetooth
      * headset/handsfree, if one is connected. Does not block.
      * Returns false if the user has requested audio off, or if there
@@ -794,6 +862,7 @@ public class BluetoothHandsfree {
 
         if (mConnectedSco != null) {
             mAudioManager.setBluetoothScoOn(false);
+            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
             mConnectedSco.close();
             mConnectedSco = null;
         }
@@ -1472,6 +1541,9 @@ public class BluetoothHandsfree {
         parser.register("+BVRA", new AtCommandHandler() {
             @Override
             public AtCommandResult handleSetCommand(Object[] args) {
+                if (BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
+                    return new AtCommandResult(AtCommandResult.ERROR);
+                }
                 if (args.length >= 1 && args[0].equals(1)) {
                     synchronized (BluetoothHandsfree.this) {
                         if (!mWaitingForVoiceRecognition) {
@@ -1492,7 +1564,7 @@ public class BluetoothHandsfree {
             }
             @Override
             public AtCommandResult handleTestCommand() {
-                return new AtCommandResult("+CLIP: (0-1)");
+                return new AtCommandResult("+BVRA: (0-1)");
             }
         });
 
@@ -1733,8 +1805,12 @@ public class BluetoothHandsfree {
 
                 int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1);
                 if (signalLevel >= 0 && signalLevel <= 31) {
+                    SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1,
+                            -1, -1, -1, true);
                     Intent intent = new Intent();
-                    intent.putExtra("asu", signalLevel);
+                    Bundle data = new Bundle();
+                    signalStrength.fillInNotifierBundle(data);
+                    intent.putExtras(data);
                     mPhoneState.updateSignalState(intent);
                 }
 
@@ -1763,3 +1839,6 @@ public class BluetoothHandsfree {
         Log.d(TAG, msg);
     }
 }
+
+
+