1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/* 2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License. 6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at 7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and 14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License. 15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone; 18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 19b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.AtCommandHandler; 20b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.AtCommandResult; 21b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.AtParser; 22f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lanimport android.bluetooth.BluetoothA2dp; 231498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinekimport android.bluetooth.BluetoothAssignedNumbers; 24db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pellyimport android.bluetooth.BluetoothAdapter; 25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.BluetoothDevice; 264079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Projectimport android.bluetooth.BluetoothHeadset; 271d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganeshimport android.bluetooth.BluetoothProfile; 2891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Changimport android.bluetooth.BluetoothServerSocket; 2991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Changimport android.bluetooth.BluetoothSocket; 30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.HeadsetBase; 31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.ActivityNotFoundException; 32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver; 33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context; 34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent; 35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.IntentFilter; 36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager; 37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri; 38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.AsyncResult; 39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle; 40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler; 41d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xieimport android.os.HandlerThread; 42d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xieimport android.os.Looper; 43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message; 44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager; 45b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager.WakeLock; 46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.SystemProperties; 47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils; 48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.ServiceState; 49404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.telephony.SignalStrength; 50b0664bb07d16eef5a0dd70013ffd02ef6db3ebebRobert Greenwaltimport android.telephony.TelephonyManager; 51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log; 52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Call; 54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Connection; 55b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Phone; 56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.TelephonyIntents; 578058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wangimport com.android.internal.telephony.CallManager; 58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 5991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Changimport java.io.IOException; 6091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Changimport java.io.InputStream; 61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.LinkedList; 62f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan 63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/** 64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Bluetooth headset manager for the Phone app. 65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * @hide 66b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 67b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class BluetoothHandsfree { 681d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private static final String TAG = "Bluetooth HS/HF"; 698eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1) 708eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan && (SystemProperties.getInt("ro.debuggable", 0) == 1); 718eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2); // even more logging 72b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public static final int TYPE_UNKNOWN = 0; 74b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public static final int TYPE_HEADSET = 1; 75b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public static final int TYPE_HANDSFREE = 2; 76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 77f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown /** The singleton instance. */ 78f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown private static BluetoothHandsfree sInstance; 79f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown 804079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project private final Context mContext; 8191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private final BluetoothAdapter mAdapter; 828058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang private final CallManager mCM; 831d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private BluetoothA2dp mA2dp; 84f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan 85f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan private BluetoothDevice mA2dpDevice; 86f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan private int mA2dpState; 871d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private boolean mPendingAudioState; 881d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private int mAudioState; 89f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan 90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private ServiceState mServiceState; 9190eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie private HeadsetBase mHeadset; 921d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private BluetoothHeadset mBluetoothHeadset; 9390eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie private int mHeadsetType; // TYPE_UNKNOWN when not connected 94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mAudioPossible; 9591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private BluetoothSocket mConnectedSco; 9691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 9791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private IncomingScoAcceptThread mIncomingScoThread = null; 9891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private ScoSocketConnectThread mConnectScoThread = null; 9991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private SignalScoCloseThread mSignalScoCloseThread = null; 100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private AudioManager mAudioManager; 102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private PowerManager mPowerManager; 103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 104f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan private boolean mPendingSco; // waiting for a2dp sink to suspend before establishing SCO 105ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent private boolean mA2dpSuspended; 106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mUserWantsAudio; 107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private WakeLock mStartCallWakeLock; // held while waiting for the intent to start call 108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private WakeLock mStartVoiceRecognitionWakeLock; // held while waiting for voice recognition 109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT command state 111c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private static final int GSM_MAX_CONNECTIONS = 6; // Max connections allowed by GSM 112c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private static final int CDMA_MAX_CONNECTIONS = 2; // Max connections allowed by CDMA 113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private long mBgndEarliestConnectionTime = 0; 115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mClip = false; // Calling Line Information Presentation 116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mIndicatorsEnabled = false; 117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mCmee = false; // Extended Error reporting 118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private long[] mClccTimestamps; // Timestamps associated with each clcc index 119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean[] mClccUsed; // Is this clcc index in use 120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mWaitingForCallStart; 121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mWaitingForVoiceRecognition; 1220966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly // do not connect audio until service connection is established 1230966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly // for 3-way supported devices, this is after AT+CHLD 1240966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly // for non-3-way supported devices, this is after AT+CMER (see spec) 1250966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly private boolean mServiceConnectionEstablished; 126db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly 1271dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh private final BluetoothPhoneState mBluetoothPhoneState; // for CIND and CIEV updates 128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final BluetoothAtPhonebook mPhonebook; 1291dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh private Phone.State mPhoneState = Phone.State.IDLE; 130487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState mCdmaThreeWayCallState = 131487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState.IDLE; 132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private DebugThread mDebugThread; 134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mScoGain = Integer.MIN_VALUE; 135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static Intent sVoiceCommandIntent; 137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Audio parameters 139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String HEADSET_NREC = "bt_headset_nrec"; 140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String HEADSET_NAME = "bt_headset_name"; 141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mRemoteBrsf = 0; 143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mLocalBrsf = 0; 144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 145c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // CDMA specific flag used in context with BT devices having display capabilities 146c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // to show which Caller is active. This state might not be always true as in CDMA 147c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // networks if a caller drops off no update is provided to the Phone. 148c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // This flag is just used as a toggle to provide a update to the BT device to specify 149c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // which caller is active. 150c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private boolean mCdmaIsSecondCallActive = false; 15191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh private boolean mCdmaCallsSwapped = false; 152c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */ 1546967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0; 1556967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_EC_NR = 1 << 1; 1566967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_VOICE_RECOG = 1 << 2; 1576967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_IN_BAND_RING = 1 << 3; 1586967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4; 1596967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_REJECT_CALL = 1 << 5; 1606967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 << 6; 1616967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7; 1626967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8; 1636967e2d953bc077c99c4831946201f3d333b833fNick Pelly 1646967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_EC_NR = 1 << 0; 1656967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1; 1666967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_CLIP = 1 << 2; 1676967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3; 1686967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4; 1696967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 << 5; 1706967e2d953bc077c99c4831946201f3d333b833fNick Pelly private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6; 171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 172b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // VirtualCall - true if Virtual Call is active, false otherwise 173b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh private boolean mVirtualCallStarted = false; 174b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 1751c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent // Voice Recognition - true if Voice Recognition is active, false otherwise 1761c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent private boolean mVoiceRecognitionStarted; 1771c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 178d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie private HandsfreeMessageHandler mHandler; 1791c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public static String typeToString(int type) { 181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (type) { 182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case TYPE_UNKNOWN: 183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return "unknown"; 184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case TYPE_HEADSET: 185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return "headset"; 186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case TYPE_HANDSFREE: 187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return "handsfree"; 188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return null; 190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 192f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown /** 193f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown * Initialize the singleton BluetoothHandsfree instance. 194f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown * This is only done once, at startup, from PhoneApp.onCreate(). 195f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown */ 196f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown /* package */ static BluetoothHandsfree init(Context context, CallManager cm) { 197f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown synchronized (BluetoothHandsfree.class) { 198f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown if (sInstance == null) { 199f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown sInstance = new BluetoothHandsfree(context, cm); 200f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown } else { 201f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance); 202f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown } 203f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown return sInstance; 204f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown } 205f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown } 206f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown 207f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown /** Private constructor; @see init() */ 208f0c4d0e94b7fa915bcfacd28ee432f8b3846511aDavid Brown private BluetoothHandsfree(Context context, CallManager cm) { 2098058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM = cm; 210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mContext = context; 21191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mAdapter = BluetoothAdapter.getDefaultAdapter(); 21291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang boolean bluetoothCapable = (mAdapter != null); 21390eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mHeadset = null; 21490eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mHeadsetType = TYPE_UNKNOWN; // nothing connected yet 2151d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (bluetoothCapable) { 2161d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mAdapter.getProfileProxy(mContext, mProfileListener, 2171d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothProfile.A2DP); 2181d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 219f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mA2dpState = BluetoothA2dp.STATE_DISCONNECTED; 220f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mA2dpDevice = null; 221ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mA2dpSuspended = false; 222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project TAG + ":StartCall"); 226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartCallWakeLock.setReferenceCounted(false); 227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartVoiceRecognitionWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project TAG + ":VoiceRecognition"); 229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartVoiceRecognitionWakeLock.setReferenceCounted(false); 230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mLocalBrsf = BRSF_AG_THREE_WAY_CALLING | 232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project BRSF_AG_EC_NR | 233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project BRSF_AG_REJECT_CALL | 234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project BRSF_AG_ENHANCED_CALL_STATUS; 2354b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project 236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sVoiceCommandIntent == null) { 237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND); 238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2406967e2d953bc077c99c4831946201f3d333b833fNick Pelly if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null && 241b8dbab241df3aa3487c1bdb488fd4e0b694d2d9aEric Laurent BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) { 242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mLocalBrsf |= BRSF_AG_VOICE_RECOG; 243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 245d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie HandlerThread thread = new HandlerThread("BluetoothHandsfreeHandler"); 246d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie thread.start(); 247d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie Looper looper = thread.getLooper(); 248d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie mHandler = new HandsfreeMessageHandler(looper); 2491dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState = new BluetoothPhoneState(); 250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mUserWantsAudio = true; 251b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mVirtualCallStarted = false; 2521c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent mVoiceRecognitionStarted = false; 253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mPhonebook = new BluetoothAtPhonebook(mContext, this); 254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 255c9d9ed30aa547b79b81adc13a4d148a003b6ee62w cdmaSetSecondCallState(false); 256f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh 257f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh if (bluetoothCapable) { 258f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh resetAtState(); 259f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh } 260f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh 261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 26391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang /** 26491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * A thread that runs in the background waiting for a Sco Server Socket to 26591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * accept a connection. Even after a connection has been accepted, the Sco Server 26691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * continues to listen for new connections. 26791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang */ 26891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private class IncomingScoAcceptThread extends Thread{ 26991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private final BluetoothServerSocket mIncomingServerSocket; 27091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private BluetoothSocket mIncomingSco; 27191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private boolean stopped = false; 27291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 27391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang public IncomingScoAcceptThread() { 27491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang BluetoothServerSocket serverSocket = null; 27591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 27691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang serverSocket = BluetoothAdapter.listenUsingScoOn(); 27791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) { 27891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.e(TAG, "Could not create BluetoothServerSocket"); 27991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang stopped = true; 28091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 28191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingServerSocket = serverSocket; 28291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 28391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 28491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang @Override 28591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang public void run() { 28691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang while (!stopped) { 28791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 28891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingSco = mIncomingServerSocket.accept(); 28991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) { 29091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.e(TAG, "BluetoothServerSocket could not accept connection"); 29191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 29291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 29391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mIncomingSco != null) { 294912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh connectSco(); 295912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 296912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 297912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 298912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 299912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private void connectSco() { 300e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent synchronized (BluetoothHandsfree.this) { 301e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent if (!Thread.interrupted() && isHeadsetConnected() && 302e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent (mAudioPossible || allowAudioAnytime()) && 303912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mConnectedSco == null) { 304912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh Log.i(TAG, "Routing audio for incoming SCO connection"); 305912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mConnectedSco = mIncomingSco; 306912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mAudioManager.setBluetoothScoOn(true); 307912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTED, 308912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mHeadset.getRemoteDevice()); 309912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 310912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (mSignalScoCloseThread == null) { 311912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread = new SignalScoCloseThread(); 312912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread.setName("SignalScoCloseThread"); 313912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread.start(); 314912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 315912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } else { 316912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh Log.i(TAG, "Rejecting incoming SCO connection"); 317912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh try { 318912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mIncomingSco.close(); 319912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh }catch (IOException e) { 320912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh Log.e(TAG, "Error when closing incoming Sco socket"); 32191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 322912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mIncomingSco = null; 32391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 32491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 32591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 32691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 327e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent // must be called with BluetoothHandsfree locked 32891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang void shutdown() { 32991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 33091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingServerSocket.close(); 33191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) { 33291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.w(TAG, "Error when closing server socket"); 33391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 334e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent stopped = true; 335e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent interrupt(); 33691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 33791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 33891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 33991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang /** 34091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * A thread that runs in the background waiting for a Sco Socket to 34191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * connect.Once the socket is connected, this thread shall be 34291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * shutdown. 34391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang */ 34491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private class ScoSocketConnectThread extends Thread{ 34591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private BluetoothSocket mOutgoingSco; 34691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 34791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang public ScoSocketConnectThread(BluetoothDevice device) { 34891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 34991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mOutgoingSco = device.createScoSocket(); 35091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) { 35191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.w(TAG, "Could not create BluetoothSocket"); 352912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh failedScoConnect(); 35391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 35491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 35591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 35691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang @Override 35791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang public void run() { 35891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 35991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mOutgoingSco.connect(); 36091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang }catch (IOException connectException) { 36191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.e(TAG, "BluetoothSocket could not connect"); 36291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mOutgoingSco = null; 363912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh failedScoConnect(); 364912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 365912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 366912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (mOutgoingSco != null) { 367912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh connectSco(); 36891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 369912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 37091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 371912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private void connectSco() { 372e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent synchronized (BluetoothHandsfree.this) { 373e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent if (!Thread.interrupted() && isHeadsetConnected() && mConnectedSco == null) { 374912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (VDBG) log("Routing audio for outgoing SCO conection"); 375912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mConnectedSco = mOutgoingSco; 376912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mAudioManager.setBluetoothScoOn(true); 3771d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 378912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTED, 379912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mHeadset.getRemoteDevice()); 3801d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 381912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (mSignalScoCloseThread == null) { 382912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread = new SignalScoCloseThread(); 383912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread.setName("SignalScoCloseThread"); 384912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mSignalScoCloseThread.start(); 385912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 386912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } else { 387912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (VDBG) log("Rejecting new connected outgoing SCO socket"); 388912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh try { 389912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mOutgoingSco.close(); 390912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh }catch (IOException e) { 391912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh Log.e(TAG, "Error when closing Sco socket"); 392912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 393912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mOutgoingSco = null; 394912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh failedScoConnect(); 39591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 39691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 39791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 39891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 399912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private void failedScoConnect() { 400912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh // Wait for couple of secs before sending AUDIO_STATE_DISCONNECTED, 401912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh // since an incoming SCO connection can happen immediately with 402912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh // certain headsets. 403912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh Message msg = Message.obtain(mHandler, SCO_AUDIO_STATE); 404912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh msg.obj = mHeadset.getRemoteDevice(); 405912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mHandler.sendMessageDelayed(msg, 2000); 40643d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie 40743d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // Sync with interrupt() statement of shutdown method 40843d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // This prevents resetting of a valid mConnectScoThread. 40943d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // If this thread has been interrupted, it has been shutdown and 41043d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // mConnectScoThread is/will be reset by the outer class. 41143d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // We do not want to do it here since mConnectScoThread could be 41243d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // assigned with a new object. 41343d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie synchronized (ScoSocketConnectThread.this) { 41443d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie if (!isInterrupted()) { 41543d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie resetConnectScoThread(); 41643d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 41743d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 418912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 419912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 420e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent // must be called with BluetoothHandsfree locked 42191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang void shutdown() { 422e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent closeConnectedSco(); 42343d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie 42443d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // sync with isInterrupted() check in failedScoConnect method 42543d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // see explanation there 42643d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie synchronized (ScoSocketConnectThread.this) { 42743d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie interrupt(); 42843d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 42991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 43091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 43191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 43291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang /* 43391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * Signals when a Sco connection has been closed 43491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang */ 43591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private class SignalScoCloseThread extends Thread{ 43691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private boolean stopped = false; 43791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 43891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang @Override 43991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang public void run() { 44091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang while (!stopped) { 441e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent BluetoothSocket connectedSco = null; 442e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent synchronized (BluetoothHandsfree.this) { 443e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent connectedSco = mConnectedSco; 444e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent } 445e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent if (connectedSco != null) { 44691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang byte b[] = new byte[1]; 44791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang InputStream inStream = null; 44891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 449e28e6bd39098d1af6459b27a6c423c43c906c5a2Eric Laurent inStream = connectedSco.getInputStream(); 45091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) {} 45191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 45291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (inStream != null) { 45391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 45491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // inStream.read is a blocking call that won't ever 45591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // return anything, but will throw an exception if the 45691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // connection is closed 45791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang int ret = inStream.read(b, 0, 1); 45891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang }catch (IOException connectException) { 45991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // call a message to close this thread and turn off audio 46091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // we can't call audioOff directly because then 46191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // the thread would try to close itself 46291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Message msg = Message.obtain(mHandler, SCO_CLOSED); 46391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mHandler.sendMessage(msg); 46491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang break; 46591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 46691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 46791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 46891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 46991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 47091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 471e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent // must be called with BluetoothHandsfree locked 47291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang void shutdown() { 473e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent stopped = true; 474e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent closeConnectedSco(); 475e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent interrupt(); 47691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 47791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 47891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 47991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private void connectScoThread(){ 48043d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // Sync with setting mConnectScoThread to null to assure the validity of 48143d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // the condition 48243d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie synchronized (ScoSocketConnectThread.class) { 48343d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie if (mConnectScoThread == null) { 48443d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie BluetoothDevice device = mHeadset.getRemoteDevice(); 48543d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie if (getAudioState(device) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 48643d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTING, device); 48743d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 488912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 48943d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie mConnectScoThread = new ScoSocketConnectThread(mHeadset.getRemoteDevice()); 49043d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie mConnectScoThread.setName("HandsfreeScoSocketConnectThread"); 491912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 49243d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie mConnectScoThread.start(); 49343d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 49443d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 49543d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 49643d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie 49743d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie private void resetConnectScoThread() { 49843d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // Sync with if (mConnectScoThread == null) check 49943d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie synchronized (ScoSocketConnectThread.class) { 50043d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie mConnectScoThread = null; 50191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 50291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 50391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 504e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent // must be called with BluetoothHandsfree locked 50591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang private void closeConnectedSco() { 50691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mConnectedSco != null) { 50791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang try { 50891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mConnectedSco.close(); 50991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } catch (IOException e) { 51091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang Log.e(TAG, "Error when closing Sco socket"); 51191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 51291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 51391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang BluetoothDevice device = null; 51491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mHeadset != null) { 51591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang device = mHeadset.getRemoteDevice(); 51691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 51791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mAudioManager.setBluetoothScoOn(false); 5181d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setAudioState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, device); 51991b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 52091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mConnectedSco = null; 52191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 52291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang } 52391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized void onBluetoothEnabled() { 525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* Bluez has a bug where it will always accept and then orphan 526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * incoming SCO connections, regardless of whether we have a listening 527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * SCO socket. So the best thing to do is always run a listening socket 52891b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang * while bluetooth is on so that at least we can disconnect it 529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * immediately when we don't want it. 530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 53191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 53291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mIncomingScoThread == null) { 53391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingScoThread = new IncomingScoAcceptThread(); 53491b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingScoThread.setName("incomingScoAcceptThread"); 53591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mIncomingScoThread.start(); 536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized void onBluetoothDisabled() { 54091b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang // Close off the SCO sockets 541a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent audioOff(); 54291b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 54391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mIncomingScoThread != null) { 544e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent mIncomingScoThread.shutdown(); 545e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent mIncomingScoThread = null; 546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean isHeadsetConnected() { 55090eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie if (mHeadset == null || mHeadsetType == TYPE_UNKNOWN) { 551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return mHeadset.isConnected(); 554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 556f6adf1a33b12c9900b3ce9c15130642ce515ae91Jaikumar Ganesh /* package */ synchronized void connectHeadset(HeadsetBase headset, int headsetType) { 557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mHeadset = headset; 558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mHeadsetType = headsetType; 559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mHeadsetType == TYPE_HEADSET) { 560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project initializeHeadsetAtParser(); 561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project initializeHandsfreeAtParser(); 563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 5641498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 5651498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek // Headset vendor-specific commands 5661498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek registerAllVendorSpecificCommands(); 5671498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project headset.startEventThread(); 569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project configAudioParameters(); 570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (inDebug()) { 572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project startDebug(); 573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (isIncallAudio()) { 576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 57734a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi } else if ( mCM.getFirstActiveRingingCall().isRinging()) { 57834a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi // need to update HS with RING when single ringing call exist 57934a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi mBluetoothPhoneState.ring(); 580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* returns true if there is some kind of in-call audio we may wish to route 584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * bluetooth to */ 585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean isIncallAudio() { 5868058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call.State state = mCM.getActiveFgCallState(); 587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return (state == Call.State.ACTIVE || state == Call.State.ALERTING); 589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 591819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh /* package */ synchronized void disconnectHeadset() { 592819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh audioOff(); 5939760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie 5949760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie // No need to check if isVirtualCallInProgress() 5959760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie // terminateScoUsingVirtualVoiceCall() does the check 5969760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie terminateScoUsingVirtualVoiceCall(); 5979760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie 59890eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mHeadsetType = TYPE_UNKNOWN; 599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project stopDebug(); 600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project resetAtState(); 601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 603bfc44512504ebc93c101ddb394719840f2d25072Jaikumar Ganesh /* package */ synchronized void resetAtState() { 604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClip = false; 605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mIndicatorsEnabled = false; 6060966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly mServiceConnectionEstablished = false; 607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCmee = false; 608c9d9ed30aa547b79b81adc13a4d148a003b6ee62w mClccTimestamps = new long[GSM_MAX_CONNECTIONS]; 609c9d9ed30aa547b79b81adc13a4d148a003b6ee62w mClccUsed = new boolean[GSM_MAX_CONNECTIONS]; 610c9d9ed30aa547b79b81adc13a4d148a003b6ee62w for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) { 611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClccUsed[i] = false; 612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mRemoteBrsf = 0; 614f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh mPhonebook.resetAtState(); 615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 6177d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie /* package */ HeadsetBase getHeadset() { 6187d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie return mHeadset; 6197d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } 6207d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie 621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private void configAudioParameters() { 622db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly String name = mHeadset.getRemoteDevice().getName(); 623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (name == null) { 624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project name = "<unknown>"; 625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 626aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent mAudioManager.setParameters(HEADSET_NAME+"="+name+";"+HEADSET_NREC+"=on"); 627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Represents the data that we send in a +CIND or +CIEV command to the HF 631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private class BluetoothPhoneState { 633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: no service 634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: service 635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mService; 636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: no active call 638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: active call (where active means audio is routed - not held call) 639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mCall; 640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: not in call setup 642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: incoming call setup 643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 2: outgoing call setup 644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 3: remote party being alerted in an outgoing call setup 645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mCallsetup; 646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: no calls held 648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: held call and active call 649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 2: held call only 650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mCallheld; 651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // cellular signal strength of AG: 0-5 653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mSignal; 654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // cellular signal strength in CSQ rssi scale 656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mRssi; // for CSQ 657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: roaming not active (home) 659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: roaming active 660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mRoam; 661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // battery charge of AG: 0-5 663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mBattchg; 664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 0: not registered 666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 1: registered, home network 667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // 5: registered, roaming 668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mStat; // for CREG 669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private String mRingingNumber; // Context for in-progress RING's 671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int mRingingType; 672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean mIgnoreRing = false; 6731ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh private boolean mStopRing = false; 674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 67590eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie // current or last call start timestamp 67690eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie private long mCallStartTime = 0; 67790eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie // time window to reconnect remotely-disconnected SCO 67890eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie // in mili-seconds 67990eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie private static final int RETRY_SCO_TIME_WINDOW = 1000; 68090eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie 681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int SERVICE_STATE_CHANGED = 1; 682487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh private static final int PRECISE_CALL_STATE_CHANGED = 2; 683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int RING = 3; 684a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman private static final int PHONE_CDMA_CALL_WAITING = 4; 685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private Handler mStateChangeHandler = new Handler() { 687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void handleMessage(Message msg) { 689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch(msg.what) { 690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case RING: 691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = ring(); 692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (result != null) { 693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC(result.toString()); 694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case SERVICE_STATE_CHANGED: 697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result; 698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project updateServiceState(sendUpdate(), state); 699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 700487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh case PRECISE_CALL_STATE_CHANGED: 701a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman case PHONE_CDMA_CALL_WAITING: 702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Connection connection = null; 703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (((AsyncResult) msg.obj).result instanceof Connection) { 704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project connection = (Connection) ((AsyncResult) msg.obj).result; 705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 706487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh handlePreciseCallStateChange(sendUpdate(), connection); 707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private BluetoothPhoneState() { 713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // init members 7148058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang // TODO May consider to repalce the default phone's state and signal 7158058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang // by CallManagter's state and signal 7168058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang updateServiceState(false, mCM.getDefaultPhone().getServiceState()); 717487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh handlePreciseCallStateChange(false, null); 718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mBattchg = 5; // There is currently no API to get battery level 719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // on demand, so set to 5 and wait for an update 7208058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength()); 721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // register for updates 723f8453f9e061b237d83d006e07009402fa7680583John Wang // Use the service state of default phone as BT service state to 724f8453f9e061b237d83d006e07009402fa7680583John Wang // avoid situation such as no cell or wifi connection but still 725f8453f9e061b237d83d006e07009402fa7680583John Wang // reporting in service (since SipPhone always reports in service). 726f8453f9e061b237d83d006e07009402fa7680583John Wang mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler, 727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project SERVICE_STATE_CHANGED, null); 7288058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.registerForPreciseCallStateChanged(mStateChangeHandler, 729487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh PRECISE_CALL_STATE_CHANGED, null); 7308058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.registerForCallWaiting(mStateChangeHandler, 7318058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PHONE_CDMA_CALL_WAITING, null); 7328058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang 733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project filter.addAction(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); 7351d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 7367d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mContext.registerReceiver(mStateReceiver, filter); 738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 740a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville private void updateBtPhoneStateAfterRadioTechnologyChange() { 7418eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange..."); 742a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville 743a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville //Unregister all events from the old obsolete phone 744f8453f9e061b237d83d006e07009402fa7680583John Wang mCM.getDefaultPhone().unregisterForServiceStateChanged(mStateChangeHandler); 7458058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.unregisterForPreciseCallStateChanged(mStateChangeHandler); 7468058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.unregisterForCallWaiting(mStateChangeHandler); 747a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville 748a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville //Register all events new to the new active phone 749f8453f9e061b237d83d006e07009402fa7680583John Wang mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler, 75019dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh SERVICE_STATE_CHANGED, null); 7518058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.registerForPreciseCallStateChanged(mStateChangeHandler, 752487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh PRECISE_CALL_STATE_CHANGED, null); 7538058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang mCM.registerForCallWaiting(mStateChangeHandler, 7548058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PHONE_CDMA_CALL_WAITING, null); 755a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville } 756a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville 757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean sendUpdate() { 75802369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled 75902369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS && mServiceConnectionEstablished; 760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean sendClipUpdate() { 76302369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mClip && 76402369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS mServiceConnectionEstablished; 76502369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS } 76602369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS 76702369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS private boolean sendRingUpdate() { 76802369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS if (isHeadsetConnected() && !mIgnoreRing && !mStopRing && 76902369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS mCM.getFirstActiveRingingCall().isRinging()) { 77002369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS if (mHeadsetType == TYPE_HANDSFREE) { 77102369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS return mServiceConnectionEstablished ? true : false; 77202369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS } 77302369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS return true; 77402369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS } 77502369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS return false; 776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 7781ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh private void stopRing() { 7791ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh mStopRing = true; 7801ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh } 7811ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh 782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* convert [0,31] ASU signal strength to the [0,5] expected by 783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * bluetooth devices. Scale is similar to status bar policy 784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 78534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh private int gsmAsuToSignal(SignalStrength signalStrength) { 78634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int asu = signalStrength.getGsmSignalStrength(); 787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (asu >= 16) return 5; 788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project else if (asu >= 8) return 4; 789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project else if (asu >= 4) return 3; 790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project else if (asu >= 2) return 2; 791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project else if (asu >= 1) return 1; 792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project else return 0; 793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 79534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh /** 79634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh * Convert the cdma / evdo db levels to appropriate icon level. 79734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh * The scale is similar to the one used in status bar policy. 79834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh * 79934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh * @param signalStrength 80034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh * @return the icon level 801404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville */ 80234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh private int cdmaDbmEcioToSignal(SignalStrength signalStrength) { 80334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int levelDbm = 0; 80434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int levelEcio = 0; 80534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int cdmaIconLevel = 0; 80634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int evdoIconLevel = 0; 80734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int cdmaDbm = signalStrength.getCdmaDbm(); 80834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int cdmaEcio = signalStrength.getCdmaEcio(); 80934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 81034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh if (cdmaDbm >= -75) levelDbm = 4; 81134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaDbm >= -85) levelDbm = 3; 81234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaDbm >= -95) levelDbm = 2; 81334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaDbm >= -100) levelDbm = 1; 81434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else levelDbm = 0; 81534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 81634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh // Ec/Io are in dB*10 81734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh if (cdmaEcio >= -90) levelEcio = 4; 81834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaEcio >= -110) levelEcio = 3; 81934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaEcio >= -130) levelEcio = 2; 82034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (cdmaEcio >= -150) levelEcio = 1; 82134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else levelEcio = 0; 82234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 82334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio; 82434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 82513df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh if (mServiceState != null && 826b0664bb07d16eef5a0dd70013ffd02ef6db3ebebRobert Greenwalt (mServiceState.getNetworkType() == TelephonyManager.NETWORK_TYPE_EVDO_0 || 827b0664bb07d16eef5a0dd70013ffd02ef6db3ebebRobert Greenwalt mServiceState.getNetworkType() == TelephonyManager.NETWORK_TYPE_EVDO_A)) { 82834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int evdoEcio = signalStrength.getEvdoEcio(); 82934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int evdoSnr = signalStrength.getEvdoSnr(); 83034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int levelEvdoEcio = 0; 83134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh int levelEvdoSnr = 0; 83234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 83334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh // Ec/Io are in dB*10 83434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh if (evdoEcio >= -650) levelEvdoEcio = 4; 83534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoEcio >= -750) levelEvdoEcio = 3; 83634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoEcio >= -900) levelEvdoEcio = 2; 83734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoEcio >= -1050) levelEvdoEcio = 1; 83834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else levelEvdoEcio = 0; 83934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 84034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh if (evdoSnr > 7) levelEvdoSnr = 4; 84134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoSnr > 5) levelEvdoSnr = 3; 84234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoSnr > 3) levelEvdoSnr = 2; 84334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else if (evdoSnr > 1) levelEvdoSnr = 1; 84434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh else levelEvdoSnr = 0; 84534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 84634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr; 84734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh } 84834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh // TODO(): There is a bug open regarding what should be sent. 84934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh return (cdmaIconLevel > evdoIconLevel) ? cdmaIconLevel : evdoIconLevel; 85034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh 851404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } 852404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville 853404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville 854404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville private int asuToSignal(SignalStrength signalStrength) { 85534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh if (signalStrength.isGsm()) { 85634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh return gsmAsuToSignal(signalStrength); 857404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } else { 85834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh return cdmaDbmEcioToSignal(signalStrength); 859404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } 860404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } 861404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville 862404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville 863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* convert [0,5] signal strength to a rssi signal strength for CSQ 864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * which is [0,31]. Despite the same scale, this is not the same value 865b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * as ASU. 866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 867b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int signalToRssi(int signal) { 868b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // using C4A suggested values 869b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (signal) { 870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 0: return 0; 871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 1: return 4; 872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 2: return 8; 873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 3: return 13; 874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 4: return 19; 875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case 5: return 31; 876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return 0; 878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() { 882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void onReceive(Context context, Intent intent) { 884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { 885d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie Message msg = mHandler.obtainMessage(BATTERY_CHANGED, intent); 886d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie mHandler.sendMessage(msg); 887f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } else if (intent.getAction().equals( 888f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED)) { 889d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie Message msg = mHandler.obtainMessage(SIGNAL_STRENGTH_CHANGED, 8906e2978b10d99879799e21ff246b2827721fe1260Matthew Xie intent); 891d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie mHandler.sendMessage(msg); 8921d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } else if (intent.getAction().equals( 8931d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { 8941d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 8951d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothProfile.STATE_DISCONNECTED); 8961d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 8971d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothProfile.STATE_DISCONNECTED); 898f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan BluetoothDevice device = 899f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 900105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh 9011d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 902105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh // We are only concerned about Connected sinks to suspend and resume 903105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh // them. We can safely ignore SINK_STATE_CHANGE for other devices. 904a43debb2022f4f4cbb7a2ca8aa3b2658b2da4231Eric Laurent if (device == null || (mA2dpDevice != null && !device.equals(mA2dpDevice))) { 905a43debb2022f4f4cbb7a2ca8aa3b2658b2da4231Eric Laurent return; 906a43debb2022f4f4cbb7a2ca8aa3b2658b2da4231Eric Laurent } 907105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh 908f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan synchronized (BluetoothHandsfree.this) { 909f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mA2dpState = state; 9101d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (state == BluetoothProfile.STATE_DISCONNECTED) { 911105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh mA2dpDevice = null; 912105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh } else { 913105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh mA2dpDevice = device; 914105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh } 915ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (oldState == BluetoothA2dp.STATE_PLAYING && 9161d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mA2dpState == BluetoothProfile.STATE_CONNECTED) { 917ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (mA2dpSuspended) { 918ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (mPendingSco) { 919ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mHandler.removeMessages(MESSAGE_CHECK_PENDING_SCO); 920ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (DBG) log("A2DP suspended, completing SCO"); 92191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang connectScoThread(); 922ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mPendingSco = false; 923f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 924f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 925f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 926f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 9277d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } else if (intent.getAction(). 9287d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { 9297d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie mPhonebook.handleAccessPermissionResult(intent); 930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void updateBatteryState(Intent intent) { 935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int batteryLevel = intent.getIntExtra("level", -1); 936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int scale = intent.getIntExtra("scale", -1); 937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (batteryLevel == -1 || scale == -1) { 938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return; // ignore 939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project batteryLevel = batteryLevel * 5 / scale; 941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mBattchg != batteryLevel) { 942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mBattchg = batteryLevel; 943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate()) { 944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("+CIEV: 7," + mBattchg); 945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void updateSignalState(Intent intent) { 950404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent 951404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread 95290eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie if (!isHeadsetConnected()) { 953d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh return; 954d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh } 955d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh 956404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras()); 957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int signal; 958404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville 959404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville if (signalStrength != null) { 960404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville signal = asuToSignal(signalStrength); 961404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville mRssi = signalToRssi(signal); // no unsolicited CSQ 962404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville if (signal != mSignal) { 963404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville mSignal = signal; 964404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville if (sendUpdate()) { 965404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville sendURC("+CIEV: 5," + mSignal); 966404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } 967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 968404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville } else { 969404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville Log.e(TAG, "Signal Strength null"); 970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void updateServiceState(boolean sendUpdate, ServiceState state) { 974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int service = state.getState() == ServiceState.STATE_IN_SERVICE ? 1 : 0; 975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int roam = state.getRoaming() ? 1 : 0; 976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int stat; 977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 97813df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh mServiceState = state; 979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (service == 0) { 980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project stat = 0; 981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project stat = (roam == 1) ? 5 : 1; 983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (service != mService) { 986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mService = service; 987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CIEV: 1," + mService); 989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (roam != mRoam) { 992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mRoam = roam; 993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CIEV: 6," + mRoam); 995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (stat != mStat) { 998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStat = stat; 999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 1000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse(toCregString()); 1001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC(result.toString()); 1005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1007487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh private synchronized void handlePreciseCallStateChange(boolean sendUpdate, 1008487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh Connection connection) { 1009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int call = 0; 1010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int callsetup = 0; 1011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int callheld = 0; 1012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int prevCallsetup = mCallsetup; 1013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 10148058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call foregroundCall = mCM.getActiveFgCall(); 10158058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call backgroundCall = mCM.getFirstActiveBgCall(); 10168058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call ringingCall = mCM.getFirstActiveRingingCall(); 1017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 10188eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("updatePhoneState()"); 1019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1020487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // This function will get called when the Precise Call State 1021487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // {@link Call.State} changes. Hence, we might get this update 1022487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // even if the {@link Phone.state} is same as before. 1023487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // Check for the same. 1024487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh 10258058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Phone.State newState = mCM.getState(); 10261dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh if (newState != mPhoneState) { 10271dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mPhoneState = newState; 10281dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh switch (mPhoneState) { 10291dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh case IDLE: 10301dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mUserWantsAudio = true; // out of call - reset state 10311dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh audioOff(); 10321dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh break; 10331dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh default: 10341dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh callStarted(); 10351dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh } 1036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 10388058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang switch(foregroundCall.getState()) { 1039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case ACTIVE: 1040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project call = 1; 1041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAudioPossible = true; 1042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case DIALING: 1044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project callsetup = 2; 1045a41427328932deb7cbadf586a1ec58e0ba26a932Jaikumar Ganesh mAudioPossible = true; 10463904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // We also need to send a Call started indication 10473904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // for cases where the 2nd MO was initiated was 10483904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // from a *BT hands free* and is waiting for a 10493904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // +BLND: OK response 10503904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // There is a special case handling of the same case 10513904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh // for CDMA below 10528058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (mCM.getFgPhone().getPhoneType() == Phone.PHONE_TYPE_GSM) { 10533904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh callStarted(); 10543904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh } 1055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case ALERTING: 1057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project callsetup = 3; 1058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Open the SCO channel for the outgoing call. 105990eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mCallStartTime = System.currentTimeMillis(); 1060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 1061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAudioPossible = true; 1062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 106381a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh case DISCONNECTING: 106481a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // This is a transient state, we don't want to send 106581a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // any AT commands during this state. 106681a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh call = mCall; 106781a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callsetup = mCallsetup; 106881a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callheld = mCallheld; 106981a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh break; 1070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project default: 1071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAudioPossible = false; 1072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 10748058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang switch(ringingCall.getState()) { 1075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case INCOMING: 1076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case WAITING: 1077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project callsetup = 1; 1078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 107981a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh case DISCONNECTING: 108081a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // This is a transient state, we don't want to send 108181a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // any AT commands during this state. 108281a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh call = mCall; 108381a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callsetup = mCallsetup; 108481a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callheld = mCallheld; 108581a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh break; 1086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 10888058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang switch(backgroundCall.getState()) { 1089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case HOLDING: 1090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (call == 1) { 1091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project callheld = 1; 1092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 1093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project call = 1; 1094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project callheld = 2; 1095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 109781a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh case DISCONNECTING: 109881a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // This is a transient state, we don't want to send 109981a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh // any AT commands during this state. 110081a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh call = mCall; 110181a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callsetup = mCallsetup; 110281a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh callheld = mCallheld; 110381a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh break; 1104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mCall != call) { 1107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (call == 1) { 1108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // This means that a call has transitioned from NOT ACTIVE to ACTIVE. 1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Switch on audio. 111090eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mCallStartTime = System.currentTimeMillis(); 1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCall = call; 1114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 1115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CIEV: 2," + mCall); 1116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mCallsetup != callsetup) { 1119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCallsetup = callsetup; 1120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 11214b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // If mCall = 0, send CIEV 11224b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // mCall = 1, mCallsetup = 0, send CIEV 11234b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // mCall = 1, mCallsetup = 1, send CIEV after CCWA, 11244b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // if 3 way supported. 11254b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // mCall = 1, mCallsetup = 2 / 3 -> send CIEV, 11264b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project // if 3 way is supported 11274b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project if (mCall != 1 || mCallsetup == 0 || 11284b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) { 1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CIEV: 3," + mCallsetup); 1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 11348058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (mCM.getDefaultPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA) { 1135c9d9ed30aa547b79b81adc13a4d148a003b6ee62w PhoneApp app = PhoneApp.getInstance(); 113660877272381161201c6969dea501e683705d6e32w if (app.cdmaPhoneCallState != null) { 1137487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState currCdmaThreeWayCallState = 113860877272381161201c6969dea501e683705d6e32w app.cdmaPhoneCallState.getCurrentCallState(); 1139487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState prevCdmaThreeWayCallState = 1140ed1d155825eb32990fde95eef9d89a7260e4c3f1w app.cdmaPhoneCallState.getPreviousCallState(); 1141ed1d155825eb32990fde95eef9d89a7260e4c3f1w 114291f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh log("CDMA call state: " + currCdmaThreeWayCallState + " prev state:" + 114391f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh prevCdmaThreeWayCallState); 1144487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callheld = getCdmaCallHeldStatus(currCdmaThreeWayCallState, 1145487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh prevCdmaThreeWayCallState); 1146487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh 1147487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (mCdmaThreeWayCallState != currCdmaThreeWayCallState) { 1148487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // In CDMA, the network does not provide any feedback 1149487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // to the phone when the 2nd MO call goes through the 1150487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // stages of DIALING > ALERTING -> ACTIVE we fake the 1151487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // sequence 1152487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if ((currCdmaThreeWayCallState == 1153487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) 1154487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) { 1155487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh mAudioPossible = true; 1156487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (sendUpdate) { 1157487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) { 1158487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh result.addResponse("+CIEV: 3,2"); 115991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh // Mimic putting the call on hold 116091f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh result.addResponse("+CIEV: 4,1"); 116191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mCallheld = callheld; 1162487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh result.addResponse("+CIEV: 3,3"); 1163487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh result.addResponse("+CIEV: 3,0"); 1164487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } 116560877272381161201c6969dea501e683705d6e32w } 1166487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // We also need to send a Call started indication 1167487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // for cases where the 2nd MO was initiated was 1168487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // from a *BT hands free* and is waiting for a 1169487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // +BLND: OK response 1170487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callStarted(); 1171c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1172c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1173487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // In CDMA, the network does not provide any feedback to 1174487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // the phone when a user merges a 3way call or swaps 1175487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // between two calls we need to send a CIEV response 1176487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // indicating that a call state got changed which should 1177487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // trigger a CLCC update request from the BT client. 1178487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (currCdmaThreeWayCallState == 117991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh CdmaPhoneCallState.PhoneCallState.CONF_CALL && 118091f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh prevCdmaThreeWayCallState == 118191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 1182487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh mAudioPossible = true; 1183487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (sendUpdate) { 1184487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) { 1185487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh result.addResponse("+CIEV: 2,1"); 1186487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh result.addResponse("+CIEV: 3,0"); 1187487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } 118860877272381161201c6969dea501e683705d6e32w } 1189c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1190c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1191487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh mCdmaThreeWayCallState = currCdmaThreeWayCallState; 1192c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1193c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1194c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 119591f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh boolean callsSwitched; 119691f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh 119791f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh if (mCM.getDefaultPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA && 119891f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mCdmaThreeWayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) { 119991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh callsSwitched = mCdmaCallsSwapped; 120091f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } else { 120191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh callsSwitched = 120291f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh (callheld == 1 && ! (backgroundCall.getEarliestConnectTime() == 120391f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mBgndEarliestConnectionTime)); 120491f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mBgndEarliestConnectionTime = backgroundCall.getEarliestConnectTime(); 120591f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } 1206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mCallheld != callheld || callsSwitched) { 1209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCallheld = callheld; 1210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate) { 1211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CIEV: 4," + mCallheld); 1212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (callsetup == 1 && callsetup != prevCallsetup) { 1216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // new incoming call 1217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String number = null; 1218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int type = 128; 1219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // find incoming phone number and type 1220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (connection == null) { 12218058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang connection = ringingCall.getEarliestConnection(); 1222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (connection == null) { 1223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.e(TAG, "Could not get a handle on Connection object for new " + 1224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "incoming call"); 1225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (connection != null) { 1228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project number = connection.getAddress(); 1229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number != null) { 1230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project type = PhoneNumberUtils.toaFromString(number); 1231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number == null) { 1234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project number = ""; 1235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if ((call != 0 || callheld != 0) && sendUpdate) { 1237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // call waiting 1238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) { 1239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CCWA: \"" + number + "\"," + type); 12404b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project result.addResponse("+CIEV: 3," + callsetup); 1241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 1243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // regular new incoming call 1244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mRingingNumber = number; 1245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mRingingType = type; 1246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mIgnoreRing = false; 12471ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh mStopRing = false; 1248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1249a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly if ((mLocalBrsf & BRSF_AG_IN_BAND_RING) != 0x0) { 125090eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie mCallStartTime = System.currentTimeMillis(); 1251a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly audioOn(); 1252a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly } 1253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResult(ring()); 1254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC(result.toString()); 1257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1259487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh private int getCdmaCallHeldStatus(CdmaPhoneCallState.PhoneCallState currState, 1260487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh CdmaPhoneCallState.PhoneCallState prevState) { 1261487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh int callheld; 1262487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // Update the Call held information 1263487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (currState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) { 1264487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh if (prevState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 1265487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callheld = 0; //0: no calls held, as now *both* the caller are active 1266487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } else { 1267487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callheld = 1; //1: held call and active call, as on answering a 1268487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // Call Waiting, one of the caller *is* put on hold 1269487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } 1270487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } else if (currState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 1271487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callheld = 1; //1: held call and active call, as on make a 3 Way Call 1272487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh // the first caller *is* put on hold 1273487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } else { 1274487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh callheld = 0; //0: no calls held as this is a SINGLE_ACTIVE call 1275487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } 1276487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh return callheld; 1277487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh } 1278487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh 1279487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh 1280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private AtCommandResult ring() { 128102369485c4c2b977e6a26cd01ab817b364758bfeSRINIVAS if (sendRingUpdate()) { 1282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 1283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("RING"); 1284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendClipUpdate()) { 1285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CLIP: \"" + mRingingNumber + "\"," + mRingingType); 1286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Message msg = mStateChangeHandler.obtainMessage(RING); 1289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStateChangeHandler.sendMessageDelayed(msg, 3000); 1290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 1291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return null; 1293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized String toCregString() { 1296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new String("+CREG: 1," + mStat); 1297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 129991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh private synchronized void updateCallHeld() { 130091f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh if (mCallheld != 0) { 130191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mCallheld = 0; 130291f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh sendURC("+CIEV: 4,0"); 130391f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } 130491f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } 130591f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh 1306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized AtCommandResult toCindResult() { 1307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.OK); 1308b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh int call, call_setup; 1309b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 1310b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Handsfree carkits expect that +CIND is properly responded to. 1311b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Hence we ensure that a proper response is sent for the virtual call too. 1312b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (isVirtualCallInProgress()) { 1313b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh call = 1; 1314b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh call_setup = 0; 1315b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } else { 1316b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // regular phone call 1317b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh call = mCall; 1318b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh call_setup = mCallsetup; 1319b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 1320d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh 1321b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength()); 1322b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh String status = "+CIND: " + mService + "," + call + "," + call_setup + "," + 1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCallheld + "," + mSignal + "," + mRoam + "," + mBattchg; 1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse(status); 1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized AtCommandResult toCsqResult() { 1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.OK); 1330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String status = "+CSQ: " + mRssi + ",99"; 1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse(status); 1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized AtCommandResult getCindTestResult() { 1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CIND: (\"service\",(0-1))," + "(\"call\",(0-1))," + 1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))," + 1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "(\"roam\",(0-1)),(\"battchg\",(0-5))"); 1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void ignoreRing() { 1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCallsetup = 0; 1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mIgnoreRing = true; 1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (sendUpdate()) { 1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("+CIEV: 3," + mCallsetup); 1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 135093db56932abb4ad52c446947048e2af69e5a9848Matthew Xie private void scoClosed() { 135193db56932abb4ad52c446947048e2af69e5a9848Matthew Xie // sync on mUserWantsAudio change 135293db56932abb4ad52c446947048e2af69e5a9848Matthew Xie synchronized(BluetoothHandsfree.this) { 135390eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie if (mUserWantsAudio && 135490eae4375aa85e6ed620e32b12f655ef99356a70Matthew Xie System.currentTimeMillis() - mCallStartTime < RETRY_SCO_TIME_WINDOW) { 135593db56932abb4ad52c446947048e2af69e5a9848Matthew Xie Message msg = mHandler.obtainMessage(SCO_CONNECTION_CHECK); 135693db56932abb4ad52c446947048e2af69e5a9848Matthew Xie mHandler.sendMessage(msg); 135793db56932abb4ad52c446947048e2af69e5a9848Matthew Xie } 135893db56932abb4ad52c446947048e2af69e5a9848Matthew Xie } 135993db56932abb4ad52c446947048e2af69e5a9848Matthew Xie } 1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int SCO_CLOSED = 3; 1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int CHECK_CALL_STARTED = 4; 1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int CHECK_VOICE_RECOGNITION_STARTED = 5; 1365f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan private static final int MESSAGE_CHECK_PENDING_SCO = 6; 1366912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private static final int SCO_AUDIO_STATE = 7; 136793db56932abb4ad52c446947048e2af69e5a9848Matthew Xie private static final int SCO_CONNECTION_CHECK = 8; 1368d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie private static final int BATTERY_CHANGED = 9; 1369d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie private static final int SIGNAL_STRENGTH_CHANGED = 10; 1370d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie 1371d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie private final class HandsfreeMessageHandler extends Handler { 1372d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie private HandsfreeMessageHandler(Looper looper) { 1373d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie super(looper); 1374d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie } 1375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 13777757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh public void handleMessage(Message msg) { 137887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie switch (msg.what) { 137987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case SCO_CLOSED: 138087ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie synchronized (BluetoothHandsfree.this) { 138187ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // synchronized 138287ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Make atomic against audioOn, userWantsAudioOn 138387ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // TODO finer lock to decouple from other call flow such as 138487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // mWaitingForCallStart change 138587ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie 138691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang audioOff(); 138793db56932abb4ad52c446947048e2af69e5a9848Matthew Xie // notify mBluetoothPhoneState that the SCO channel has closed 138893db56932abb4ad52c446947048e2af69e5a9848Matthew Xie mBluetoothPhoneState.scoClosed(); 138987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie } 139087ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 139187ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case CHECK_CALL_STARTED: 139287ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie synchronized (BluetoothHandsfree.this) { 139387ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // synchronized 139487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Protect test/change of mWaitingForCallStart 13957757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh if (mWaitingForCallStart) { 13967757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh mWaitingForCallStart = false; 13977757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh Log.e(TAG, "Timeout waiting for call to start"); 13987757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh sendURC("ERROR"); 13997757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh if (mStartCallWakeLock.isHeld()) { 14007757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh mStartCallWakeLock.release(); 14017757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh } 14027757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh } 140387ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie } 140487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 140587ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case CHECK_VOICE_RECOGNITION_STARTED: 140687ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie synchronized (BluetoothHandsfree.this) { 140787ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // synchronized 140887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Protect test/change of mWaitingForVoiceRecognition 14097757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh if (mWaitingForVoiceRecognition) { 14107757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh mWaitingForVoiceRecognition = false; 14117757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh Log.e(TAG, "Timeout waiting for voice recognition to start"); 14127757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh sendURC("ERROR"); 14137757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh } 141487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie } 141587ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 141687ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case MESSAGE_CHECK_PENDING_SCO: 141787ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie synchronized (BluetoothHandsfree.this) { 141887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // synchronized 141987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Protect test/change of mPendingSco 1420f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan if (mPendingSco && isA2dpMultiProfile()) { 1421f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan Log.w(TAG, "Timeout suspending A2DP for SCO (mA2dpState = " + 1422f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mA2dpState + "). Starting SCO anyway"); 142391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang connectScoThread(); 1424f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mPendingSco = false; 1425f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 142687ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie } 142787ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 142887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case SCO_AUDIO_STATE: 142987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie BluetoothDevice device = (BluetoothDevice) msg.obj; 143087ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie if (getAudioState(device) == BluetoothHeadset.STATE_AUDIO_CONNECTING) { 143187ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie setAudioState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, device); 143287ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie } 143387ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 143487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case SCO_CONNECTION_CHECK: 143587ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie synchronized (mBluetoothPhoneState) { 143687ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // synchronized on mCall change 143787ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie if (mBluetoothPhoneState.mCall == 1) { 143887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Sometimes, the SCO channel is torn down by HF with no reason. 143987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // Because we are still in active call, reconnect SCO. 144087ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie // audioOn does nothing if the SCO is already on. 144187ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie audioOn(); 144293db56932abb4ad52c446947048e2af69e5a9848Matthew Xie } 1443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 144487ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 144587ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case BATTERY_CHANGED: 144687ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie mBluetoothPhoneState.updateBatteryState((Intent) msg.obj); 144787ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 144887ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie case SIGNAL_STRENGTH_CHANGED: 144987ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie mBluetoothPhoneState.updateSignalState((Intent) msg.obj); 145087ad6e7a229370ef0437f407b2e2a6d986025763Matthew Xie break; 1451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1453d9436d8b89bdb18e6ce5e7abcefeab60015d5e81Matthew Xie } 14541d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 14551d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private synchronized void setAudioState(int state, BluetoothDevice device) { 14561d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (VDBG) log("setAudioState(" + state + ")"); 14571d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (mBluetoothHeadset == null) { 14581d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET); 14591d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mPendingAudioState = true; 14601d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mAudioState = state; 14611d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return; 14621d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14631d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mBluetoothHeadset.setAudioState(device, state); 14644079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project } 14654079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project 1466912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private synchronized int getAudioState(BluetoothDevice device) { 1467912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh if (mBluetoothHeadset == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 1468912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh return mBluetoothHeadset.getAudioState(device); 1469912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 1470912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 14711d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private BluetoothProfile.ServiceListener mProfileListener = 14721d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh new BluetoothProfile.ServiceListener() { 14731d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public void onServiceConnected(int profile, BluetoothProfile proxy) { 14741d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (profile == BluetoothProfile.HEADSET) { 14751d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mBluetoothHeadset = (BluetoothHeadset) proxy; 14761d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh synchronized(BluetoothHandsfree.this) { 14771d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (mPendingAudioState) { 14781d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mBluetoothHeadset.setAudioState(mHeadset.getRemoteDevice(), mAudioState); 14791d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mPendingAudioState = false; 14801d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14811d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14821d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } else if (profile == BluetoothProfile.A2DP) { 14831d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mA2dp = (BluetoothA2dp) proxy; 14841d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14851d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14861d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public void onServiceDisconnected(int profile) { 14871d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (profile == BluetoothProfile.HEADSET) { 14881d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mBluetoothHeadset = null; 14891d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } else if (profile == BluetoothProfile.A2DP) { 14901d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mA2dp = null; 14911d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14921d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 14931d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh }; 14941d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 14951498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek /* 14961498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * Put the AT command, company ID, arguments, and device in an Intent and broadcast it. 14971498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek */ 14981498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private void broadcastVendorSpecificEventIntent(String command, 14991498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek int companyId, 150086324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh int commandType, 15011498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek Object[] arguments, 15021498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek BluetoothDevice device) { 15031498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek if (VDBG) log("broadcastVendorSpecificEventIntent(" + command + ")"); 15041498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek Intent intent = 15051498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek new Intent(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT); 15061498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD, command); 150786324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, 150886324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh commandType); 15091498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek // assert: all elements of args are Serializable 15101498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS, arguments); 15111498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 151286324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh 151386324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh intent.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY 151486324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh + "." + Integer.toString(companyId)); 151586324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh 15161498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH); 15171498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 15181498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 1519a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville void updateBtHandsfreeAfterRadioTechnologyChange() { 15201498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek if (VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange..."); 1521a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville 15221dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState.updateBtPhoneStateAfterRadioTechnologyChange(); 1523a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville } 1524a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville 1525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Request to establish SCO (audio) connection to bluetooth 1526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * headset/handsfree, if one is connected. Does not block. 1527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Returns false if the user has requested audio off, or if there 1528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * is some other immediate problem that will prevent BT audio. 1529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 1530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized boolean audioOn() { 1531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (VDBG) log("audioOn()"); 1532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!isHeadsetConnected()) { 1533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("audioOn(): headset is not connected!"); 1534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 1535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 15360966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if (mHeadsetType == TYPE_HANDSFREE && !mServiceConnectionEstablished) { 15370966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if (DBG) log("audioOn(): service connection not yet established!"); 15380966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly return false; 15390966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } 1540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mConnectedSco != null) { 1542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("audioOn(): audio is already connected"); 1543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return true; 1544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!mUserWantsAudio) { 1547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("audioOn(): user requested no audio, ignoring"); 1548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 1549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1551f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan if (mPendingSco) { 1552f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan if (DBG) log("audioOn(): SCO already pending"); 1553f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan return true; 1554f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 1555f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan 1556ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mA2dpSuspended = false; 1557ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mPendingSco = false; 1558f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan if (isA2dpMultiProfile() && mA2dpState == BluetoothA2dp.STATE_PLAYING) { 1559f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan if (DBG) log("suspending A2DP stream for SCO"); 1560ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mA2dpSuspended = mA2dp.suspendSink(mA2dpDevice); 1561ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (mA2dpSuspended) { 1562ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mPendingSco = true; 1563f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan Message msg = mHandler.obtainMessage(MESSAGE_CHECK_PENDING_SCO); 1564f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mHandler.sendMessageDelayed(msg, 2000); 1565f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } else { 1566f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan Log.w(TAG, "Could not suspend A2DP stream for SCO, going ahead with SCO"); 1567337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly } 1568337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly } 1569337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly 1570337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly if (!mPendingSco) { 157191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang connectScoThread(); 1572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return true; 1575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Used to indicate the user requested BT audio on. 1578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * This will establish SCO (BT audio), even if the user requested it off 1579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * previously on this call. 1580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 1581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized void userWantsAudioOn() { 1582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mUserWantsAudio = true; 1583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 1584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Used to indicate the user requested BT audio off. 1586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * This will prevent us from establishing BT audio again during this call 1587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * if audioOn() is called. 1588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 1589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized void userWantsAudioOff() { 1590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mUserWantsAudio = false; 1591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOff(); 1592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Request to disconnect SCO (audio) connection to bluetooth 1595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * headset/handsfree, if one is connected. Does not block. 1596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 1597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized void audioOff() { 1598819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh if (VDBG) log("audioOff(): mPendingSco: " + mPendingSco + 1599819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh ", mConnectedSco: " + mConnectedSco + 1600819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh ", mA2dpState: " + mA2dpState + 160191b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang ", mA2dpSuspended: " + mA2dpSuspended); 1602ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent 1603ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent if (mA2dpSuspended) { 1604a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent if (isA2dpMultiProfile()) { 160591b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (DBG) log("resuming A2DP stream after disconnecting SCO"); 160691b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang mA2dp.resumeSink(mA2dpDevice); 1607a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent } 1608ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent mA2dpSuspended = false; 1609ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent } 1610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1611310e6fb854504637a4cefd123d8dd387660cf811Nick Pelly mPendingSco = false; 1612310e6fb854504637a4cefd123d8dd387660cf811Nick Pelly 161391b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang if (mSignalScoCloseThread != null) { 1614e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent mSignalScoCloseThread.shutdown(); 1615e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent mSignalScoCloseThread = null; 1616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 161791b4c99be8dbdd8fca6b76a0e34e8a4b989b2b87Danica Chang 161843d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // Sync with setting mConnectScoThread to null to assure the validity of 161943d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie // the condition 162043d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie synchronized (ScoSocketConnectThread.class) { 162143d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie if (mConnectScoThread != null) { 162243d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie mConnectScoThread.shutdown(); 162343d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie resetConnectScoThread(); 162443d59ddb900224b9f6e9df6e3cfda6174fb57507Matthew Xie } 1625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1626819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh 1627e5d4f38445a097390b72c53b40f86e126c0cd75eEric Laurent closeConnectedSco(); // Should be closed already, but just in case 1628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ boolean isAudioOn() { 1631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return (mConnectedSco != null); 1632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1634f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan private boolean isA2dpMultiProfile() { 1635f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan return mA2dp != null && mHeadset != null && mA2dpDevice != null && 1636f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan mA2dpDevice.equals(mHeadset.getRemoteDevice()); 1637f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan } 1638f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan 1639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ void ignoreRing() { 16401dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState.ignoreRing(); 1641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1643eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh private void sendURC(String urc) { 1644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (isHeadsetConnected()) { 1645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mHeadset.sendURC(urc); 1646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** helper to redial last dialled number */ 1650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private AtCommandResult redial() { 1651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String number = mPhonebook.getLastDialledNumber(); 1652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number == null) { 1653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // spec seems to suggest sending ERROR if we dont have a 1654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // number to redial 16558eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Bluetooth redial requested (+BLDN), but no previous " + 1656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "outgoing calls found. Ignoring"); 1657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 1658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1659b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Outgoing call initiated by the handsfree device 1660a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh // Send terminateScoUsingVirtualVoiceCall 1661a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh terminateScoUsingVirtualVoiceCall(); 1662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, 166365454c803eb305c4740885ad4995a871b034a58aDavid Brown Uri.fromParts(Constants.SCHEME_TEL, number, null)); 1664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mContext.startActivity(intent); 1666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // We do not immediately respond OK, wait until we get a phone state 1668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // update. If we return OK now and the handsfree immeidately requests 1669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // our phone state it will say we are not in call yet which confuses 1670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // some devices 1671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project expectCallStart(); 1672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.UNSOLICITED); // send nothing 1673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Build the +CLCC result 1676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * The complexity arises from the fact that we need to maintain the same 1677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * CLCC index even as a call moves between states. */ 1678c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private synchronized AtCommandResult gsmGetClccResult() { 1679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Collect all known connections 1680c9d9ed30aa547b79b81adc13a4d148a003b6ee62w Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS]; // indexed by CLCC index 1681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project LinkedList<Connection> newConnections = new LinkedList<Connection>(); 1682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project LinkedList<Connection> connections = new LinkedList<Connection>(); 1683a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang 16848058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call foregroundCall = mCM.getActiveFgCall(); 16858058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call backgroundCall = mCM.getFirstActiveBgCall(); 16868058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call ringingCall = mCM.getFirstActiveRingingCall(); 16878058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang 16888058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (ringingCall.getState().isAlive()) { 16898058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang connections.addAll(ringingCall.getConnections()); 1690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 16918058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (foregroundCall.getState().isAlive()) { 16928058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang connections.addAll(foregroundCall.getConnections()); 1693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 16948058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (backgroundCall.getState().isAlive()) { 16958058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang connections.addAll(backgroundCall.getConnections()); 1696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Mark connections that we already known about 1699c9d9ed30aa547b79b81adc13a4d148a003b6ee62w boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS]; 1700c9d9ed30aa547b79b81adc13a4d148a003b6ee62w for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) { 1701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project clccUsed[i] = mClccUsed[i]; 1702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClccUsed[i] = false; 1703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project for (Connection c : connections) { 1705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean found = false; 1706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project long timestamp = c.getCreateTime(); 1707c9d9ed30aa547b79b81adc13a4d148a003b6ee62w for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) { 1708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (clccUsed[i] && timestamp == mClccTimestamps[i]) { 1709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClccUsed[i] = true; 1710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project found = true; 1711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project clccConnections[i] = c; 1712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!found) { 1716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project newConnections.add(c); 1717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Find a CLCC index for new connections 1721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project while (!newConnections.isEmpty()) { 1722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Find lowest empty index 1723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int i = 0; 1724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project while (mClccUsed[i]) i++; 1725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Find earliest connection 1726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project long earliestTimestamp = newConnections.get(0).getCreateTime(); 1727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Connection earliestConnection = newConnections.get(0); 1728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project for (int j = 0; j < newConnections.size(); j++) { 1729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project long timestamp = newConnections.get(j).getCreateTime(); 1730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (timestamp < earliestTimestamp) { 1731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project earliestTimestamp = timestamp; 1732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project earliestConnection = newConnections.get(j); 1733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // update 1737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClccUsed[i] = true; 1738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClccTimestamps[i] = earliestTimestamp; 1739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project clccConnections[i] = earliestConnection; 1740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project newConnections.remove(earliestConnection); 1741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Build CLCC 1744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.OK); 1745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project for (int i = 0; i < clccConnections.length; i++) { 1746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mClccUsed[i]) { 1747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String clccEntry = connectionToClccEntry(i, clccConnections[i]); 1748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (clccEntry != null) { 1749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse(clccEntry); 1750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 1755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Convert a Connection object into a single +CLCC result */ 1758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private String connectionToClccEntry(int index, Connection c) { 1759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int state; 1760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (c.getState()) { 1761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case ACTIVE: 1762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 0; 1763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case HOLDING: 1765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 1; 1766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case DIALING: 1768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 2; 1769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case ALERTING: 1771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 3; 1772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case INCOMING: 1774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 4; 1775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case WAITING: 1777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project state = 5; 1778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 1779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project default: 1780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return null; // bad state 1781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int mpty = 0; 1784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Call call = c.getCall(); 1785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (call != null) { 1786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mpty = call.isMultiparty() ? 1 : 0; 1787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int direction = c.isIncoming() ? 1 : 0; 1790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String number = c.getAddress(); 1792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int type = -1; 1793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number != null) { 1794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project type = PhoneNumberUtils.toaFromString(number); 1795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty; 1798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number != null) { 1799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result += ",\"" + number + "\"," + type; 1800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 1802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 1803c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1804c9d9ed30aa547b79b81adc13a4d148a003b6ee62w /** Build the +CLCC result for CDMA 1805c9d9ed30aa547b79b81adc13a4d148a003b6ee62w * The complexity arises from the fact that we need to maintain the same 1806c9d9ed30aa547b79b81adc13a4d148a003b6ee62w * CLCC index even as a call moves between states. */ 1807c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private synchronized AtCommandResult cdmaGetClccResult() { 1808c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // In CDMA at one time a user can have only two live/active connections 1809c9d9ed30aa547b79b81adc13a4d148a003b6ee62w Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index 18108058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call foregroundCall = mCM.getActiveFgCall(); 18118058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call ringingCall = mCM.getFirstActiveRingingCall(); 1812c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 18138058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call.State ringingCallState = ringingCall.getState(); 1814c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // If the Ringing Call state is INCOMING, that means this is the very first call 1815c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // hence there should not be any Foreground Call 1816c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (ringingCallState == Call.State.INCOMING) { 18178eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Filling clccConnections[0] for INCOMING state"); 18188058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[0] = ringingCall.getLatestConnection(); 18198058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang } else if (foregroundCall.getState().isAlive()) { 1820c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Getting Foreground Call connection based on Call state 18218058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (ringingCall.isRinging()) { 18228eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state"); 18238058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[0] = foregroundCall.getEarliestConnection(); 18248058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[1] = ringingCall.getLatestConnection(); 1825c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else { 18268058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (foregroundCall.getConnections().size() <= 1) { 1827c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Single call scenario 18288eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Filling clccConnections[0] with ForgroundCall latest connection"); 18298058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[0] = foregroundCall.getLatestConnection(); 1830c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else { 1831c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Multiple Call scenario. This would be true for both 1832c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // CONF_CALL and THRWAY_ACTIVE state 18338eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Filling clccConnections[0] & [1] with ForgroundCall connections"); 18348058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[0] = foregroundCall.getEarliestConnection(); 18358058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang clccConnections[1] = foregroundCall.getLatestConnection(); 1836c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1837c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1838c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1839c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1840c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Update the mCdmaIsSecondCallActive flag based on the Phone call state 1841c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState() 1842c9d9ed30aa547b79b81adc13a4d148a003b6ee62w == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) { 1843c9d9ed30aa547b79b81adc13a4d148a003b6ee62w cdmaSetSecondCallState(false); 1844c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState() 1845c9d9ed30aa547b79b81adc13a4d148a003b6ee62w == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 1846c9d9ed30aa547b79b81adc13a4d148a003b6ee62w cdmaSetSecondCallState(true); 1847c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1848c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1849c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Build CLCC 1850c9d9ed30aa547b79b81adc13a4d148a003b6ee62w AtCommandResult result = new AtCommandResult(AtCommandResult.OK); 1851c9d9ed30aa547b79b81adc13a4d148a003b6ee62w for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) { 1852c9d9ed30aa547b79b81adc13a4d148a003b6ee62w String clccEntry = cdmaConnectionToClccEntry(i, clccConnections[i]); 1853c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (clccEntry != null) { 1854c9d9ed30aa547b79b81adc13a4d148a003b6ee62w result.addResponse(clccEntry); 1855c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1856c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1857c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1858c9d9ed30aa547b79b81adc13a4d148a003b6ee62w return result; 1859c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1860c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1861c9d9ed30aa547b79b81adc13a4d148a003b6ee62w /** Convert a Connection object into a single +CLCC result for CDMA phones */ 1862c9d9ed30aa547b79b81adc13a4d148a003b6ee62w private String cdmaConnectionToClccEntry(int index, Connection c) { 1863c9d9ed30aa547b79b81adc13a4d148a003b6ee62w int state; 1864c9d9ed30aa547b79b81adc13a4d148a003b6ee62w PhoneApp app = PhoneApp.getInstance(); 1865c9d9ed30aa547b79b81adc13a4d148a003b6ee62w CdmaPhoneCallState.PhoneCallState currCdmaCallState = 1866c9d9ed30aa547b79b81adc13a4d148a003b6ee62w app.cdmaPhoneCallState.getCurrentCallState(); 1867c9d9ed30aa547b79b81adc13a4d148a003b6ee62w CdmaPhoneCallState.PhoneCallState prevCdmaCallState = 1868c9d9ed30aa547b79b81adc13a4d148a003b6ee62w app.cdmaPhoneCallState.getPreviousCallState(); 1869c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1870c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) 1871c9d9ed30aa547b79b81adc13a4d148a003b6ee62w && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) { 1872c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // If the current state is reached after merging two calls 1873c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // we set the state of all the connections as ACTIVE 1874c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 0; 1875c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else { 1876c9d9ed30aa547b79b81adc13a4d148a003b6ee62w switch (c.getState()) { 1877c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case ACTIVE: 1878c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // For CDMA since both the connections are set as active by FW after accepting 1879c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // a Call waiting or making a 3 way call, we need to set the state specifically 1880c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the 1881c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // CLCC result will allow BT devices to enable the swap or merge options 1882c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (index == 0) { // For the 1st active connection 1883c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = mCdmaIsSecondCallActive ? 1 : 0; 1884c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else { // for the 2nd active connection 1885c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = mCdmaIsSecondCallActive ? 0 : 1; 1886c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1887c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1888c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case HOLDING: 1889c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 1; 1890c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1891c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case DIALING: 1892c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 2; 1893c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1894c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case ALERTING: 1895c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 3; 1896c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1897c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case INCOMING: 1898c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 4; 1899c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1900c9d9ed30aa547b79b81adc13a4d148a003b6ee62w case WAITING: 1901c9d9ed30aa547b79b81adc13a4d148a003b6ee62w state = 5; 1902c9d9ed30aa547b79b81adc13a4d148a003b6ee62w break; 1903c9d9ed30aa547b79b81adc13a4d148a003b6ee62w default: 1904c9d9ed30aa547b79b81adc13a4d148a003b6ee62w return null; // bad state 1905c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1906c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1907c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1908c9d9ed30aa547b79b81adc13a4d148a003b6ee62w int mpty = 0; 19093eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) { 1910c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 1911c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // If the current state is reached after merging two calls 1912c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // we set the multiparty call true. 1913c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi mpty = 1; 1914c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi } else { 1915c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // CALL_CONF state is not from merging two calls, but from 1916c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // accepting the second call. In this case first will be on 1917c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // hold in most cases but in some cases its already merged. 1918c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // However, we will follow the common case and the test case 1919c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi // as per Bluetooth SIG PTS 1920c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi mpty = 0; 1921c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi } 19223eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu } else { 19233eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu mpty = 0; 1924c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1925c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1926c9d9ed30aa547b79b81adc13a4d148a003b6ee62w int direction = c.isIncoming() ? 1 : 0; 1927c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1928c9d9ed30aa547b79b81adc13a4d148a003b6ee62w String number = c.getAddress(); 1929c9d9ed30aa547b79b81adc13a4d148a003b6ee62w int type = -1; 1930c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (number != null) { 1931c9d9ed30aa547b79b81adc13a4d148a003b6ee62w type = PhoneNumberUtils.toaFromString(number); 1932c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1933c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 1934c9d9ed30aa547b79b81adc13a4d148a003b6ee62w String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty; 1935c9d9ed30aa547b79b81adc13a4d148a003b6ee62w if (number != null) { 1936c9d9ed30aa547b79b81adc13a4d148a003b6ee62w result += ",\"" + number + "\"," + type; 1937c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1938c9d9ed30aa547b79b81adc13a4d148a003b6ee62w return result; 1939c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 1940c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 19411498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek /* 19421498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * Register a vendor-specific command. 19431498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * @param commandName the name of the command. For example, if the expected 19441498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * incoming command is <code>AT+FOO=bar,baz</code>, the value of this should be 19451498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * <code>"+FOO"</code>. 19461498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * @param companyId the Bluetooth SIG Company Identifier 19471498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * @param parser the AtParser on which to register the command 19481498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek */ 19491498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private void registerVendorSpecificCommand(String commandName, 19501498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek int companyId, 19511498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek AtParser parser) { 19521498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek parser.register(commandName, 19531498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek new VendorSpecificCommandHandler(commandName, companyId)); 19541498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 19551498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 19561498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek /* 19571498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * Register all vendor-specific commands here. 19581498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek */ 19591498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private void registerAllVendorSpecificCommands() { 19601498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek AtParser parser = mHeadset.getAtParser(); 19611498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 19621498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek // Plantronics-specific headset events go here 19631498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek registerVendorSpecificCommand("+XEVENT", 19641498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek BluetoothAssignedNumbers.PLANTRONICS, 19651498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek parser); 19661498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 19671498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 1968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 1969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Register AT Command handlers to implement the Headset profile 1970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 1971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private void initializeHeadsetAtParser() { 19728eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Registering Headset AT commands"); 1973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtParser parser = mHeadset.getAtParser(); 19741498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek // Headsets usually only have one button, which is meant to cause the 1975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // HS to send us AT+CKPD=200 or AT+CKPD. 1976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CKPD", new AtCommandHandler() { 1977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private AtCommandResult headsetButtonPress() { 1978eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh if (mCM.getFirstActiveRingingCall().isRinging()) { 1979eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // Answer the call 1980eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh mBluetoothPhoneState.stopRing(); 1981eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh sendURC("OK"); 1982eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh PhoneUtils.answerCall(mCM.getFirstActiveRingingCall()); 1983eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // If in-band ring tone is supported, SCO connection will already 1984eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // be up and the following call will just return. 1985eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh audioOn(); 19861ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh return new AtCommandResult(AtCommandResult.UNSOLICITED); 1987eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh } else if (mCM.hasActiveFgCall()) { 1988eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh if (!isAudioOn()) { 1989eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // Transfer audio from AG to HS 1990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 1991eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh } else { 1992eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh if (mHeadset.getDirection() == HeadsetBase.DIRECTION_INCOMING && 1993eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh (System.currentTimeMillis() - mHeadset.getConnectTimestamp()) < 5000) { 1994eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // Headset made a recent ACL connection to us - and 1995eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // made a mandatory AT+CKPD request to connect 1996eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // audio which races with our automatic audio 1997eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // setup. ignore 1998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 1999eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // Hang up the call 2000eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh audioOff(); 2001eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh PhoneUtils.hangup(PhoneApp.getInstance().mCM); 2002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2004eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh return new AtCommandResult(AtCommandResult.OK); 2005eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh } else { 2006eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh // No current call - redial last number 2007eeab0c52a0542179621ee7854d7913cfd2445429Jaikumar Ganesh return redial(); 2008b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return headsetButtonPress(); 2013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return headsetButtonPress(); 2017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 2022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Register AT Command handlers to implement the Handsfree profile 2023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 2024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private void initializeHandsfreeAtParser() { 20258eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("Registering Handsfree AT commands"); 2026b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtParser parser = mHeadset.getAtParser(); 20278058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang final Phone phone = mCM.getDefaultPhone(); 2028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Answer 2030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register('A', new AtCommandHandler() { 2031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleBasicCommand(String args) { 20331ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh sendURC("OK"); 20341ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh mBluetoothPhoneState.stopRing(); 20358058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PhoneUtils.answerCall(mCM.getFirstActiveRingingCall()); 20361ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh return new AtCommandResult(AtCommandResult.UNSOLICITED); 2037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register('D', new AtCommandHandler() { 2040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleBasicCommand(String args) { 2042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length() > 0) { 2043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.charAt(0) == '>') { 2044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Yuck - memory dialling requested. 2045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Just dial last number for now 2046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.startsWith(">9999")) { // for PTS test 2047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return redial(); 2050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2051a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh // Send terminateScoUsingVirtualVoiceCall 2052a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh terminateScoUsingVirtualVoiceCall(); 2053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Remove trailing ';' 2054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.charAt(args.length() - 1) == ';') { 2055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project args = args.substring(0, args.length() - 1); 2056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2057eccbc2aa0b0a719bcadcdba5e1aeb22a5814d08ainshik 2058eccbc2aa0b0a719bcadcdba5e1aeb22a5814d08ainshik args = PhoneNumberUtils.convertPreDial(args); 2059eccbc2aa0b0a719bcadcdba5e1aeb22a5814d08ainshik 2060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, 206165454c803eb305c4740885ad4995a871b034a58aDavid Brown Uri.fromParts(Constants.SCHEME_TEL, args, null)); 2062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2063b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mContext.startActivity(intent); 2064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project expectCallStart(); 2066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.UNSOLICITED); // send nothing 2067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Hang-up command 2074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CHUP", new AtCommandHandler() { 2075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2077586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh sendURC("OK"); 2078b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (isVirtualCallInProgress()) { 2079a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh terminateScoUsingVirtualVoiceCall(); 2080b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } else { 2081b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (mCM.hasActiveFgCall()) { 2082b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh PhoneUtils.hangupActiveCall(mCM.getActiveFgCall()); 2083b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } else if (mCM.hasActiveRingingCall()) { 2084b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall()); 2085b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } else if (mCM.hasActiveBgCall()) { 2086b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall()); 2087b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2089586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh return new AtCommandResult(AtCommandResult.UNSOLICITED); 2090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Bluetooth Retrieve Supported Features command 2094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+BRSF", new AtCommandHandler() { 2095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private AtCommandResult sendBRSF() { 2096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+BRSF: " + mLocalBrsf); 2097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+BRSF=<handsfree supported features bitmap> 2101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Handsfree is telling us which features it supports. We 2102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // send the features we support 2103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length == 1 && (args[0] instanceof Integer)) { 2104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mRemoteBrsf = (Integer) args[0]; 2105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.w(TAG, "HF didn't sent BRSF assuming 0"); 2107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return sendBRSF(); 2109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // This seems to be out of spec, but lets do the nice thing 2113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return sendBRSF(); 2114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // This seems to be out of spec, but lets do the nice thing 2118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return sendBRSF(); 2119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Call waiting notification on/off 2123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CCWA", new AtCommandHandler() { 2124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Seems to be out of spec, but lets return nicely 2127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Call waiting is always on 2132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CCWA: 1"); 2133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CCWA=<n> 2137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Handsfree is trying to enable/disable call waiting. We 2138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // cannot disable in the current implementation. 2139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 2143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Request for range of supported CCWA paramters 2144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CCWA: (\"n\",(1))"); 2145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Mobile Equipment Event Reporting enable/disable command 2149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Of the full 3GPP syntax paramters (mode, keyp, disp, ind, bfr) we 2150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // only support paramter ind (disable/enable evert reporting using 2151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // +CDEV) 2152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CMER", new AtCommandHandler() { 2153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult( 2156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "+CMER: 3,0,0," + (mIndicatorsEnabled ? "1" : "0")); 2157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length < 4) { 2161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // This is a syntax error 2162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[0].equals(3) && args[1].equals(0) && 2164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project args[2].equals(0)) { 21650966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly boolean valid = false; 2166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args[3].equals(0)) { 2167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mIndicatorsEnabled = false; 21680966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly valid = true; 2169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[3].equals(1)) { 2170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mIndicatorsEnabled = true; 21710966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly valid = true; 21720966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } 21730966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if (valid) { 21740966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) == 0x0) { 21750966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly mServiceConnectionEstablished = true; 21760966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly sendURC("OK"); // send immediately, then initiate audio 21770966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if (isIncallAudio()) { 21780966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly audioOn(); 217934a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi } else if (mCM.getFirstActiveRingingCall().isRinging()) { 218034a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi // need to update HS with RING cmd when single 218134a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi // ringing call exist 218234a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi mBluetoothPhoneState.ring(); 21830966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } 21840966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly // only send OK once 21850966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly return new AtCommandResult(AtCommandResult.UNSOLICITED); 21860966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } else { 21870966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly return new AtCommandResult(AtCommandResult.OK); 21880966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } 2189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 21910966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED); 2192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 2195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CMER: (3),(0),(0),(0-1)"); 2196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Mobile Equipment Error Reporting enable/disable 2200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CMEE", new AtCommandHandler() { 2201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // out of spec, assume they want to enable 2204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCmee = true; 2205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CMEE: " + (mCmee ? "1" : "0")); 2210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CMEE=<n> 2214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length == 0) { 2215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // <n> ommitted - default to 0 2216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCmee = false; 2217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (!(args[0] instanceof Integer)) { 2219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Syntax error 2220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mCmee = ((Integer)args[0] == 1); 2223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 2228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Probably not required but spec, but no harm done 2229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CMEE: (0-1)"); 2230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Bluetooth Last Dialled Number 2234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+BLDN", new AtCommandHandler() { 2235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return redial(); 2238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Indicator Update command 2242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CIND", new AtCommandHandler() { 2243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 22451dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh return mBluetoothPhoneState.toCindResult(); 2246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 22491dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh return mBluetoothPhoneState.getCindTestResult(); 2250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Query Signal Quality (legacy) 2254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CSQ", new AtCommandHandler() { 2255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 22571dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh return mBluetoothPhoneState.toCsqResult(); 2258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Query network registration state 2262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CREG", new AtCommandHandler() { 2263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 22651dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh return new AtCommandResult(mBluetoothPhoneState.toCregString()); 2266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Send DTMF. I don't know if we are also expected to play the DTMF tone 2270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // locally, right now we don't 2271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+VTS", new AtCommandHandler() { 2272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length >= 1) { 2275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project char c; 2276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args[0] instanceof Integer) { 2277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project c = ((Integer) args[0]).toString().charAt(0); 2278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project c = ((String) args[0]).charAt(0); 2280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (isValidDtmf(c)) { 22828058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang phone.sendDtmf(c); 2283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean isValidDtmf(char c) { 2289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (c) { 2290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case '#': 2291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case '*': 2292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return true; 2293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project default: 2294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (Character.digit(c, 14) != -1) { 2295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return true; // 0-9 and A-D 2296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 2298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // List calls 2303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CLCC", new AtCommandHandler() { 2304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 23068058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang int phoneType = phone.getPhoneType(); 2307b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Handsfree carkits expect that +CLCC is properly responded to. 2308b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Hence we ensure that a proper response is sent for the virtual call too. 2309b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (isVirtualCallInProgress()) { 2310b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh String number = phone.getLine1Number(); 2311b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh AtCommandResult result = new AtCommandResult(AtCommandResult.OK); 2312b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh String args; 2313b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (number == null) { 2314b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh args = "+CLCC: 1,0,0,0,0,\"\",0"; 2315b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2316b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh else 2317b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh { 2318b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh args = "+CLCC: 1,0,0,0,0,\"" + number + "\"," + 2319b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh PhoneNumberUtils.toaFromString(number); 2320b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2321b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh result.addResponse(args); 2322b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return result; 2323b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 232479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink if (phoneType == Phone.PHONE_TYPE_CDMA) { 2325c9d9ed30aa547b79b81adc13a4d148a003b6ee62w return cdmaGetClccResult(); 232679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else if (phoneType == Phone.PHONE_TYPE_GSM) { 2327c9d9ed30aa547b79b81adc13a4d148a003b6ee62w return gsmGetClccResult(); 232879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else { 232979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink throw new IllegalStateException("Unexpected phone type: " + phoneType); 2330c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 2331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Call Hold and Multiparty Handling command 2335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CHLD", new AtCommandHandler() { 2336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 23388058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang int phoneType = phone.getPhoneType(); 23398058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call ringingCall = mCM.getFirstActiveRingingCall(); 23408058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang Call backgroundCall = mCM.getFirstActiveBgCall(); 23418058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang 2342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length >= 1) { 2343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args[0].equals(0)) { 2344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean result; 23458058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (ringingCall.isRinging()) { 23468058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang result = PhoneUtils.hangupRingingCall(ringingCall); 2347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 23488058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang result = PhoneUtils.hangupHoldingCall(backgroundCall); 2349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (result) { 2351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[0].equals(1)) { 235679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink if (phoneType == Phone.PHONE_TYPE_CDMA) { 23578058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (ringingCall.isRinging()) { 235891f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh // Hangup the active call and then answer call waiting call. 23598eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("CHLD:1 Callwaiting Answer call"); 2360ba2b1409db0b7f7901bd30c238f7a63c72dc0a35jhtop.kim PhoneUtils.hangupRingingAndActive(phone); 2361c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else { 2362c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // If there is no Call waiting then just hangup 2363c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // the active call. In CDMA this mean that the complete 2364c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // call session would be ended 23658eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("CHLD:1 Hangup Call"); 23668343169cc89621d46dce86449f5ee1ff5d3a4919John Wang PhoneUtils.hangup(PhoneApp.getInstance().mCM); 2367c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 2368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 236979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else if (phoneType == Phone.PHONE_TYPE_GSM) { 2370a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman // Hangup active call, answer held call 23718343169cc89621d46dce86449f5ee1ff5d3a4919John Wang if (PhoneUtils.answerAndEndActive( 23728058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PhoneApp.getInstance().mCM, ringingCall)) { 2373a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman return new AtCommandResult(AtCommandResult.OK); 2374a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman } else { 2375a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman return new AtCommandResult(AtCommandResult.ERROR); 2376a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman } 237779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else { 237879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink throw new IllegalStateException("Unexpected phone type: " + phoneType); 2379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[0].equals(2)) { 238191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh sendURC("OK"); 238279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink if (phoneType == Phone.PHONE_TYPE_CDMA) { 2383a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman // For CDMA, the way we switch to a new incoming call is by 2384a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman // calling PhoneUtils.answerCall(). switchAndHoldActive() won't 2385a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman // properly update the call state within telephony. 2386c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // If the Phone state is already in CONF_CALL then we simply send 2387c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // a flash cmd by calling switchHoldingAndActive() 23888058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (ringingCall.isRinging()) { 23898eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("CHLD:2 Callwaiting Answer call"); 23908058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PhoneUtils.answerCall(ringingCall); 2391a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang PhoneUtils.setMute(false); 2392c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Setting the second callers state flag to TRUE (i.e. active) 2393c9d9ed30aa547b79b81adc13a4d148a003b6ee62w cdmaSetSecondCallState(true); 2394c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } else if (PhoneApp.getInstance().cdmaPhoneCallState 2395c9d9ed30aa547b79b81adc13a4d148a003b6ee62w .getCurrentCallState() 2396c9d9ed30aa547b79b81adc13a4d148a003b6ee62w == CdmaPhoneCallState.PhoneCallState.CONF_CALL) { 23978eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("CHLD:2 Swap Calls"); 23988058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PhoneUtils.switchHoldingAndActive(backgroundCall); 2399c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // Toggle the second callers active state flag 2400c9d9ed30aa547b79b81adc13a4d148a003b6ee62w cdmaSwapSecondCallState(); 2401c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 240279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else if (phoneType == Phone.PHONE_TYPE_GSM) { 24038058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang PhoneUtils.switchHoldingAndActive(backgroundCall); 240479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else { 240579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink throw new IllegalStateException("Unexpected phone type: " + phoneType); 2406a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman } 240791f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh return new AtCommandResult(AtCommandResult.UNSOLICITED); 2408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[0].equals(3)) { 240991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh sendURC("OK"); 241079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink if (phoneType == Phone.PHONE_TYPE_CDMA) { 241191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh CdmaPhoneCallState.PhoneCallState state = 241291f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState(); 2413c9d9ed30aa547b79b81adc13a4d148a003b6ee62w // For CDMA, we need to check if the call is in THRWAY_ACTIVE state 241491f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh if (state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) { 24158eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("CHLD:3 Merge Calls"); 2416b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan PhoneUtils.mergeCalls(); 241791f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } else if (state == CdmaPhoneCallState.PhoneCallState.CONF_CALL) { 241891f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh // State is CONF_CALL already and we are getting a merge call 241991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh // This can happen when CONF_CALL was entered from a Call Waiting 242091f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mBluetoothPhoneState.updateCallHeld(); 2421c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 242279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else if (phoneType == Phone.PHONE_TYPE_GSM) { 24238058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang if (mCM.hasActiveFgCall() && mCM.hasActiveBgCall()) { 2424b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan PhoneUtils.mergeCalls(); 2425c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 242679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink } else { 242779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink throw new IllegalStateException("Unexpected phone type: " + phoneType); 2428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 242991f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh return new AtCommandResult(AtCommandResult.UNSOLICITED); 2430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 24360966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly mServiceConnectionEstablished = true; 2437d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly sendURC("+CHLD: (0,1,2,3)"); 2438d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly sendURC("OK"); // send reply first, then connect audio 24390966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly if (isIncallAudio()) { 24400966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly audioOn(); 244134a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi } else if (mCM.getFirstActiveRingingCall().isRinging()) { 244234a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi // need to update HS with RING when single ringing call exist 244334a30a05feb48e56b8f6d5e05d9d58ce649bfdd1Srinivas Krovvidi mBluetoothPhoneState.ring(); 24440966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly } 24450966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly // already replied 24460966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly return new AtCommandResult(AtCommandResult.UNSOLICITED); 2447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Get Network operator name 2451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+COPS", new AtCommandHandler() { 2452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 24548058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang String operatorName = phone.getServiceState().getOperatorAlphaLong(); 2455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (operatorName != null) { 2456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (operatorName.length() > 16) { 2457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project operatorName = operatorName.substring(0, 16); 2458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult( 2460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "+COPS: 0,0,\"" + operatorName + "\""); 2461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult( 24635b58955238953dd3c689b1d1342cb9d79ec3e9deJesper Hansson "+COPS: 0"); 2464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Handsfree only supports AT+COPS=3,0 2469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length != 2 || !(args[0] instanceof Integer) 2470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project || !(args[1] instanceof Integer)) { 2471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // syntax error 2472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if ((Integer)args[0] != 3 || (Integer)args[1] != 0) { 2474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED); 2475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 2481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Out of spec, but lets be friendly 2482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+COPS: (3),(0)"); 2483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Mobile PIN 2487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CPIN is not in the handsfree spec (although it is in 3GPP) 2488b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CPIN", new AtCommandHandler() { 2489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CPIN: READY"); 2492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2494b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Bluetooth Response and Hold 2496b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Only supported on PDC (Japan) and CDMA networks. 2497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+BTRH", new AtCommandHandler() { 2498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Replying with just OK indicates no response and hold 2501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // features in use now 2502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2503b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2504b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2505b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2506b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Neeed PDC or CDMA 2507b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2508b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2509b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2511b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Request International Mobile Subscriber Identity (IMSI) 2512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Not in bluetooth handset spec 2513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CIMI", new AtCommandHandler() { 2514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2515b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CIMI 25178058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang String imsi = phone.getSubscriberId(); 2518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (imsi == null || imsi.length() == 0) { 2519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return reportCmeError(BluetoothCmeError.SIM_FAILURE); 2520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(imsi); 2522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Calling Line Identification Presentation 2527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CLIP", new AtCommandHandler() { 2528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleReadCommand() { 2530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Currently assumes the network is provisioned for CLIP 2531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CLIP: " + (mClip ? "1" : "0") + ",1"); 2532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CLIP=<n> 2536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length >= 1 && (args[0].equals(0) || args[0].equals(1))) { 2537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mClip = args[0].equals(1); 2538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 2545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CLIP: (0-1)"); 2546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CGSN - Returns the device IMEI number. 2550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CGSN", new AtCommandHandler() { 2551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Get the IMEI of the device. 25548058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang // phone will not be NULL at this point. 25558058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang return new AtCommandResult("+CGSN: " + phone.getDeviceId()); 2556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CGMM - Query Model Information 2560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CGMM", new AtCommandHandler() { 2561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Return the Model Information. 2564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String model = SystemProperties.get("ro.product.model"); 2565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (model != null) { 2566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CGMM: " + model); 2567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+CGMI - Query Manufacturer Information 2574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CGMI", new AtCommandHandler() { 2575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Return the Model Information. 2578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String manuf = SystemProperties.get("ro.product.manufacturer"); 2579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (manuf != null) { 2580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CGMI: " + manuf); 2581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Noise Reduction and Echo Cancellation control 2588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+NREC", new AtCommandHandler() { 2589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args[0].equals(0)) { 2592aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent mAudioManager.setParameters(HEADSET_NREC+"=off"); 2593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args[0].equals(1)) { 2595aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent mAudioManager.setParameters(HEADSET_NREC+"=on"); 2596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Voice recognition (dialing) 2603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+BVRA", new AtCommandHandler() { 2604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2606b8dbab241df3aa3487c1bdb488fd4e0b694d2d9aEric Laurent if (!BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) { 26076967e2d953bc077c99c4831946201f3d333b833fNick Pelly return new AtCommandResult(AtCommandResult.ERROR); 26086967e2d953bc077c99c4831946201f3d333b833fNick Pelly } 2609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length >= 1 && args[0].equals(1)) { 2610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project synchronized (BluetoothHandsfree.this) { 26111c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent if (!isVoiceRecognitionInProgress() && 2612eb1d4e290a13b55430960fd7ba58404608f10593Eric Laurent !isCellularCallInProgress() && 2613eb1d4e290a13b55430960fd7ba58404608f10593Eric Laurent !isVirtualCallInProgress()) { 2614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project try { 2615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mContext.startActivity(sVoiceCommandIntent); 2616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } catch (ActivityNotFoundException e) { 2617b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project expectVoiceRecognition(); 2620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.UNSOLICITED); // send nothing yet 2623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (args.length >= 1 && args[0].equals(0)) { 26241c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent if (isVoiceRecognitionInProgress()) { 26251c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent audioOff(); 26261c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent } 2627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleTestCommand() { 26336967e2d953bc077c99c4831946201f3d333b833fNick Pelly return new AtCommandResult("+BVRA: (0-1)"); 2634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Retrieve Subscriber Number 2638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CNUM", new AtCommandHandler() { 2639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 26418058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang String number = phone.getLine1Number(); 2642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (number == null) { 2643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CNUM: ,\"" + number + "\"," + 2646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project PhoneNumberUtils.toaFromString(number) + ",,4"); 2647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Microphone Gain 2651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+VGM", new AtCommandHandler() { 2652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+VGM=<gain> in range [0,15] 2655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Headset/Handsfree is reporting its current gain setting 2656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Speaker Gain 2661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+VGS", new AtCommandHandler() { 2662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleSetCommand(Object[] args) { 2664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AT+VGS=<gain> in range [0,15] 2665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (args.length != 1 || !(args[0] instanceof Integer)) { 2666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mScoGain = (Integer) args[0]; 2669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int flag = mAudioManager.isBluetoothScoOn() ? AudioManager.FLAG_SHOW_UI:0; 2670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, mScoGain, flag); 2672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.OK); 2673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 2675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Phone activity status 2677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project parser.register("+CPAS", new AtCommandHandler() { 2678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult handleActionCommand() { 2680b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int status = 0; 26818058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang switch (mCM.getState()) { 2682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case IDLE: 2683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project status = 0; 2684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 2685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case RINGING: 2686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project status = 3; 2687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 2688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case OFFHOOK: 2689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project status = 4; 2690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 2691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult("+CPAS: " + status); 2693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }); 26951498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 2696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mPhonebook.register(parser); 2697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void sendScoGainUpdate(int gain) { 2700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mScoGain != gain && (mRemoteBrsf & BRSF_HF_REMOTE_VOL_CONTROL) != 0x0) { 2701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("+VGS:" + gain); 2702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mScoGain = gain; 2703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public AtCommandResult reportCmeError(int error) { 2707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mCmee) { 2708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 2709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+CME ERROR: " + error); 2710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return result; 2711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return new AtCommandResult(AtCommandResult.ERROR); 2713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int START_CALL_TIMEOUT = 10000; // ms 2717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void expectCallStart() { 2719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mWaitingForCallStart = true; 2720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Message msg = Message.obtain(mHandler, CHECK_CALL_STARTED); 2721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mHandler.sendMessageDelayed(msg, START_CALL_TIMEOUT); 2722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!mStartCallWakeLock.isHeld()) { 2723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartCallWakeLock.acquire(START_CALL_TIMEOUT); 2724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void callStarted() { 2728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mWaitingForCallStart) { 2729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mWaitingForCallStart = false; 2730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("OK"); 2731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mStartCallWakeLock.isHeld()) { 2732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartCallWakeLock.release(); 2733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int START_VOICE_RECOGNITION_TIMEOUT = 5000; // ms 2738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private synchronized void expectVoiceRecognition() { 2740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mWaitingForVoiceRecognition = true; 2741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Message msg = Message.obtain(mHandler, CHECK_VOICE_RECOGNITION_STARTED); 2742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mHandler.sendMessageDelayed(msg, START_VOICE_RECOGNITION_TIMEOUT); 2743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!mStartVoiceRecognitionWakeLock.isHeld()) { 2744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartVoiceRecognitionWakeLock.acquire(START_VOICE_RECOGNITION_TIMEOUT); 2745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized boolean startVoiceRecognition() { 27491c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 27501c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent if ((isCellularCallInProgress()) || 27511c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent (isVirtualCallInProgress()) || 27521c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent mVoiceRecognitionStarted) { 27531c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent Log.e(TAG, "startVoiceRecognition: Call in progress"); 27541c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent return false; 27551c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent } 27561c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 27571c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent mVoiceRecognitionStarted = true; 27581c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 2759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mWaitingForVoiceRecognition) { 2760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // HF initiated 2761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mWaitingForVoiceRecognition = false; 2762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("OK"); 2763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 2764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // AG initiated 2765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("+BVRA: 1"); 2766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean ret = audioOn(); 27681c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent if (ret == false) { 27691c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent mVoiceRecognitionStarted = false; 27701c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent } 2771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mStartVoiceRecognitionWakeLock.isHeld()) { 2772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mStartVoiceRecognitionWakeLock.release(); 2773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return ret; 2775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /* package */ synchronized boolean stopVoiceRecognition() { 27781c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 27791c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent if (!isVoiceRecognitionInProgress()) { 27801c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent return false; 27811c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent } 27821c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 27831c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent mVoiceRecognitionStarted = false; 27841c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 2785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC("+BVRA: 0"); 2786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOff(); 2787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return true; 2788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 27901c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent // Voice Recognition in Progress 27911c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent private boolean isVoiceRecognitionInProgress() { 27921c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent return (mVoiceRecognitionStarted || mWaitingForVoiceRecognition); 27931c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent } 27941c5ea6e6845b1e81b987a33e0d5fd3944552d7edEric Laurent 27951498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek /* 27961498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek * This class broadcasts vendor-specific commands + arguments to interested receivers. 27971498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek */ 27981498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private class VendorSpecificCommandHandler extends AtCommandHandler { 27991498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 28001498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private String mCommandName; 28011498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 28021498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private int mCompanyId; 28031498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 28041498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek private VendorSpecificCommandHandler(String commandName, int companyId) { 28051498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek mCommandName = commandName; 28061498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek mCompanyId = companyId; 28071498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 28081498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 28091498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek @Override 281086324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh public AtCommandResult handleReadCommand() { 281186324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh return new AtCommandResult(AtCommandResult.ERROR); 281286324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh } 281386324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh 281486324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh @Override 281586324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh public AtCommandResult handleTestCommand() { 281686324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh return new AtCommandResult(AtCommandResult.ERROR); 281786324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh } 281886324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh 281986324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh @Override 282086324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh public AtCommandResult handleActionCommand() { 282186324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh return new AtCommandResult(AtCommandResult.ERROR); 282286324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh } 282386324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh 282486324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh @Override 28251498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek public AtCommandResult handleSetCommand(Object[] arguments) { 28261498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek broadcastVendorSpecificEventIntent(mCommandName, 28271498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek mCompanyId, 282886324d3be365c1104c40ba007e671de8f1306021Jaikumar Ganesh BluetoothHeadset.AT_CMD_TYPE_SET, 28291498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek arguments, 28301498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek mHeadset.getRemoteDevice()); 28311498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek return new AtCommandResult(AtCommandResult.OK); 28321498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 28331498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek } 28341498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek 2835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean inDebug() { 2836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return DBG && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE, false); 2837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private boolean allowAudioAnytime() { 2840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return inDebug() && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE_AUDIO_ANYTIME, 2841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project false); 2842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private void startDebug() { 2845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG && mDebugThread == null) { 2846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mDebugThread = new DebugThread(); 2847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mDebugThread.start(); 2848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private void stopDebug() { 2852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (mDebugThread != null) { 2853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mDebugThread.interrupt(); 2854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mDebugThread = null; 2855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2858b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // VirtualCall SCO support 2859b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // 2860b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2861b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Cellular call in progress 2862b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh private boolean isCellularCallInProgress() { 2863b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (mCM.hasActiveFgCall() || mCM.hasActiveRingingCall()) return true; 2864b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 2865b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2866b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2867b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Virtual Call in Progress 2868b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh private boolean isVirtualCallInProgress() { 2869b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return mVirtualCallStarted; 2870b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2871b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2872a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh void setVirtualCallInProgress(boolean state) { 2873a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh mVirtualCallStarted = state; 2874a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh } 2875a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh 2876b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh //NOTE: Currently the VirtualCall API does not allow the application to initiate a call 2877b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // transfer. Call transfer may be initiated from the handsfree device and this is handled by 2878b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // the VirtualCall API 2879a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh synchronized boolean initiateScoUsingVirtualVoiceCall() { 2880a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) log("initiateScoUsingVirtualVoiceCall: Received"); 2881b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // 1. Check if the SCO state is idle 2882a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (isCellularCallInProgress() || isVoiceRecognitionInProgress()) { 2883a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh Log.e(TAG, "initiateScoUsingVirtualVoiceCall: Call in progress"); 2884b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 2885b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2886b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2887b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // 2. Perform outgoing call setup procedure 2888a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (mBluetoothPhoneState.sendUpdate() && !isVirtualCallInProgress()) { 2889b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 2890b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // outgoing call 2891b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh result.addResponse("+CIEV: 3,2"); 2892b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh result.addResponse("+CIEV: 2,1"); 2893b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh result.addResponse("+CIEV: 3,0"); 2894b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh sendURC(result.toString()); 2895a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) Log.d(TAG, "initiateScoUsingVirtualVoiceCall: Sent Call-setup procedure"); 2896b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2897a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh 28986e979d3698decc3631570a4f7db483cb94262c5dJaikumar Ganesh mVirtualCallStarted = true; 28996e979d3698decc3631570a4f7db483cb94262c5dJaikumar Ganesh 2900b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // 3. Open the Audio Connection 2901b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (audioOn() == false) { 2902a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh log("initiateScoUsingVirtualVoiceCall: audioON failed"); 2903a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh terminateScoUsingVirtualVoiceCall(); 2904b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 2905b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2906b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2907b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mAudioPossible = true; 2908b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2909b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Done 2910a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) log("initiateScoUsingVirtualVoiceCall: Done"); 2911b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return true; 2912b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2913b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2914a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh synchronized boolean terminateScoUsingVirtualVoiceCall() { 2915a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) log("terminateScoUsingVirtualVoiceCall: Received"); 29169760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie 29179760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie if (!isVirtualCallInProgress()) { 29189760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie return false; 29199760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie } 29209760482b3e3f8a0c11cae2866ff03fab1b2c3242Matthew Xie 2921a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh // 1. Release audio connection 2922b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh audioOff(); 2923b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2924a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh // 2. terminate call-setup 29256e979d3698decc3631570a4f7db483cb94262c5dJaikumar Ganesh if (mBluetoothPhoneState.sendUpdate()) { 2926b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED); 2927b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // outgoing call 2928b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh result.addResponse("+CIEV: 2,0"); 2929b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh sendURC(result.toString()); 2930a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) log("terminateScoUsingVirtualVoiceCall: Sent Call-setup procedure"); 2931b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 29326e979d3698decc3631570a4f7db483cb94262c5dJaikumar Ganesh mVirtualCallStarted = false; 2933b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mAudioPossible = false; 2934b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2935b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh // Done 2936a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh if (DBG) log("terminateScoUsingVirtualVoiceCall: Done"); 2937b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return true; 2938b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 2939b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2940b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 2941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Debug thread to read debug properties - runs when debug.bt.hfp is true 2942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * at the time a bluetooth handsfree device is connected. Debug properties 2943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * are polled and mock updates sent every 1 second */ 2944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private class DebugThread extends Thread { 2945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Turns on/off handsfree profile debugging mode */ 294677c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE = "debug.bt.hfp"; 2947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Mock battery level change - use 0 to 5 */ 294977c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_BATTERY = "debug.bt.hfp.battery"; 2950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Mock no cellular service when false */ 295277c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_SERVICE = "debug.bt.hfp.service"; 2953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Mock cellular roaming when true */ 295577c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_ROAM = "debug.bt.hfp.roam"; 2956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** false to true transition will force an audio (SCO) connection to 2958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * be established. true to false will force audio to be disconnected 2959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 296077c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_AUDIO = "debug.bt.hfp.audio"; 2961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** true allows incoming SCO connection out of call. 2963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 296477c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_AUDIO_ANYTIME = "debug.bt.hfp.audio_anytime"; 2965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2966b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Mock signal strength change in ASU - use 0 to 31 */ 296777c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_SIGNAL = "debug.bt.hfp.signal"; 2968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Debug AT+CLCC: print +CLCC result */ 297077c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_HANDSFREE_CLCC = "debug.bt.hfp.clcc"; 2971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** Debug AT+BSIR - Send In Band Ringtones Unsolicited AT command. 2973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * debug.bt.unsol.inband = 0 => AT+BSIR = 0 sent by the AG 2974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * debug.bt.unsol.inband = 1 => AT+BSIR = 0 sent by the AG 2975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Other values are ignored. 2976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 2977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 297877c123c48996dbecf307b4e75a05b0d4a5561563Conley Owens static final String DEBUG_UNSOL_INBAND_RINGTONE = "debug.bt.unsol.inband"; 2979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 2981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void run() { 2982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean oldService = true; 2983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean oldRoam = false; 2984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean oldAudio = false; 2985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project while (!isInterrupted() && inDebug()) { 2987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int batteryLevel = SystemProperties.getInt(DEBUG_HANDSFREE_BATTERY, -1); 2988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (batteryLevel >= 0 && batteryLevel <= 5) { 2989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Intent intent = new Intent(); 2990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project intent.putExtra("level", batteryLevel); 2991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project intent.putExtra("scale", 5); 29921dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState.updateBatteryState(intent); 2993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 2994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project boolean serviceStateChanged = false; 2996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (SystemProperties.getBoolean(DEBUG_HANDSFREE_SERVICE, true) != oldService) { 2997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project oldService = !oldService; 2998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project serviceStateChanged = true; 2999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (SystemProperties.getBoolean(DEBUG_HANDSFREE_ROAM, false) != oldRoam) { 3001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project oldRoam = !oldRoam; 3002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project serviceStateChanged = true; 3003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (serviceStateChanged) { 3005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Bundle b = new Bundle(); 3006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project b.putInt("state", oldService ? 0 : 1); 3007b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project b.putBoolean("roaming", oldRoam); 30081dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState.updateServiceState(true, ServiceState.newFromBundle(b)); 3009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 3011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (SystemProperties.getBoolean(DEBUG_HANDSFREE_AUDIO, false) != oldAudio) { 3012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project oldAudio = !oldAudio; 3013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (oldAudio) { 3014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOn(); 3015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 3016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project audioOff(); 3017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 3020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1); 3021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (signalLevel >= 0 && signalLevel <= 31) { 3022404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1, 3023404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville -1, -1, -1, true); 3024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Intent intent = new Intent(); 3025404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville Bundle data = new Bundle(); 3026404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville signalStrength.fillInNotifierBundle(data); 3027404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville intent.putExtras(data); 30281dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh mBluetoothPhoneState.updateSignalState(intent); 3029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 3031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (SystemProperties.getBoolean(DEBUG_HANDSFREE_CLCC, false)) { 3032c9d9ed30aa547b79b81adc13a4d148a003b6ee62w log(gsmGetClccResult().toString()); 3033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project try { 3035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sleep(1000); // 1 second 3036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } catch (InterruptedException e) { 3037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 3038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 3040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int inBandRing = 3041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project SystemProperties.getInt(DEBUG_UNSOL_INBAND_RINGTONE, -1); 3042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (inBandRing == 0 || inBandRing == 1) { 3043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AtCommandResult result = 3044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project new AtCommandResult(AtCommandResult.UNSOLICITED); 3045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project result.addResponse("+BSIR: " + inBandRing); 3046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendURC(result.toString()); 3047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 3052c9d9ed30aa547b79b81adc13a4d148a003b6ee62w public void cdmaSwapSecondCallState() { 30538eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("cdmaSetSecondCallState: Toggling mCdmaIsSecondCallActive"); 3054c9d9ed30aa547b79b81adc13a4d148a003b6ee62w mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive; 305591f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mCdmaCallsSwapped = true; 3056c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 3057c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 3058c9d9ed30aa547b79b81adc13a4d148a003b6ee62w public void cdmaSetSecondCallState(boolean state) { 30598eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state); 3060c9d9ed30aa547b79b81adc13a4d148a003b6ee62w mCdmaIsSecondCallActive = state; 306191f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh 306291f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh if (!mCdmaIsSecondCallActive) { 306391f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh mCdmaCallsSwapped = false; 306491f4a3ccc2ac2e146f54c4b4b88b62c16595602aJaikumar Ganesh } 3065c9d9ed30aa547b79b81adc13a4d148a003b6ee62w } 3066c9d9ed30aa547b79b81adc13a4d148a003b6ee62w 3067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static void log(String msg) { 3068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.d(TAG, msg); 3069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 3070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project} 3071