BluetoothHandsfree.java revision c39c3c9ada26aa8fab1373ad94c9b0d9e8875caa
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;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.HeadsetBase;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.ScoSocket;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.ActivityNotFoundException;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.IntentFilter;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager;
35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.AsyncResult;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle;
38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler;
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message;
40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager;
41b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager.WakeLock;
42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.SystemProperties;
43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.ServiceState;
45404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.telephony.SignalStrength;
46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Call;
49b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Connection;
50b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Phone;
51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.TelephonyIntents;
528058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wangimport com.android.internal.telephony.CallManager;
53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.LinkedList;
55f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Bluetooth headset manager for the Phone app.
58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * @hide
59b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
60b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class BluetoothHandsfree {
61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String TAG = "BT HS/HF";
628eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1)
638eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            && (SystemProperties.getInt("ro.debuggable", 0) == 1);
648eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);  // even more logging
65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
66b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_UNKNOWN           = 0;
67b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HEADSET           = 1;
68b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HANDSFREE         = 2;
69b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
704079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private final Context mContext;
718058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang    private final CallManager mCM;
72f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private final BluetoothA2dp mA2dp;
73f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
74f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private BluetoothDevice mA2dpDevice;
75f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private int mA2dpState;
76f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ServiceState mServiceState;
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private HeadsetBase mHeadset;  // null when not connected
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mHeadsetType;
80b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mAudioPossible;
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mIncomingSco;
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mOutgoingSco;
83b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mConnectedSco;
84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AudioManager mAudioManager;
86b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private PowerManager mPowerManager;
87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
88f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private boolean mPendingSco;  // waiting for a2dp sink to suspend before establishing SCO
89ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent    private boolean mA2dpSuspended;
90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mUserWantsAudio;
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
92b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartVoiceRecognitionWakeLock;  // held while waiting for voice recognition
93b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // AT command state
95c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private static final int GSM_MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
96c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private static final int CDMA_MAX_CONNECTIONS = 2;  // Max connections allowed by CDMA
97b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
98b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long mBgndEarliestConnectionTime = 0;
99b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mClip = false;  // Calling Line Information Presentation
100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mIndicatorsEnabled = false;
101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mCmee = false;  // Extended Error reporting
102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long[] mClccTimestamps; // Timestamps associated with each clcc index
103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean[] mClccUsed;     // Is this clcc index in use
104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForCallStart;
105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForVoiceRecognition;
1060966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // do not connect audio until service connection is established
1070966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // for 3-way supported devices, this is after AT+CHLD
1080966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // for non-3-way supported devices, this is after AT+CMER (see spec)
1090966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    private boolean mServiceConnectionEstablished;
110db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly
1111dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh    private final BluetoothPhoneState mBluetoothPhoneState;  // for CIND and CIEV updates
112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final BluetoothAtPhonebook mPhonebook;
1131dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh    private Phone.State mPhoneState = Phone.State.IDLE;
114487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh    CdmaPhoneCallState.PhoneCallState mCdmaThreeWayCallState =
115487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                            CdmaPhoneCallState.PhoneCallState.IDLE;
116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private DebugThread mDebugThread;
118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mScoGain = Integer.MIN_VALUE;
119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static Intent sVoiceCommandIntent;
121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Audio parameters
123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NREC = "bt_headset_nrec";
124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NAME = "bt_headset_name";
125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mRemoteBrsf = 0;
127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mLocalBrsf = 0;
128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
129c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // CDMA specific flag used in context with BT devices having display capabilities
130c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // to show which Caller is active. This state might not be always true as in CDMA
131c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // networks if a caller drops off no update is provided to the Phone.
132c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // This flag is just used as a toggle to provide a update to the BT device to specify
133c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // which caller is active.
134c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private boolean mCdmaIsSecondCallActive = false;
135c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */
1376967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
1386967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_EC_NR = 1 << 1;
1396967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_RECOG = 1 << 2;
1406967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_IN_BAND_RING = 1 << 3;
1416967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
1426967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_REJECT_CALL = 1 << 5;
1436967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
1446967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
1456967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
1466967e2d953bc077c99c4831946201f3d333b833fNick Pelly
1476967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_EC_NR = 1 << 0;
1486967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
1496967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CLIP = 1 << 2;
1506967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
1516967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
1526967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
1536967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static String typeToString(int type) {
156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (type) {
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_UNKNOWN:
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "unknown";
159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HEADSET:
160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "headset";
161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HANDSFREE:
162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "handsfree";
163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return null;
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1678058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang    public BluetoothHandsfree(Context context, CallManager cm) {
1688058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        mCM = cm;
169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext = context;
170cec56587c1d3c90014848d7adfe817bef9c325eaNick Pelly        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
171db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        boolean bluetoothCapable = (adapter != null);
172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;  // nothing connected yet
173f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        mA2dp = new BluetoothA2dp(mContext);
174f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        mA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
175f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        mA2dpDevice = null;
176ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent        mA2dpSuspended = false;
177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":StartCall");
181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock.setReferenceCounted(false);
182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":VoiceRecognition");
184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock.setReferenceCounted(false);
185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mLocalBrsf = BRSF_AG_THREE_WAY_CALLING |
187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_EC_NR |
188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_REJECT_CALL |
189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_ENHANCED_CALL_STATUS;
1904b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project
191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (sVoiceCommandIntent == null) {
192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1956967e2d953bc077c99c4831946201f3d333b833fNick Pelly        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null &&
196b8dbab241df3aa3487c1bdb488fd4e0b694d2d9aEric Laurent                BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) {
197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLocalBrsf |= BRSF_AG_VOICE_RECOG;
198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2001dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState = new BluetoothPhoneState();
201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook = new BluetoothAtPhonebook(mContext, this);
203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
204c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        cdmaSetSecondCallState(false);
205f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh
206f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh        if (bluetoothCapable) {
207f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh            resetAtState();
208f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh        }
209f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh
210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothEnabled() {
213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* Bluez has a bug where it will always accept and then orphan
214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * incoming SCO connections, regardless of whether we have a listening
215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * SCO socket. So the best thing to do is always run a listening socket
216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * while bluetooth is on so that at least we can diconnect it
217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * immediately when we don't want it.
218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco == null) {
220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = createScoSocket();
221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.accept();
222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothDisabled() {
226a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent        audioOff();
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco != null) {
228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.close();
229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = null;
230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isHeadsetConnected() {
234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadset == null) {
235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mHeadset.isConnected();
238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
240f6adf1a33b12c9900b3ce9c15130642ce515ae91Jaikumar Ganesh    /* package */ synchronized void connectHeadset(HeadsetBase headset, int headsetType) {
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = headset;
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadsetType = headsetType;
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadsetType == TYPE_HEADSET) {
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHeadsetAtParser();
245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHandsfreeAtParser();
247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2481498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
2491498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        // Headset vendor-specific commands
2501498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        registerAllVendorSpecificCommands();
2511498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        headset.startEventThread();
253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        configAudioParameters();
254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (inDebug()) {
256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            startDebug();
257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isIncallAudio()) {
260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            audioOn();
261179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi        } else if ( mCM.getFirstActiveRingingCall().isRinging()) {
262179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi            // need to update HS with RING when single ringing call exist
263179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi            mBluetoothPhoneState.ring();
264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* returns true if there is some kind of in-call audio we may wish to route
268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * bluetooth to */
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isIncallAudio() {
2708058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call.State state = mCM.getActiveFgCallState();
271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (state == Call.State.ACTIVE || state == Call.State.ALERTING);
273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
275819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh    /* package */ synchronized void disconnectHeadset() {
276819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh        // Close off the SCO sockets
277819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh        audioOff();
278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;
279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        stopDebug();
280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        resetAtState();
281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
283bfc44512504ebc93c101ddb394719840f2d25072Jaikumar Ganesh    /* package */ synchronized void resetAtState() {
284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mClip = false;
285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mIndicatorsEnabled = false;
2860966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        mServiceConnectionEstablished = false;
287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mCmee = false;
288c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mClccTimestamps = new long[GSM_MAX_CONNECTIONS];
289c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mClccUsed = new boolean[GSM_MAX_CONNECTIONS];
290c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mRemoteBrsf = 0;
294f5945125c4e044b860f89a370fe376b97bd91d37Jaikumar Ganesh        mPhonebook.resetAtState();
295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void configAudioParameters() {
298db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        String name = mHeadset.getRemoteDevice().getName();
299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (name == null) {
300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            name = "<unknown>";
301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
302aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent        mAudioManager.setParameters(HEADSET_NAME+"="+name+";"+HEADSET_NREC+"=on");
303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Represents the data that we send in a +CIND or +CIEV command to the HF
307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class BluetoothPhoneState {
309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no service
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: service
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mService;
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no active call
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: active call (where active means audio is routed - not held call)
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCall;
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not in call setup
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: incoming call setup
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: outgoing call setup
320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 3: remote party being alerted in an outgoing call setup
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallsetup;
322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no calls held
324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: held call and active call
325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: held call only
326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallheld;
327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength of AG: 0-5
329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mSignal;
330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength in CSQ rssi scale
332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRssi;  // for CSQ
333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: roaming not active (home)
335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: roaming active
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRoam;
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // battery charge of AG: 0-5
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mBattchg;
340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not registered
342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: registered, home network
343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 5: registered, roaming
344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mStat;  // for CREG
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private String mRingingNumber;  // Context for in-progress RING's
347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int    mRingingType;
348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean mIgnoreRing = false;
3491ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh        private boolean mStopRing = false;
350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int SERVICE_STATE_CHANGED = 1;
352487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh        private static final int PRECISE_CALL_STATE_CHANGED = 2;
353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int RING = 3;
354a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman        private static final int PHONE_CDMA_CALL_WAITING = 4;
355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private Handler mStateChangeHandler = new Handler() {
357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void handleMessage(Message msg) {
359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch(msg.what) {
360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RING:
361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result = ring();
362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (result != null) {
363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        sendURC(result.toString());
364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case SERVICE_STATE_CHANGED:
367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateServiceState(sendUpdate(), state);
369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
370487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                case PRECISE_CALL_STATE_CHANGED:
371a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                case PHONE_CDMA_CALL_WAITING:
372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Connection connection = null;
373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (((AsyncResult) msg.obj).result instanceof Connection) {
374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        connection = (Connection) ((AsyncResult) msg.obj).result;
375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
376487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    handlePreciseCallStateChange(sendUpdate(), connection);
377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private BluetoothPhoneState() {
383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // init members
3848058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            // TODO May consider to repalce the default phone's state and signal
3858058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            //      by CallManagter's state and signal
3868058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            updateServiceState(false, mCM.getDefaultPhone().getServiceState());
387487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            handlePreciseCallStateChange(false, null);
388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mBattchg = 5;  // There is currently no API to get battery level
389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           // on demand, so set to 5 and wait for an update
3908058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength());
391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // register for updates
393f8453f9e061b237d83d006e07009402fa7680583John Wang            // Use the service state of default phone as BT service state to
394f8453f9e061b237d83d006e07009402fa7680583John Wang            // avoid situation such as no cell or wifi connection but still
395f8453f9e061b237d83d006e07009402fa7680583John Wang            // reporting in service (since SipPhone always reports in service).
396f8453f9e061b237d83d006e07009402fa7680583John Wang            mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler,
397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                  SERVICE_STATE_CHANGED, null);
3988058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.registerForPreciseCallStateChanged(mStateChangeHandler,
399487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    PRECISE_CALL_STATE_CHANGED, null);
4008058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.registerForCallWaiting(mStateChangeHandler,
4018058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                PHONE_CDMA_CALL_WAITING, null);
4028058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang
403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            filter.addAction(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
405f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mContext.registerReceiver(mStateReceiver, filter);
407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
409a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        private void updateBtPhoneStateAfterRadioTechnologyChange() {
4108eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
411a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
412a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Unregister all events from the old obsolete phone
413f8453f9e061b237d83d006e07009402fa7680583John Wang            mCM.getDefaultPhone().unregisterForServiceStateChanged(mStateChangeHandler);
4148058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.unregisterForPreciseCallStateChanged(mStateChangeHandler);
4158058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.unregisterForCallWaiting(mStateChangeHandler);
416a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
417a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Register all events new to the new active phone
418f8453f9e061b237d83d006e07009402fa7680583John Wang            mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler,
41919dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh                                                  SERVICE_STATE_CHANGED, null);
4208058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.registerForPreciseCallStateChanged(mStateChangeHandler,
421487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    PRECISE_CALL_STATE_CHANGED, null);
4228058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mCM.registerForCallWaiting(mStateChangeHandler,
4238058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                PHONE_CDMA_CALL_WAITING, null);
424a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        }
425a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendUpdate() {
4270280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled
4280280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                   && mServiceConnectionEstablished;
429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendClipUpdate() {
4320280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mClip &&
4330280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                   mServiceConnectionEstablished;
4340280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS        }
4350280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS
4360280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS        private boolean sendRingUpdate() {
4370280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            if (isHeadsetConnected() && !mIgnoreRing && !mStopRing &&
4380280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                    mCM.getFirstActiveRingingCall().isRinging()) {
4390280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                if (mHeadsetType == TYPE_HANDSFREE) {
4400280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                    return mServiceConnectionEstablished ? true : false;
4410280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                }
4420280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS                return true;
4430280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            }
4440280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            return false;
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
4471ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh        private void stopRing() {
4481ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh            mStopRing = true;
4491ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh        }
4501ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,31] ASU signal strength to the [0,5] expected by
452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * bluetooth devices. Scale is similar to status bar policy
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
45434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        private int gsmAsuToSignal(SignalStrength signalStrength) {
45534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int asu = signalStrength.getGsmSignalStrength();
456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if      (asu >= 16) return 5;
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 8)  return 4;
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 4)  return 3;
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 2)  return 2;
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 1)  return 1;
461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else                return 0;
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
46434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        /**
46534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * Convert the cdma / evdo db levels to appropriate icon level.
46634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * The scale is similar to the one used in status bar policy.
46734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         *
46834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * @param signalStrength
46934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * @return the icon level
470404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville         */
47134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        private int cdmaDbmEcioToSignal(SignalStrength signalStrength) {
47234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int levelDbm = 0;
47334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int levelEcio = 0;
47434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaIconLevel = 0;
47534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int evdoIconLevel = 0;
47634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaDbm = signalStrength.getCdmaDbm();
47734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaEcio = signalStrength.getCdmaEcio();
47834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
47934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (cdmaDbm >= -75) levelDbm = 4;
48034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -85) levelDbm = 3;
48134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -95) levelDbm = 2;
48234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -100) levelDbm = 1;
48334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else levelDbm = 0;
48434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
48534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            // Ec/Io are in dB*10
48634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (cdmaEcio >= -90) levelEcio = 4;
48734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -110) levelEcio = 3;
48834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -130) levelEcio = 2;
48934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -150) levelEcio = 1;
49034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else levelEcio = 0;
49134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
49234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
49334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
49413df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh            if (mServiceState != null &&
495b1164d370e8d83a8a4f3cbdc73dffc087254cabdJaikumar Ganesh                  (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0 ||
496b1164d370e8d83a8a4f3cbdc73dffc087254cabdJaikumar Ganesh                   mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
49734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int evdoEcio = signalStrength.getEvdoEcio();
49834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int evdoSnr = signalStrength.getEvdoSnr();
49934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int levelEvdoEcio = 0;
50034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int levelEvdoSnr = 0;
50134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
50234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  // Ec/Io are in dB*10
50334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  if (evdoEcio >= -650) levelEvdoEcio = 4;
50434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -750) levelEvdoEcio = 3;
50534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -900) levelEvdoEcio = 2;
50634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -1050) levelEvdoEcio = 1;
50734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else levelEvdoEcio = 0;
50834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
50934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  if (evdoSnr > 7) levelEvdoSnr = 4;
51034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 5) levelEvdoSnr = 3;
51134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 3) levelEvdoSnr = 2;
51234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 1) levelEvdoSnr = 1;
51334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else levelEvdoSnr = 0;
51434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
51534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
51634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            }
51734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            // TODO(): There is a bug open regarding what should be sent.
51834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            return (cdmaIconLevel > evdoIconLevel) ?  cdmaIconLevel : evdoIconLevel;
51934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
520404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
521404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
522404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
523404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        private int asuToSignal(SignalStrength signalStrength) {
52434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (signalStrength.isGsm()) {
52534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                return gsmAsuToSignal(signalStrength);
526404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
52734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                return cdmaDbmEcioToSignal(signalStrength);
528404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            }
529404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
530404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
531404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,5] signal strength to a rssi signal strength for CSQ
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * which is [0,31]. Despite the same scale, this is not the same value
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * as ASU.
535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int signalToRssi(int signal) {
537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // using C4A suggested values
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (signal) {
539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 0: return 0;
540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 1: return 4;
541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 2: return 8;
542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 3: return 13;
543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 4: return 19;
544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 5: return 31;
545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return 0;
547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void onReceive(Context context, Intent intent) {
553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateBatteryState(intent);
555f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                } else if (intent.getAction().equals(
556f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED)) {
557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateSignalState(intent);
558f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                } else if (intent.getAction().equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
559f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE,
560f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            BluetoothA2dp.STATE_DISCONNECTED);
561f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE,
562f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            BluetoothA2dp.STATE_DISCONNECTED);
563f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    BluetoothDevice device =
564f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
565105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh
566105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                    // We are only concerned about Connected sinks to suspend and resume
567105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                    // them. We can safely ignore SINK_STATE_CHANGE for other devices.
568105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                    if (mA2dpDevice != null && !device.equals(mA2dpDevice)) return;
569105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh
570f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    synchronized (BluetoothHandsfree.this) {
571f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        mA2dpState = state;
572105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                        if (state == BluetoothA2dp.STATE_DISCONNECTED) {
573105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                            mA2dpDevice = null;
574105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                        } else {
575105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                            mA2dpDevice = device;
576105bb2145aba70c03b43bfab906c1b0551387309Jaikumar Ganesh                        }
577ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                        if (oldState == BluetoothA2dp.STATE_PLAYING &&
578ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                            mA2dpState == BluetoothA2dp.STATE_CONNECTED) {
579ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                            if (mA2dpSuspended) {
580ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                if (mPendingSco) {
581ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    mHandler.removeMessages(MESSAGE_CHECK_PENDING_SCO);
582ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    if (DBG) log("A2DP suspended, completing SCO");
583ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    mOutgoingSco = createScoSocket();
584ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    if (!mOutgoingSco.connect(
585f0316a1fb5c00585d0fe4b500723557afabec70bEric Olsen                                            mHeadset.getRemoteDevice().getAddress(),
586f0316a1fb5c00585d0fe4b500723557afabec70bEric Olsen                                            mHeadset.getRemoteDevice().getName())) {
587ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                        mOutgoingSco = null;
588ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    }
589ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                                    mPendingSco = false;
590f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                                }
591f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            }
592f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        }
593f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    }
594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateBatteryState(Intent intent) {
599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int batteryLevel = intent.getIntExtra("level", -1);
600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int scale = intent.getIntExtra("scale", -1);
601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (batteryLevel == -1 || scale == -1) {
602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return;  // ignore
603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            batteryLevel = batteryLevel * 5 / scale;
605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mBattchg != batteryLevel) {
606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mBattchg = batteryLevel;
607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate()) {
608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC("+CIEV: 7," + mBattchg);
609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateSignalState(Intent intent) {
614404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent
615404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread
616d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh            if (mHeadset == null) {
617d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh                return;
618d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh            }
619d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh
620404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras());
621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int signal;
622404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
623404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            if (signalStrength != null) {
624404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                signal = asuToSignal(signalStrength);
625404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                mRssi = signalToRssi(signal);  // no unsolicited CSQ
626404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                if (signal != mSignal) {
627404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    mSignal = signal;
628404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    if (sendUpdate()) {
629404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                        sendURC("+CIEV: 5," + mSignal);
630404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    }
631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
632404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
633404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                Log.e(TAG, "Signal Strength null");
634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateServiceState(boolean sendUpdate, ServiceState state) {
638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int service = state.getState() == ServiceState.STATE_IN_SERVICE ? 1 : 0;
639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int roam = state.getRoaming() ? 1 : 0;
640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int stat;
641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
64213df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh            mServiceState = state;
643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service == 0) {
644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = 0;
645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = (roam == 1) ? 5 : 1;
647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service != mService) {
650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mService = service;
651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 1," + mService);
653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (roam != mRoam) {
656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mRoam = roam;
657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 6," + mRoam);
659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (stat != mStat) {
662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStat = stat;
663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(toCregString());
665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
671487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh        private synchronized void handlePreciseCallStateChange(boolean sendUpdate,
672487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                Connection connection) {
673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int call = 0;
674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callsetup = 0;
675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callheld = 0;
676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int prevCallsetup = mCallsetup;
677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
6788058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            Call foregroundCall = mCM.getActiveFgCall();
6798058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            Call backgroundCall = mCM.getFirstActiveBgCall();
6808058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            Call ringingCall = mCM.getFirstActiveRingingCall();
681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6828eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("updatePhoneState()");
683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
684487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            // This function will get called when the Precise Call State
685487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            // {@link Call.State} changes. Hence, we might get this update
686487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            // even if the {@link Phone.state} is same as before.
687487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            // Check for the same.
688487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh
6898058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            Phone.State newState = mCM.getState();
6901dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh            if (newState != mPhoneState) {
6911dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                mPhoneState = newState;
6921dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                switch (mPhoneState) {
6931dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                case IDLE:
6941dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mUserWantsAudio = true;  // out of call - reset state
6951dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    audioOff();
6961dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    break;
6971dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                default:
6981dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    callStarted();
6991dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                }
700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7028058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            switch(foregroundCall.getState()) {
703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ACTIVE:
704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                call = 1;
705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DIALING:
708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 2;
709a41427328932deb7cbadf586a1ec58e0ba26a932Jaikumar Ganesh                mAudioPossible = true;
7103904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // We also need to send a Call started indication
7113904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // for cases where the 2nd MO was initiated was
7123904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // from a *BT hands free* and is waiting for a
7133904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // +BLND: OK response
7143904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // There is a special case handling of the same case
7153904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                // for CDMA below
7168058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                if (mCM.getFgPhone().getPhoneType() == Phone.PHONE_TYPE_GSM) {
7173904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                    callStarted();
7183904e979ce9a501acbe6d8739393767a495388e8Jaikumar Ganesh                }
719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ALERTING:
721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 3;
722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Open the SCO channel for the outgoing call.
723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                audioOn();
724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
72681a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh            case DISCONNECTING:
72781a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // This is a transient state, we don't want to send
72881a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // any AT commands during this state.
72981a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                call = mCall;
73081a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callsetup = mCallsetup;
73181a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callheld = mCallheld;
73281a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                break;
733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = false;
735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7378058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            switch(ringingCall.getState()) {
738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case INCOMING:
739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case WAITING:
740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 1;
741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
74281a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh            case DISCONNECTING:
74381a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // This is a transient state, we don't want to send
74481a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // any AT commands during this state.
74581a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                call = mCall;
74681a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callsetup = mCallsetup;
74781a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callheld = mCallheld;
74881a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                break;
749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7518058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            switch(backgroundCall.getState()) {
752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case HOLDING:
753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 1;
755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    call = 1;
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 2;
758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
76081a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh            case DISCONNECTING:
76181a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // This is a transient state, we don't want to send
76281a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                // any AT commands during this state.
76381a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                call = mCall;
76481a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callsetup = mCallsetup;
76581a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                callheld = mCallheld;
76681a26f368128024620b0dc7b0eb32debf3fe3419Jaikumar Ganesh                break;
767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCall != call) {
770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This means that a call has transitioned from NOT ACTIVE to ACTIVE.
772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Switch on audio.
773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCall = call;
776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 2," + mCall);
778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallsetup != callsetup) {
781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallsetup = callsetup;
782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
7834b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // If mCall = 0, send CIEV
7844b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 0, send CIEV
7854b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 1, send CIEV after CCWA,
7864b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way supported.
7874b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 2 / 3 -> send CIEV,
7884b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way is supported
7894b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    if (mCall != 1 || mCallsetup == 0 ||
7904b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CIEV: 3," + mCallsetup);
792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7968058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            if (mCM.getDefaultPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA) {
797c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                PhoneApp app = PhoneApp.getInstance();
79860877272381161201c6969dea501e683705d6e32w                if (app.cdmaPhoneCallState != null) {
799487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    CdmaPhoneCallState.PhoneCallState currCdmaThreeWayCallState =
80060877272381161201c6969dea501e683705d6e32w                            app.cdmaPhoneCallState.getCurrentCallState();
801487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    CdmaPhoneCallState.PhoneCallState prevCdmaThreeWayCallState =
802ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        app.cdmaPhoneCallState.getPreviousCallState();
803ed1d155825eb32990fde95eef9d89a7260e4c3f1w
804487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    callheld = getCdmaCallHeldStatus(currCdmaThreeWayCallState,
805487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                                     prevCdmaThreeWayCallState);
806487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh
807487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    if (mCdmaThreeWayCallState != currCdmaThreeWayCallState) {
808487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // In CDMA, the network does not provide any feedback
809487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // to the phone when the 2nd MO call goes through the
810487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // stages of DIALING > ALERTING -> ACTIVE we fake the
811487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // sequence
812487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        if ((currCdmaThreeWayCallState ==
813487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
814487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
815487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            mAudioPossible = true;
816487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            if (sendUpdate) {
817487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
818487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    result.addResponse("+CIEV: 3,2");
819487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    result.addResponse("+CIEV: 3,3");
820487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    result.addResponse("+CIEV: 3,0");
821487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                }
82260877272381161201c6969dea501e683705d6e32w                            }
823487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            // We also need to send a Call started indication
824487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            // for cases where the 2nd MO was initiated was
825487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            // from a *BT hands free* and is waiting for a
826487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            // +BLND: OK response
827487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            callStarted();
828c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        }
829c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
830487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // In CDMA, the network does not provide any feedback to
831487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // the phone when a user merges a 3way call or swaps
832487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // between two calls we need to send a CIEV response
833487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // indicating that a call state got changed which should
834487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // trigger a CLCC update request from the BT client.
835487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        if (currCdmaThreeWayCallState ==
836487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
837487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            mAudioPossible = true;
838487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            if (sendUpdate) {
839487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
840487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    result.addResponse("+CIEV: 2,1");
841487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                    result.addResponse("+CIEV: 3,0");
842487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                }
84360877272381161201c6969dea501e683705d6e32w                            }
844c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        }
845c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    }
846487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    mCdmaThreeWayCallState = currCdmaThreeWayCallState;
847c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
848c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
849c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean callsSwitched =
8518058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                (callheld == 1 && ! (backgroundCall.getEarliestConnectTime() ==
852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mBgndEarliestConnectionTime));
853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
8548058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            mBgndEarliestConnectionTime = backgroundCall.getEarliestConnectTime();
855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallheld != callheld || callsSwitched) {
857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallheld = callheld;
858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
859b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 4," + mCallheld);
860b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
861b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (callsetup == 1 && callsetup != prevCallsetup) {
864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // new incoming call
865b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String number = null;
866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int type = 128;
867b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // find incoming phone number and type
868b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection == null) {
8698058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    connection = ringingCall.getEarliestConnection();
870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (connection == null) {
871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.e(TAG, "Could not get a handle on Connection object for new " +
872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                              "incoming call");
873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection != null) {
876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = connection.getAddress();
877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (number != null) {
878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        type = PhoneNumberUtils.toaFromString(number);
879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = "";
883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if ((call != 0 || callheld != 0) && sendUpdate) {
885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // call waiting
886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CCWA: \"" + number + "\"," + type);
8884b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        result.addResponse("+CIEV: 3," + callsetup);
889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
890b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // regular new incoming call
892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingNumber = number;
893b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingType = type;
894b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mIgnoreRing = false;
8951ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                    mStopRing = false;
896b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
897a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly                    if ((mLocalBrsf & BRSF_AG_IN_BAND_RING) != 0x0) {
898a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly                        audioOn();
899a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly                    }
900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResult(ring());
901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
905b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
906487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh        private int getCdmaCallHeldStatus(CdmaPhoneCallState.PhoneCallState currState,
907487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                                  CdmaPhoneCallState.PhoneCallState prevState) {
908487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            int callheld;
909487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            // Update the Call held information
910487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            if (currState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
911487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                if (prevState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
912487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    callheld = 0; //0: no calls held, as now *both* the caller are active
913487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                } else {
914487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                    callheld = 1; //1: held call and active call, as on answering a
915487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                            // Call Waiting, one of the caller *is* put on hold
916487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                }
917487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            } else if (currState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
918487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                callheld = 1; //1: held call and active call, as on make a 3 Way Call
919487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                        // the first caller *is* put on hold
920487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            } else {
921487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh                callheld = 0; //0: no calls held as this is a SINGLE_ACTIVE call
922487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            }
923487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh            return callheld;
924487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh        }
925487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh
926487f0e7aa6b2db7212e76713199d4812a61c4625Jaikumar Ganesh
927b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private AtCommandResult ring() {
9280280bd6306692055f42ed0b7408dcc089a235c37SRINIVAS            if (sendRingUpdate()) {
929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                result.addResponse("RING");
931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendClipUpdate()) {
932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CLIP: \"" + mRingingNumber + "\"," + mRingingType);
933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Message msg = mStateChangeHandler.obtainMessage(RING);
936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStateChangeHandler.sendMessageDelayed(msg, 3000);
937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return result;
938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;
940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized String toCregString() {
943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new String("+CREG: 1," + mStat);
944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCindResult() {
947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
948d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh            mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength());
949d16be9780f29c031e3d854fde5b92f05392836e3Jaikumar Ganesh
950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CIND: " + mService + "," + mCall + "," + mCallsetup + "," +
951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mCallheld + "," + mSignal + "," + mRoam + "," + mBattchg;
952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCsqResult() {
957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CSQ: " + mRssi + ",99";
959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult getCindTestResult() {
965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult("+CIND: (\"service\",(0-1))," + "(\"call\",(0-1))," +
966b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))," +
967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"roam\",(0-1)),(\"battchg\",(0-5))");
968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void ignoreRing() {
971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mCallsetup = 0;
972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIgnoreRing = true;
973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (sendUpdate()) {
974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                sendURC("+CIEV: 3," + mCallsetup);
975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_ACCEPTED = 1;
981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CONNECTED = 2;
982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CLOSED = 3;
983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_CALL_STARTED = 4;
984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_VOICE_RECOGNITION_STARTED = 5;
985f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private static final int MESSAGE_CHECK_PENDING_SCO = 6;
986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final Handler mHandler = new Handler() {
988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
9897757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh        public void handleMessage(Message msg) {
9907757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh            synchronized (BluetoothHandsfree.this) {
9917757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                switch (msg.what) {
9927757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_ACCEPTED:
9937757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
9947757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        if (isHeadsetConnected() && (mAudioPossible || allowAudioAnytime()) &&
9957757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                                mConnectedSco == null) {
9967757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            Log.i(TAG, "Routing audio for incoming SCO connection");
9977757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mConnectedSco = (ScoSocket)msg.obj;
9987757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mAudioManager.setBluetoothScoOn(true);
999db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED,
1000db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                                    mHeadset.getRemoteDevice());
10017757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        } else {
10027757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            Log.i(TAG, "Rejecting incoming SCO connection");
10037757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            ((ScoSocket)msg.obj).close();
10047757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        }
10057757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } // else error trying to accept, try again
10067757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    mIncomingSco = createScoSocket();
10077757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    mIncomingSco.accept();
10087757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
10097757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_CONNECTED:
10107757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (msg.arg1 == ScoSocket.STATE_CONNECTED && isHeadsetConnected() &&
1011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mConnectedSco == null) {
10128eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                        if (VDBG) log("Routing audio for outgoing SCO conection");
1013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mConnectedSco = (ScoSocket)msg.obj;
1014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mAudioManager.setBluetoothScoOn(true);
1015db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED,
1016db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                                mHeadset.getRemoteDevice());
10177757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } else if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
10188eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                        if (VDBG) log("Rejecting new connected outgoing SCO socket");
1019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        ((ScoSocket)msg.obj).close();
10207757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mOutgoingSco.close();
1021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mOutgoingSco = null;
10237757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
10247757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_CLOSED:
10257757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mConnectedSco == (ScoSocket)msg.obj) {
1026819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                        mConnectedSco.close();
10277757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mConnectedSco = null;
10287757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mAudioManager.setBluetoothScoOn(false);
1029db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED,
1030819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                               mHeadset.getRemoteDevice());
10317757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } else if (mOutgoingSco == (ScoSocket)msg.obj) {
1032819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                        mOutgoingSco.close();
10337757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mOutgoingSco = null;
1034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
10357757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
10367757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case CHECK_CALL_STARTED:
10377757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mWaitingForCallStart) {
10387757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mWaitingForCallStart = false;
10397757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        Log.e(TAG, "Timeout waiting for call to start");
10407757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        sendURC("ERROR");
10417757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        if (mStartCallWakeLock.isHeld()) {
10427757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mStartCallWakeLock.release();
10437757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        }
10447757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    }
10457757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
10467757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case CHECK_VOICE_RECOGNITION_STARTED:
10477757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mWaitingForVoiceRecognition) {
10487757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mWaitingForVoiceRecognition = false;
10497757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        Log.e(TAG, "Timeout waiting for voice recognition to start");
10507757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        sendURC("ERROR");
10517757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    }
10527757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
1053f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                case MESSAGE_CHECK_PENDING_SCO:
1054f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    if (mPendingSco && isA2dpMultiProfile()) {
1055f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        Log.w(TAG, "Timeout suspending A2DP for SCO (mA2dpState = " +
1056f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                                mA2dpState + "). Starting SCO anyway");
1057f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        mOutgoingSco = createScoSocket();
1058819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                        if (!(isHeadsetConnected() &&
1059819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                                mOutgoingSco.connect(mHeadset.getRemoteDevice().getAddress(),
1060819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                                 mHeadset.getRemoteDevice().getName()))) {
1061f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                            mOutgoingSco = null;
1062f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        }
1063f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                        mPendingSco = false;
1064f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    }
1065f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                    break;
1066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
1070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket createScoSocket() {
1072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new ScoSocket(mPowerManager, mHandler, SCO_ACCEPTED, SCO_CONNECTED, SCO_CLOSED);
1073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1075db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly    private void broadcastAudioStateIntent(int state, BluetoothDevice device) {
10764079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        if (VDBG) log("broadcastAudioStateIntent(" + state + ")");
107718e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly        Intent intent = new Intent(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
107818e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly        intent.putExtra(BluetoothHeadset.EXTRA_AUDIO_STATE, state);
107918e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
10804079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
10814079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    }
10824079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project
10831498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    /*
10841498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * Put the AT command, company ID, arguments, and device in an Intent and broadcast it.
10851498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     */
10861498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    private void broadcastVendorSpecificEventIntent(String command,
10871498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                                    int companyId,
10881498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                                    Object[] arguments,
10891498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                                    BluetoothDevice device) {
10901498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        if (VDBG) log("broadcastVendorSpecificEventIntent(" + command + ")");
10911498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        Intent intent =
10921498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                new Intent(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
10931498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD, command);
10941498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID,
10951498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                        companyId);
10961498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
10971498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        // assert: all elements of args are Serializable
10981498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS, arguments);
10991498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
11001498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
11011498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    }
11021498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
1103a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    void updateBtHandsfreeAfterRadioTechnologyChange() {
11041498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        if (VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
1105a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
11061dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState.updateBtPhoneStateAfterRadioTechnologyChange();
1107a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    }
1108a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to establish SCO (audio) connection to bluetooth
1110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns false if the user has requested audio off, or if there
1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * is some other immediate problem that will prevent BT audio.
1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean audioOn() {
1115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (VDBG) log("audioOn()");
1116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!isHeadsetConnected()) {
1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): headset is not connected!");
1118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
1119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
11200966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        if (mHeadsetType == TYPE_HANDSFREE && !mServiceConnectionEstablished) {
11210966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly            if (DBG) log("audioOn(): service connection not yet established!");
11220966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly            return false;
11230966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        }
1124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
1126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): audio is already connected");
1127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
1128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mUserWantsAudio) {
1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): user requested no audio, ignoring");
1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
1133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
1136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): outgoing SCO already in progress");
1137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
1138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1139f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
1140f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        if (mPendingSco) {
1141f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            if (DBG) log("audioOn(): SCO already pending");
1142f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            return true;
1143f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        }
1144f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
1145ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent        mA2dpSuspended = false;
1146ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent        mPendingSco = false;
1147f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        if (isA2dpMultiProfile() && mA2dpState == BluetoothA2dp.STATE_PLAYING) {
1148f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            if (DBG) log("suspending A2DP stream for SCO");
1149ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent            mA2dpSuspended = mA2dp.suspendSink(mA2dpDevice);
1150ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent            if (mA2dpSuspended) {
1151ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent                mPendingSco = true;
1152f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                Message msg = mHandler.obtainMessage(MESSAGE_CHECK_PENDING_SCO);
1153f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                mHandler.sendMessageDelayed(msg, 2000);
1154f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            } else {
1155f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                Log.w(TAG, "Could not suspend A2DP stream for SCO, going ahead with SCO");
1156337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly            }
1157337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly        }
1158337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly
1159337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly        if (!mPendingSco) {
1160337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly            mOutgoingSco = createScoSocket();
1161f0316a1fb5c00585d0fe4b500723557afabec70bEric Olsen            if (!mOutgoingSco.connect(mHeadset.getRemoteDevice().getAddress(),
1162f0316a1fb5c00585d0fe4b500723557afabec70bEric Olsen                    mHeadset.getRemoteDevice().getName())) {
1163337c7eb41d344b39efcf740cdc579257152a1c58Nick Pelly                mOutgoingSco = null;
1164f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan            }
1165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
1168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio on.
1171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will establish SCO (BT audio), even if the user requested it off
1172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  previously on this call.
1173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOn() {
1175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
1176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOn();
1177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio off.
1179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will prevent us from establishing BT audio again during this call
1180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  if audioOn() is called.
1181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOff() {
1183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = false;
1184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
1185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to disconnect SCO (audio) connection to bluetooth
1188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
1189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void audioOff() {
1191819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh        if (VDBG) log("audioOff(): mPendingSco: " + mPendingSco +
1192819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                ", mConnectedSco: " + mConnectedSco +
1193819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                ", mOutgoingSco: " + mOutgoingSco  +
1194819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                ", mA2dpState: " + mA2dpState +
1195819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                ", mA2dpSuspended: " + mA2dpSuspended +
1196819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh                ", mIncomingSco:" + mIncomingSco);
1197ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent
1198ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent        if (mA2dpSuspended) {
1199a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent            if (isA2dpMultiProfile()) {
1200a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent              if (DBG) log("resuming A2DP stream after disconnecting SCO");
1201a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent              mA2dp.resumeSink(mA2dpDevice);
1202a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent            }
1203ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent            mA2dpSuspended = false;
1204ab377a6e67c195c230db42e98d597bf4deba14bdEric Laurent        }
1205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1206310e6fb854504637a4cefd123d8dd387660cf811Nick Pelly        mPendingSco = false;
1207310e6fb854504637a4cefd123d8dd387660cf811Nick Pelly
1208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
1209c335ba22b8d739eddaed89b78fad4520abf36b19Nick Pelly            BluetoothDevice device = null;
1210c335ba22b8d739eddaed89b78fad4520abf36b19Nick Pelly            if (mHeadset != null) {
1211c335ba22b8d739eddaed89b78fad4520abf36b19Nick Pelly                device = mHeadset.getRemoteDevice();
1212c335ba22b8d739eddaed89b78fad4520abf36b19Nick Pelly            }
1213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco.close();
1214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco = null;
12151b69b5d702539a74d1511d7467737eddc24b7744Nick Pelly            mAudioManager.setBluetoothScoOn(false);
12161b69b5d702539a74d1511d7467737eddc24b7744Nick Pelly            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED, device);
1217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
1219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco.close();
1220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
1221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1222819fc69ac472a8d77be8e5dd79a21434c6de8a37Jaikumar Ganesh
1223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ boolean isAudioOn() {
1226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (mConnectedSco != null);
1227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1229f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    private boolean isA2dpMultiProfile() {
1230f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan        return mA2dp != null && mHeadset != null && mA2dpDevice != null &&
1231f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan                mA2dpDevice.equals(mHeadset.getRemoteDevice());
1232f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan    }
1233f9f946bc1e3ba287f0fa8f47a662e42f20892526Zhu Lan
1234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void ignoreRing() {
12351dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState.ignoreRing();
1236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void sendURC(String urc) {
1239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isHeadsetConnected()) {
1240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mHeadset.sendURC(urc);
1241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** helper to redial last dialled number */
1245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AtCommandResult redial() {
1246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = mPhonebook.getLastDialledNumber();
1247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number == null) {
1248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // spec seems to suggest sending ERROR if we dont have a
1249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // number to redial
12508eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("Bluetooth redial requested (+BLDN), but no previous " +
1251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                  "outgoing calls found. Ignoring");
1252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
1253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
1255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Uri.fromParts("tel", number, null));
1256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext.startActivity(intent);
1258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // We do not immediately respond OK, wait until we get a phone state
1260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // update. If we return OK now and the handsfree immeidately requests
1261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // our phone state it will say we are not in call yet which confuses
1262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // some devices
1263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        expectCallStart();
1264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
1265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Build the +CLCC result
1268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  The complexity arises from the fact that we need to maintain the same
1269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  CLCC index even as a call moves between states. */
1270c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private synchronized AtCommandResult gsmGetClccResult() {
1271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Collect all known connections
1272c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS];  // indexed by CLCC index
1273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> newConnections = new LinkedList<Connection>();
1274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> connections = new LinkedList<Connection>();
1275a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang
12768058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call foregroundCall = mCM.getActiveFgCall();
12778058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call backgroundCall = mCM.getFirstActiveBgCall();
12788058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call ringingCall = mCM.getFirstActiveRingingCall();
12798058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang
12808058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        if (ringingCall.getState().isAlive()) {
12818058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            connections.addAll(ringingCall.getConnections());
1282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
12838058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        if (foregroundCall.getState().isAlive()) {
12848058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            connections.addAll(foregroundCall.getConnections());
1285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
12868058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        if (backgroundCall.getState().isAlive()) {
12878058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            connections.addAll(backgroundCall.getConnections());
1288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mark connections that we already known about
1291c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS];
1292c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
1293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccUsed[i] = mClccUsed[i];
1294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
1295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (Connection c : connections) {
1297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean found = false;
1298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long timestamp = c.getCreateTime();
1299c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
1300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
1301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClccUsed[i] = true;
1302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    found = true;
1303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    clccConnections[i] = c;
1304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!found) {
1308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newConnections.add(c);
1309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Find a CLCC index for new connections
1313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        while (!newConnections.isEmpty()) {
1314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find lowest empty index
1315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int i = 0;
1316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (mClccUsed[i]) i++;
1317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find earliest connection
1318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long earliestTimestamp = newConnections.get(0).getCreateTime();
1319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Connection earliestConnection = newConnections.get(0);
1320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            for (int j = 0; j < newConnections.size(); j++) {
1321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                long timestamp = newConnections.get(j).getCreateTime();
1322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (timestamp < earliestTimestamp) {
1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestTimestamp = timestamp;
1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestConnection = newConnections.get(j);
1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // update
1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = true;
1330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccTimestamps[i] = earliestTimestamp;
1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccConnections[i] = earliestConnection;
1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            newConnections.remove(earliestConnection);
1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Build CLCC
1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int i = 0; i < clccConnections.length; i++) {
1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mClccUsed[i]) {
1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String clccEntry = connectionToClccEntry(i, clccConnections[i]);
1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccEntry != null) {
1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(clccEntry);
1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Convert a Connection object into a single +CLCC result */
1350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private String connectionToClccEntry(int index, Connection c) {
1351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int state;
1352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (c.getState()) {
1353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ACTIVE:
1354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 0;
1355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case HOLDING:
1357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 1;
1358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case DIALING:
1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 2;
1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ALERTING:
1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 3;
1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case INCOMING:
1366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 4;
1367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case WAITING:
1369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 5;
1370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        default:
1372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;  // bad state
1373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int mpty = 0;
1376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call call = c.getCall();
1377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (call != null) {
1378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mpty = call.isMultiparty() ? 1 : 0;
1379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int direction = c.isIncoming() ? 1 : 0;
1382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = c.getAddress();
1384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int type = -1;
1385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            type = PhoneNumberUtils.toaFromString(number);
1387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
1390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result += ",\"" + number + "\"," + type;
1392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
1394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1395c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1396c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    /** Build the +CLCC result for CDMA
1397c9d9ed30aa547b79b81adc13a4d148a003b6ee62w     *  The complexity arises from the fact that we need to maintain the same
1398c9d9ed30aa547b79b81adc13a4d148a003b6ee62w     *  CLCC index even as a call moves between states. */
1399c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private synchronized AtCommandResult cdmaGetClccResult() {
1400c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // In CDMA at one time a user can have only two live/active connections
1401c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index
14028058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call foregroundCall = mCM.getActiveFgCall();
14038058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call ringingCall = mCM.getFirstActiveRingingCall();
1404c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
14058058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        Call.State ringingCallState = ringingCall.getState();
1406c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // If the Ringing Call state is INCOMING, that means this is the very first call
1407c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // hence there should not be any Foreground Call
1408c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (ringingCallState == Call.State.INCOMING) {
14098eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("Filling clccConnections[0] for INCOMING state");
14108058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            clccConnections[0] = ringingCall.getLatestConnection();
14118058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        } else if (foregroundCall.getState().isAlive()) {
1412c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // Getting Foreground Call connection based on Call state
14138058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang            if (ringingCall.isRinging()) {
14148eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state");
14158058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                clccConnections[0] = foregroundCall.getEarliestConnection();
14168058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                clccConnections[1] = ringingCall.getLatestConnection();
1417c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            } else {
14188058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                if (foregroundCall.getConnections().size() <= 1) {
1419c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // Single call scenario
14208eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                    if (VDBG) log("Filling clccConnections[0] with ForgroundCall latest connection");
14218058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    clccConnections[0] = foregroundCall.getLatestConnection();
1422c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                } else {
1423c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // Multiple Call scenario. This would be true for both
1424c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // CONF_CALL and THRWAY_ACTIVE state
14258eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                    if (VDBG) log("Filling clccConnections[0] & [1] with ForgroundCall connections");
14268058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    clccConnections[0] = foregroundCall.getEarliestConnection();
14278058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    clccConnections[1] = foregroundCall.getLatestConnection();
1428c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1429c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1430c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1431c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1432c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // Update the mCdmaIsSecondCallActive flag based on the Phone call state
1433c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1434c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
1435c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            cdmaSetSecondCallState(false);
1436c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1437c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
1438c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            cdmaSetSecondCallState(true);
1439c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1440c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1441c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // Build CLCC
1442c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
1443c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) {
1444c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            String clccEntry = cdmaConnectionToClccEntry(i, clccConnections[i]);
1445c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            if (clccEntry != null) {
1446c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                result.addResponse(clccEntry);
1447c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1448c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1449c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1450c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        return result;
1451c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
1452c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1453c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    /** Convert a Connection object into a single +CLCC result for CDMA phones */
1454c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private String cdmaConnectionToClccEntry(int index, Connection c) {
1455c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int state;
1456c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        PhoneApp app = PhoneApp.getInstance();
1457c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        CdmaPhoneCallState.PhoneCallState currCdmaCallState =
1458c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                app.cdmaPhoneCallState.getCurrentCallState();
1459c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
1460c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                app.cdmaPhoneCallState.getPreviousCallState();
1461c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1462c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
1463c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) {
1464c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // If the current state is reached after merging two calls
1465c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // we set the state of all the connections as ACTIVE
1466c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            state = 0;
1467c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else {
1468c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            switch (c.getState()) {
1469c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case ACTIVE:
1470c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // For CDMA since both the connections are set as active by FW after accepting
1471c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // a Call waiting or making a 3 way call, we need to set the state specifically
1472c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the
1473c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // CLCC result will allow BT devices to enable the swap or merge options
1474c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                if (index == 0) { // For the 1st active connection
1475c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    state = mCdmaIsSecondCallActive ? 1 : 0;
1476c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                } else { // for the 2nd active connection
1477c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    state = mCdmaIsSecondCallActive ? 0 : 1;
1478c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1479c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1480c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case HOLDING:
1481c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 1;
1482c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1483c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case DIALING:
1484c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 2;
1485c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1486c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case ALERTING:
1487c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 3;
1488c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1489c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case INCOMING:
1490c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 4;
1491c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1492c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case WAITING:
1493c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 5;
1494c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1495c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            default:
1496c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                return null;  // bad state
1497c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1498c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1499c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1500c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int mpty = 0;
15013eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu        if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
1502c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi            if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
1503c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // If the current state is reached after merging two calls
1504c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // we set the multiparty call true.
1505c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                mpty = 1;
1506c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi            } else {
1507c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // CALL_CONF state is not from merging two calls, but from
1508c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // accepting the second call. In this case first will be on
1509c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // hold in most cases but in some cases its already merged.
1510c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // However, we will follow the common case and the test case
1511c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                // as per Bluetooth SIG PTS
1512c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi                mpty = 0;
1513c39c3c9ada26aa8fab1373ad94c9b0d9e8875caaSrinivas Krovvidi            }
15143eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu        } else {
15153eb2a4ae98eb737004d40f7ce03a8d83883fb079Kuanting Zhu            mpty = 0;
1516c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1517c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1518c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int direction = c.isIncoming() ? 1 : 0;
1519c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1520c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        String number = c.getAddress();
1521c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int type = -1;
1522c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (number != null) {
1523c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            type = PhoneNumberUtils.toaFromString(number);
1524c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1525c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1526c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
1527c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (number != null) {
1528c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            result += ",\"" + number + "\"," + type;
1529c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1530c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        return result;
1531c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
1532c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
15331498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    /*
15341498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * Register a vendor-specific command.
15351498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * @param commandName the name of the command.  For example, if the expected
15361498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * incoming command is <code>AT+FOO=bar,baz</code>, the value of this should be
15371498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * <code>"+FOO"</code>.
15381498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * @param companyId the Bluetooth SIG Company Identifier
15391498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * @param parser the AtParser on which to register the command
15401498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     */
15411498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    private void registerVendorSpecificCommand(String commandName,
15421498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                               int companyId,
15431498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                               AtParser parser) {
15441498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        parser.register(commandName,
15451498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                        new VendorSpecificCommandHandler(commandName, companyId));
15461498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    }
15471498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
15481498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    /*
15491498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * Register all vendor-specific commands here.
15501498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     */
15511498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    private void registerAllVendorSpecificCommands() {
15521498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        AtParser parser = mHeadset.getAtParser();
15531498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
15541498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        // Plantronics-specific headset events go here
15551498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        registerVendorSpecificCommand("+XEVENT",
15561498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                      BluetoothAssignedNumbers.PLANTRONICS,
15571498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                      parser);
15581498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    }
15591498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
1560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Headset profile
1562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHeadsetAtParser() {
15648eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("Registering Headset AT commands");
1565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
15661498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        // Headsets usually only have one button, which is meant to cause the
1567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // HS to send us AT+CKPD=200 or AT+CKPD.
1568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CKPD", new AtCommandHandler() {
1569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult headsetButtonPress() {
15708058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                if (mCM.getFirstActiveRingingCall().isRinging()) {
1571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Answer the call
15721ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                    mBluetoothPhoneState.stopRing();
15731ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                    sendURC("OK");
15748058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
1575a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly                    // If in-band ring tone is supported, SCO connection will already
1576a23972e3605fb235897250fd4edc2b70be13e00dNick Pelly                    // be up and the following call will just return.
1577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
15781ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                    return new AtCommandResult(AtCommandResult.UNSOLICITED);
15798058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                } else if (mCM.hasActiveFgCall()) {
1580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (!isAudioOn()) {
1581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Transfer audio from AG to HS
1582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
1583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mHeadset.getDirection() == HeadsetBase.DIRECTION_INCOMING &&
1585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                          (System.currentTimeMillis() - mHeadset.getConnectTimestamp()) < 5000) {
1586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Headset made a recent ACL connection to us - and
1587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // made a mandatory AT+CKPD request to connect
1588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // audio which races with our automatic audio
1589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // setup.  ignore
1590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Hang up the call
1592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            audioOff();
15938343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                            PhoneUtils.hangup(PhoneApp.getInstance().mCM);
1594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
15961ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                    return new AtCommandResult(AtCommandResult.OK);
1597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // No current call - redial last number
1599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return redial();
1600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Handsfree profile
1615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHandsfreeAtParser() {
16178eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("Registering Handsfree AT commands");
1618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
16198058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang        final Phone phone = mCM.getDefaultPhone();
1620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Answer
1622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('A', new AtCommandHandler() {
1623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
16251ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                sendURC("OK");
16261ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                mBluetoothPhoneState.stopRing();
16278058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
16281ec7e6b9b3bf1dfc384676244bec1edb50fedc58Jaikumar Ganesh                return new AtCommandResult(AtCommandResult.UNSOLICITED);
1629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('D', new AtCommandHandler() {
1632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
1634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length() > 0) {
1635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args.charAt(0) == '>') {
1636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Yuck - memory dialling requested.
1637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Just dial last number for now
1638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.startsWith(">9999")) {   // for PTS test
1639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return redial();
1642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Remove trailing ';'
1644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.charAt(args.length() - 1) == ';') {
1645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            args = args.substring(0, args.length() - 1);
1646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
1648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                Uri.fromParts("tel", args, null));
1649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mContext.startActivity(intent);
1651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        expectCallStart();
1653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
1654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Hang-up command
1661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHUP", new AtCommandHandler() {
1662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1664586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh                sendURC("OK");
16658058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                if (mCM.hasActiveFgCall()) {
16668058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    PhoneUtils.hangupActiveCall(mCM.getActiveFgCall());
16678058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                } else if (mCM.hasActiveRingingCall()) {
16688058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall());
16698058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                } else if (mCM.hasActiveBgCall()) {
16708058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                    PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall());
1671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1672586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh                return new AtCommandResult(AtCommandResult.UNSOLICITED);
1673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Retrieve Supported Features command
1677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BRSF", new AtCommandHandler() {
1678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult sendBRSF() {
1679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+BRSF: " + mLocalBrsf);
1680b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+BRSF=<handsfree supported features bitmap>
1684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is telling us which features it supports. We
1685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // send the features we support
1686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 1 && (args[0] instanceof Integer)) {
1687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRemoteBrsf = (Integer) args[0];
1688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Log.w(TAG, "HF didn't sent BRSF assuming 0");
1690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call waiting notification on/off
1706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CCWA", new AtCommandHandler() {
1707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Seems to be out of spec, but lets return nicely
1710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Call waiting is always on
1715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: 1");
1716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CCWA=<n>
1720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is trying to enable/disable call waiting. We
1721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // cannot disable in the current implementation.
1722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Request for range of supported CCWA paramters
1727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: (\"n\",(1))");
1728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Event Reporting enable/disable command
1732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Of the full 3GPP syntax paramters (mode, keyp, disp, ind, bfr) we
1733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // only support paramter ind (disable/enable evert reporting using
1734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // +CDEV)
1735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMER", new AtCommandHandler() {
1736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(
1739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "+CMER: 3,0,0," + (mIndicatorsEnabled ? "1" : "0"));
1740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length < 4) {
1744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This is a syntax error
1745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(3) && args[1].equals(0) &&
1747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           args[2].equals(0)) {
17480966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    boolean valid = false;
1749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[3].equals(0)) {
1750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = false;
17510966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        valid = true;
1752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[3].equals(1)) {
1753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = true;
17540966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        valid = true;
17550966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    }
17560966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    if (valid) {
17570966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) == 0x0) {
17580966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            mServiceConnectionEstablished = true;
17590966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            sendURC("OK");  // send immediately, then initiate audio
17600966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            if (isIncallAudio()) {
17610966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                                audioOn();
1762179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                            } else if (mCM.getFirstActiveRingingCall().isRinging()) {
1763179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                                // need to update HS with RING cmd when single
1764179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                                // ringing call exist
1765179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                                mBluetoothPhoneState.ring();
17660966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            }
17670966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            // only send OK once
17680966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            return new AtCommandResult(AtCommandResult.UNSOLICITED);
17690966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        } else {
17700966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            return new AtCommandResult(AtCommandResult.OK);
17710966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        }
1772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
17740966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMER: (3),(0),(0),(0-1)");
1779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Error Reporting enable/disable
1783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMEE", new AtCommandHandler() {
1784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // out of spec, assume they want to enable
1787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCmee = true;
1788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: " + (mCmee ? "1" : "0"));
1793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CMEE=<n>
1797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 0) {
1798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // <n> ommitted - default to 0
1799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = false;
1800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!(args[0] instanceof Integer)) {
1802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Syntax error
1803b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1804b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1805b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = ((Integer)args[0] == 1);
1806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Probably not required but spec, but no harm done
1812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: (0-1)");
1813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Last Dialled Number
1817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BLDN", new AtCommandHandler() {
1818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return redial();
1821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Indicator Update command
1825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIND", new AtCommandHandler() {
1826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
18281dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.toCindResult();
1829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
18321dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.getCindTestResult();
1833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query Signal Quality (legacy)
1837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CSQ", new AtCommandHandler() {
1838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
18401dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.toCsqResult();
1841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query network registration state
1845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CREG", new AtCommandHandler() {
1846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
18481dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return new AtCommandResult(mBluetoothPhoneState.toCregString());
1849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Send DTMF. I don't know if we are also expected to play the DTMF tone
1853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // locally, right now we don't
1854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VTS", new AtCommandHandler() {
1855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    char c;
1859b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0] instanceof Integer) {
1860b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((Integer) args[0]).toString().charAt(0);
1861b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((String) args[0]).charAt(0);
1863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (isValidDtmf(c)) {
18658058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                        phone.sendDtmf(c);
1866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1867b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1868b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1869b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private boolean isValidDtmf(char c) {
1872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (c) {
1873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '#':
1874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '*':
1875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return true;
1876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                default:
1877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (Character.digit(c, 14) != -1) {
1878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return true;  // 0-9 and A-D
1879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return false;
1881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // List calls
1886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLCC", new AtCommandHandler() {
1887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1888b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
18898058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                int phoneType = phone.getPhoneType();
189079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneType == Phone.PHONE_TYPE_CDMA) {
1891c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    return cdmaGetClccResult();
189279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                } else if (phoneType == Phone.PHONE_TYPE_GSM) {
1893c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    return gsmGetClccResult();
189479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                } else {
189579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                    throw new IllegalStateException("Unexpected phone type: " + phoneType);
1896c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1897b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1898b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1899b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call Hold and Multiparty Handling command
1901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHLD", new AtCommandHandler() {
1902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
19048058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                int phoneType = phone.getPhoneType();
19058058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                Call ringingCall = mCM.getFirstActiveRingingCall();
19068058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                Call backgroundCall = mCM.getFirstActiveBgCall();
19078058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang
1908b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1909b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0].equals(0)) {
1910b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        boolean result;
19118058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                        if (ringingCall.isRinging()) {
19128058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            result = PhoneUtils.hangupRingingCall(ringingCall);
1913b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
19148058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            result = PhoneUtils.hangupHoldingCall(backgroundCall);
1915b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1916b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (result) {
1917b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
1918b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1919b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1920b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1921b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(1)) {
192279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        if (phoneType == Phone.PHONE_TYPE_CDMA) {
19238058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            if (ringingCall.isRinging()) {
1924c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // If there is Call waiting then answer the call and
1925c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // put the first call on hold.
19268eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:1 Callwaiting Answer call");
19278058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                                PhoneUtils.answerCall(ringingCall);
1928a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                                PhoneUtils.setMute(false);
1929c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Setting the second callers state flag to TRUE (i.e. active)
1930c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSetSecondCallState(true);
1931c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            } else {
1932c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // If there is no Call waiting then just hangup
1933c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // the active call. In CDMA this mean that the complete
1934c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // call session would be ended
19358eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:1 Hangup Call");
19368343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                                PhoneUtils.hangup(PhoneApp.getInstance().mCM);
1937c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
1938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
193979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else if (phoneType == Phone.PHONE_TYPE_GSM) {
1940a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // Hangup active call, answer held call
19418343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                            if (PhoneUtils.answerAndEndActive(
19428058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                                    PhoneApp.getInstance().mCM, ringingCall)) {
1943a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                return new AtCommandResult(AtCommandResult.OK);
1944a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            } else {
1945a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                return new AtCommandResult(AtCommandResult.ERROR);
1946a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            }
194779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else {
194879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
1949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(2)) {
195179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        if (phoneType == Phone.PHONE_TYPE_CDMA) {
1952a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // For CDMA, the way we switch to a new incoming call is by
1953a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // calling PhoneUtils.answerCall(). switchAndHoldActive() won't
1954a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // properly update the call state within telephony.
1955c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // If the Phone state is already in CONF_CALL then we simply send
1956c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // a flash cmd by calling switchHoldingAndActive()
19578058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            if (ringingCall.isRinging()) {
19588eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:2 Callwaiting Answer call");
19598058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                                PhoneUtils.answerCall(ringingCall);
1960a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                                PhoneUtils.setMute(false);
1961c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Setting the second callers state flag to TRUE (i.e. active)
1962c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSetSecondCallState(true);
1963c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            } else if (PhoneApp.getInstance().cdmaPhoneCallState
1964c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    .getCurrentCallState()
1965c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
19668eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:2 Swap Calls");
19678058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                                PhoneUtils.switchHoldingAndActive(backgroundCall);
1968c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Toggle the second callers active state flag
1969c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSwapSecondCallState();
1970c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
197179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else if (phoneType == Phone.PHONE_TYPE_GSM) {
19728058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            PhoneUtils.switchHoldingAndActive(backgroundCall);
197379b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else {
197479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
1975a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                        }
1976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(3)) {
197879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        if (phoneType == Phone.PHONE_TYPE_CDMA) {
1979c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // For CDMA, we need to check if the call is in THRWAY_ACTIVE state
1980c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1981c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
19828eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:3 Merge Calls");
1983b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                                PhoneUtils.mergeCalls();
1984c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
198579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else if (phoneType == Phone.PHONE_TYPE_GSM) {
19868058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                            if (mCM.hasActiveFgCall() && mCM.hasActiveBgCall()) {
1987b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                                PhoneUtils.mergeCalls();
1988c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
198979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                        } else {
199079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
1991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
19990966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                mServiceConnectionEstablished = true;
2000d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly                sendURC("+CHLD: (0,1,2,3)");
2001d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly                sendURC("OK");  // send reply first, then connect audio
20020966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                if (isIncallAudio()) {
20030966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    audioOn();
2004179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                } else if (mCM.getFirstActiveRingingCall().isRinging()) {
2005179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                    // need to update HS with RING when single ringing call exist
2006179bbc0b646d7af4cb6662927c7a3e7a36332dedSrinivas Krovvidi                    mBluetoothPhoneState.ring();
20070966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                }
20080966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                // already replied
20090966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                return new AtCommandResult(AtCommandResult.UNSOLICITED);
2010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Get Network operator name
2014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+COPS", new AtCommandHandler() {
2015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
20178058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                String operatorName = phone.getServiceState().getOperatorAlphaLong();
2018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (operatorName != null) {
2019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (operatorName.length() > 16) {
2020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        operatorName = operatorName.substring(0, 16);
2021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
2022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
2023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            "+COPS: 0,0,\"" + operatorName + "\"");
2024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2025b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
20265b58955238953dd3c689b1d1342cb9d79ec3e9deJesper Hansson                            "+COPS: 0");
2027b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree only supports AT+COPS=3,0
2032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 2 || !(args[0] instanceof Integer)
2033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    || !(args[1] instanceof Integer)) {
2034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // syntax error
2035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
2036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if ((Integer)args[0] != 3 || (Integer)args[1] != 0) {
2037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
2038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
2044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Out of spec, but lets be friendly
2045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+COPS: (3),(0)");
2046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile PIN
2050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CPIN is not in the handsfree spec (although it is in 3GPP)
2051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPIN", new AtCommandHandler() {
2052b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
2054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPIN: READY");
2055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Response and Hold
2059b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Only supported on PDC (Japan) and CDMA networks.
2060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BTRH", new AtCommandHandler() {
2061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
2063b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Replying with just OK indicates no response and hold
2064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // features in use now
2065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
2066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Neeed PDC or CDMA
2070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
2071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Request International Mobile Subscriber Identity (IMSI)
2075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Not in bluetooth handset spec
2076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIMI", new AtCommandHandler() {
2077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
2079b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CIMI
20808058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                String imsi = phone.getSubscriberId();
2081b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (imsi == null || imsi.length() == 0) {
2082b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.SIM_FAILURE);
2083b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2084b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(imsi);
2085b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Calling Line Identification Presentation
2090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLIP", new AtCommandHandler() {
2091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
2093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Currently assumes the network is provisioned for CLIP
2094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: " + (mClip ? "1" : "0") + ",1");
2095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CLIP=<n>
2099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && (args[0].equals(0) || args[0].equals(1))) {
2100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClip = args[0].equals(1);
2101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
2104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
2108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: (0-1)");
2109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGSN - Returns the device IMEI number.
2113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGSN", new AtCommandHandler() {
2114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
2116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Get the IMEI of the device.
21178058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                // phone will not be NULL at this point.
21188058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                return new AtCommandResult("+CGSN: " + phone.getDeviceId());
2119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMM - Query Model Information
2123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMM", new AtCommandHandler() {
2124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
2126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
2127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String model = SystemProperties.get("ro.product.model");
2128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (model != null) {
2129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMM: " + model);
2130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
2132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMI - Query Manufacturer Information
2137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMI", new AtCommandHandler() {
2138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
2140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
2141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String manuf = SystemProperties.get("ro.product.manufacturer");
2142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (manuf != null) {
2143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMI: " + manuf);
2144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
2145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
2146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Noise Reduction and Echo Cancellation control
2151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+NREC", new AtCommandHandler() {
2152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args[0].equals(0)) {
2155aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent                    mAudioManager.setParameters(HEADSET_NREC+"=off");
2156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(1)) {
2158aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent                    mAudioManager.setParameters(HEADSET_NREC+"=on");
2159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
2162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Voice recognition (dialing)
2166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BVRA", new AtCommandHandler() {
2167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2169b8dbab241df3aa3487c1bdb488fd4e0b694d2d9aEric Laurent                if (!BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) {
21706967e2d953bc077c99c4831946201f3d333b833fNick Pelly                    return new AtCommandResult(AtCommandResult.ERROR);
21716967e2d953bc077c99c4831946201f3d333b833fNick Pelly                }
2172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && args[0].equals(1)) {
2173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    synchronized (BluetoothHandsfree.this) {
2174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (!mWaitingForVoiceRecognition) {
2175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            try {
2176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                mContext.startActivity(sVoiceCommandIntent);
2177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            } catch (ActivityNotFoundException e) {
2178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                return new AtCommandResult(AtCommandResult.ERROR);
2179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            }
2180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            expectVoiceRecognition();
2181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
2182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
2183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing yet
2184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args.length >= 1 && args[0].equals(0)) {
2185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOff();
2186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
2189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
21926967e2d953bc077c99c4831946201f3d333b833fNick Pelly                return new AtCommandResult("+BVRA: (0-1)");
2193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Retrieve Subscriber Number
2197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CNUM", new AtCommandHandler() {
2198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
22008058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                String number = phone.getLine1Number();
2201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
2202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
2203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CNUM: ,\"" + number + "\"," +
2205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        PhoneNumberUtils.toaFromString(number) + ",,4");
2206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Microphone Gain
2210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGM", new AtCommandHandler() {
2211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGM=<gain>    in range [0,15]
2214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Headset/Handsfree is reporting its current gain setting
2215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
2216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Speaker Gain
2220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGS", new AtCommandHandler() {
2221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
2223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGS=<gain>    in range [0,15]
2224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 1 || !(args[0] instanceof Integer)) {
2225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
2226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mScoGain = (Integer) args[0];
2228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int flag =  mAudioManager.isBluetoothScoOn() ? AudioManager.FLAG_SHOW_UI:0;
2229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, mScoGain, flag);
2231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
2232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
2234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Phone activity status
2236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPAS", new AtCommandHandler() {
2237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
2238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
2239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int status = 0;
22408058bbc4c7d0d56e133bd2fb9dfc559004e4d61aJohn Wang                switch (mCM.getState()) {
2241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case IDLE:
2242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 0;
2243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
2244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RINGING:
2245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 3;
2246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
2247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case OFFHOOK:
2248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 4;
2249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
2250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPAS: " + status);
2252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
22541498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
2255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook.register(parser);
2256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void sendScoGainUpdate(int gain) {
2259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mScoGain != gain && (mRemoteBrsf & BRSF_HF_REMOTE_VOL_CONTROL) != 0x0) {
2260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+VGS:" + gain);
2261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mScoGain = gain;
2262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public AtCommandResult reportCmeError(int error) {
2266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mCmee) {
2267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
2268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse("+CME ERROR: " + error);
2269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
2270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
2271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
2272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_CALL_TIMEOUT = 10000;  // ms
2276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectCallStart() {
2278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForCallStart = true;
2279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_CALL_STARTED);
2280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_CALL_TIMEOUT);
2281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartCallWakeLock.isHeld()) {
2282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartCallWakeLock.acquire(START_CALL_TIMEOUT);
2283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void callStarted() {
2287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForCallStart) {
2288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForCallStart = false;
2289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
2290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mStartCallWakeLock.isHeld()) {
2291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStartCallWakeLock.release();
2292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_VOICE_RECOGNITION_TIMEOUT = 5000;  // ms
2297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectVoiceRecognition() {
2299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForVoiceRecognition = true;
2300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_VOICE_RECOGNITION_STARTED);
2301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_VOICE_RECOGNITION_TIMEOUT);
2302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartVoiceRecognitionWakeLock.isHeld()) {
2303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.acquire(START_VOICE_RECOGNITION_TIMEOUT);
2304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean startVoiceRecognition() {
2308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForVoiceRecognition) {
2309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // HF initiated
2310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForVoiceRecognition = false;
2311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
2312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
2313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // AG initiated
2314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+BVRA: 1");
2315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean ret = audioOn();
2317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mStartVoiceRecognitionWakeLock.isHeld()) {
2318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.release();
2319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return ret;
2321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean stopVoiceRecognition() {
2324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        sendURC("+BVRA: 0");
2325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
2326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
2327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
23291498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    /*
23301498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     * This class broadcasts vendor-specific commands + arguments to interested receivers.
23311498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek     */
23321498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    private class VendorSpecificCommandHandler extends AtCommandHandler {
23331498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
23341498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        private String mCommandName;
23351498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
23361498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        private int mCompanyId;
23371498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
23381498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        private VendorSpecificCommandHandler(String commandName, int companyId) {
23391498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek            mCommandName = commandName;
23401498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek            mCompanyId = companyId;
23411498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        }
23421498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
23431498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        @Override
23441498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        public AtCommandResult handleSetCommand(Object[] arguments) {
23451498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek            broadcastVendorSpecificEventIntent(mCommandName,
23461498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                               mCompanyId,
23471498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                               arguments,
23481498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek                                               mHeadset.getRemoteDevice());
23491498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek            return new AtCommandResult(AtCommandResult.OK);
23501498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek        }
23511498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek    }
23521498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek
2353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean inDebug() {
2354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return DBG && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE, false);
2355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean allowAudioAnytime() {
2358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return inDebug() && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE_AUDIO_ANYTIME,
2359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                false);
2360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void startDebug() {
2363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG && mDebugThread == null) {
2364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = new DebugThread();
2365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.start();
2366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void stopDebug() {
2370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mDebugThread != null) {
2371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.interrupt();
2372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = null;
2373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Debug thread to read debug properties - runs when debug.bt.hfp is true
2377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  at the time a bluetooth handsfree device is connected. Debug properties
2378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  are polled and mock updates sent every 1 second */
2379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class DebugThread extends Thread {
2380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Turns on/off handsfree profile debugging mode */
2381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE = "debug.bt.hfp";
2382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock battery level change - use 0 to 5 */
2384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_BATTERY = "debug.bt.hfp.battery";
2385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock no cellular service when false */
2387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SERVICE = "debug.bt.hfp.service";
2388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock cellular roaming when true */
2390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_ROAM = "debug.bt.hfp.roam";
2391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** false to true transition will force an audio (SCO) connection to
2393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         *  be established. true to false will force audio to be disconnected
2394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO = "debug.bt.hfp.audio";
2396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** true allows incoming SCO connection out of call.
2398b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2399b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO_ANYTIME = "debug.bt.hfp.audio_anytime";
2400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock signal strength change in ASU - use 0 to 31 */
2402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SIGNAL = "debug.bt.hfp.signal";
2403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+CLCC: print +CLCC result */
2405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_CLCC = "debug.bt.hfp.clcc";
2406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+BSIR - Send In Band Ringtones Unsolicited AT command.
2408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 0 => AT+BSIR = 0 sent by the AG
2409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 1 => AT+BSIR = 0 sent by the AG
2410b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Other values are ignored.
2411b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2412b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2413b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_UNSOL_INBAND_RINGTONE =
2414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            "debug.bt.unsol.inband";
2415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
2417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public void run() {
2418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldService = true;
2419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldRoam = false;
2420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldAudio = false;
2421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (!isInterrupted() && inDebug()) {
2423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int batteryLevel = SystemProperties.getInt(DEBUG_HANDSFREE_BATTERY, -1);
2424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (batteryLevel >= 0 && batteryLevel <= 5) {
2425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
2426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("level", batteryLevel);
2427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("scale", 5);
24281dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateBatteryState(intent);
2429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                boolean serviceStateChanged = false;
2432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_SERVICE, true) != oldService) {
2433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldService = !oldService;
2434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
2435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2436b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_ROAM, false) != oldRoam) {
2437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldRoam = !oldRoam;
2438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
2439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (serviceStateChanged) {
2441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Bundle b = new Bundle();
2442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putInt("state", oldService ? 0 : 1);
2443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putBoolean("roaming", oldRoam);
24441dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateServiceState(true, ServiceState.newFromBundle(b));
2445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_AUDIO, false) != oldAudio) {
2448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldAudio = !oldAudio;
2449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (oldAudio) {
2450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
2451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
2452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOff();
2453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
2454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1);
2457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (signalLevel >= 0 && signalLevel <= 31) {
2458404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1,
2459404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                            -1, -1, -1, true);
2460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
2461404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    Bundle data = new Bundle();
2462404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    signalStrength.fillInNotifierBundle(data);
2463404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    intent.putExtras(data);
24641dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateSignalState(intent);
2465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_CLCC, false)) {
2468c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    log(gsmGetClccResult().toString());
2469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                try {
2471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sleep(1000);  // 1 second
2472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } catch (InterruptedException e) {
2473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
2474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int inBandRing =
2477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    SystemProperties.getInt(DEBUG_UNSOL_INBAND_RINGTONE, -1);
2478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (inBandRing == 0 || inBandRing == 1) {
2479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result =
2480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        new AtCommandResult(AtCommandResult.UNSOLICITED);
2481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+BSIR: " + inBandRing);
2482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC(result.toString());
2483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2488c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    public void cdmaSwapSecondCallState() {
24898eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("cdmaSetSecondCallState: Toggling mCdmaIsSecondCallActive");
2490c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive;
2491c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
2492c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
2493c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    public void cdmaSetSecondCallState(boolean state) {
24948eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state);
2495c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mCdmaIsSecondCallActive = state;
2496c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
2497c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
2498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static void log(String msg) {
2499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Log.d(TAG, msg);
2500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
2502