BluetoothHandsfree.java revision 586668fe6a1259083fbbc67de8ecac850c1475f1
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;
22db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pellyimport android.bluetooth.BluetoothAdapter;
23b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
244079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Projectimport android.bluetooth.BluetoothHeadset;
254079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Projectimport android.bluetooth.BluetoothIntent;
26b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.HeadsetBase;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.ScoSocket;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.ActivityNotFoundException;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.IntentFilter;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.AsyncResult;
36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler;
38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message;
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager;
40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager.WakeLock;
41b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.SystemProperties;
42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.ServiceState;
44404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.telephony.SignalStrength;
45b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Call;
48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Connection;
49b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Phone;
50b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.TelephonyIntents;
51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.LinkedList;
53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Bluetooth headset manager for the Phone app.
55b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * @hide
56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class BluetoothHandsfree {
58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String TAG = "BT HS/HF";
598eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1)
608eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            && (SystemProperties.getInt("ro.debuggable", 0) == 1);
618eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);  // even more logging
62b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_UNKNOWN           = 0;
64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HEADSET           = 1;
65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HANDSFREE         = 2;
66b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
674079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private final Context mContext;
684079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private final Phone mPhone;
69b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ServiceState mServiceState;
70b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private HeadsetBase mHeadset;  // null when not connected
71b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mHeadsetType;
72b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mAudioPossible;
73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mIncomingSco;
74b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mOutgoingSco;
75b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mConnectedSco;
76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mForegroundCall;
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mBackgroundCall;
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mRingingCall;
80b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AudioManager mAudioManager;
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private PowerManager mPowerManager;
83b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mUserWantsAudio;
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
86b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartVoiceRecognitionWakeLock;  // held while waiting for voice recognition
87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
88b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // AT command state
89c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private static final int GSM_MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
90c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private static final int CDMA_MAX_CONNECTIONS = 2;  // Max connections allowed by CDMA
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
92b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long mBgndEarliestConnectionTime = 0;
93b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mClip = false;  // Calling Line Information Presentation
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mIndicatorsEnabled = false;
95b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mCmee = false;  // Extended Error reporting
96b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long[] mClccTimestamps; // Timestamps associated with each clcc index
97b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean[] mClccUsed;     // Is this clcc index in use
98b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForCallStart;
99b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForVoiceRecognition;
1000966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // do not connect audio until service connection is established
1010966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // for 3-way supported devices, this is after AT+CHLD
1020966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    // for non-3-way supported devices, this is after AT+CMER (see spec)
1030966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly    private boolean mServiceConnectionEstablished;
104db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly
1051dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh    private final BluetoothPhoneState mBluetoothPhoneState;  // for CIND and CIEV updates
106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final BluetoothAtPhonebook mPhonebook;
1071dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh    private Phone.State mPhoneState = Phone.State.IDLE;
108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private DebugThread mDebugThread;
110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mScoGain = Integer.MIN_VALUE;
111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static Intent sVoiceCommandIntent;
113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Audio parameters
115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NREC = "bt_headset_nrec";
116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NAME = "bt_headset_name";
117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mRemoteBrsf = 0;
119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mLocalBrsf = 0;
120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
121c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // CDMA specific flag used in context with BT devices having display capabilities
122c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // to show which Caller is active. This state might not be always true as in CDMA
123c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // networks if a caller drops off no update is provided to the Phone.
124c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // This flag is just used as a toggle to provide a update to the BT device to specify
125c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    // which caller is active.
126c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private boolean mCdmaIsSecondCallActive = false;
127c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */
1296967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
1306967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_EC_NR = 1 << 1;
1316967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_RECOG = 1 << 2;
1326967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_IN_BAND_RING = 1 << 3;
1336967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
1346967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_REJECT_CALL = 1 << 5;
1356967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
1366967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
1376967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
1386967e2d953bc077c99c4831946201f3d333b833fNick Pelly
1396967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_EC_NR = 1 << 0;
1406967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
1416967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CLIP = 1 << 2;
1426967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
1436967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
1446967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
1456967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static String typeToString(int type) {
148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (type) {
149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_UNKNOWN:
150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "unknown";
151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HEADSET:
152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "headset";
153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HANDSFREE:
154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "handsfree";
155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return null;
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public BluetoothHandsfree(Context context, Phone phone) {
160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhone = phone;
161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext = context;
162db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        BluetoothAdapter adapter =
163db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
164db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        boolean bluetoothCapable = (adapter != null);
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;  // nothing connected yet
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":StartCall");
170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock.setReferenceCounted(false);
171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":VoiceRecognition");
173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock.setReferenceCounted(false);
174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mLocalBrsf = BRSF_AG_THREE_WAY_CALLING |
176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_EC_NR |
177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_REJECT_CALL |
178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_ENHANCED_CALL_STATUS;
1794b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project
180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (sVoiceCommandIntent == null) {
181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1846967e2d953bc077c99c4831946201f3d333b833fNick Pelly        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null &&
1856967e2d953bc077c99c4831946201f3d333b833fNick Pelly                !BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLocalBrsf |= BRSF_AG_VOICE_RECOG;
187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (bluetoothCapable) {
190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            resetAtState();
191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mRingingCall = mPhone.getRingingCall();
194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mForegroundCall = mPhone.getForegroundCall();
195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mBackgroundCall = mPhone.getBackgroundCall();
1961dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState = new BluetoothPhoneState();
197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook = new BluetoothAtPhonebook(mContext, this);
199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
200c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        cdmaSetSecondCallState(false);
201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothEnabled() {
204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* Bluez has a bug where it will always accept and then orphan
205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * incoming SCO connections, regardless of whether we have a listening
206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * SCO socket. So the best thing to do is always run a listening socket
207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * while bluetooth is on so that at least we can diconnect it
208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * immediately when we don't want it.
209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco == null) {
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = createScoSocket();
212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.accept();
213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothDisabled() {
217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mAudioManager.setBluetoothScoOn(false);
219db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED,
220db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                    mHeadset.getRemoteDevice());
221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco.close();
222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco = null;
223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco.close();
226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco != null) {
229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.close();
230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = null;
231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isHeadsetConnected() {
235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadset == null) {
236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mHeadset.isConnected();
239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void connectHeadset(HeadsetBase headset, int headsetType) {
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = headset;
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadsetType = headsetType;
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadsetType == TYPE_HEADSET) {
245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHeadsetAtParser();
246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHandsfreeAtParser();
248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        headset.startEventThread();
250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        configAudioParameters();
251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (inDebug()) {
253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            startDebug();
254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isIncallAudio()) {
257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            audioOn();
258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* returns true if there is some kind of in-call audio we may wish to route
262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * bluetooth to */
263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isIncallAudio() {
264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call.State state = mForegroundCall.getState();
265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (state == Call.State.ACTIVE || state == Call.State.ALERTING);
267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void disconnectHeadset() {
270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;
271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        stopDebug();
272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        resetAtState();
273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void resetAtState() {
276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mClip = false;
277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mIndicatorsEnabled = false;
2780966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        mServiceConnectionEstablished = false;
279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mCmee = false;
280c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mClccTimestamps = new long[GSM_MAX_CONNECTIONS];
281c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mClccUsed = new boolean[GSM_MAX_CONNECTIONS];
282c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mRemoteBrsf = 0;
286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void configAudioParameters() {
289db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        String name = mHeadset.getRemoteDevice().getName();
290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (name == null) {
291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            name = "<unknown>";
292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
293aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent        mAudioManager.setParameters(HEADSET_NAME+"="+name+";"+HEADSET_NREC+"=on");
294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Represents the data that we send in a +CIND or +CIEV command to the HF
298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class BluetoothPhoneState {
300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no service
301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: service
302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mService;
303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no active call
305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: active call (where active means audio is routed - not held call)
306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCall;
307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not in call setup
309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: incoming call setup
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: outgoing call setup
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 3: remote party being alerted in an outgoing call setup
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallsetup;
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no calls held
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: held call and active call
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: held call only
317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallheld;
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength of AG: 0-5
320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mSignal;
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength in CSQ rssi scale
323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRssi;  // for CSQ
324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: roaming not active (home)
326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: roaming active
327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRoam;
328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // battery charge of AG: 0-5
330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mBattchg;
331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not registered
333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: registered, home network
334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 5: registered, roaming
335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mStat;  // for CREG
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private String mRingingNumber;  // Context for in-progress RING's
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int    mRingingType;
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean mIgnoreRing = false;
340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int SERVICE_STATE_CHANGED = 1;
342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int PHONE_STATE_CHANGED = 2;
343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int RING = 3;
344a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman        private static final int PHONE_CDMA_CALL_WAITING = 4;
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private Handler mStateChangeHandler = new Handler() {
347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void handleMessage(Message msg) {
349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch(msg.what) {
350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RING:
351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result = ring();
352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (result != null) {
353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        sendURC(result.toString());
354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case SERVICE_STATE_CHANGED:
357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateServiceState(sendUpdate(), state);
359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case PHONE_STATE_CHANGED:
361a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                case PHONE_CDMA_CALL_WAITING:
362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Connection connection = null;
363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (((AsyncResult) msg.obj).result instanceof Connection) {
364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        connection = (Connection) ((AsyncResult) msg.obj).result;
365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updatePhoneState(sendUpdate(), connection);
367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private BluetoothPhoneState() {
373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // init members
374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updateServiceState(false, mPhone.getServiceState());
375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updatePhoneState(false, null);
376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mBattchg = 5;  // There is currently no API to get battery level
377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           // on demand, so set to 5 and wait for an update
378404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            mSignal = asuToSignal(mPhone.getSignalStrength());
379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // register for updates
381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhone.registerForServiceStateChanged(mStateChangeHandler,
382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                  SERVICE_STATE_CHANGED, null);
38319dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            mPhone.registerForPreciseCallStateChanged(mStateChangeHandler,
384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                PHONE_STATE_CHANGED, null);
385a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman            if (mPhone.getPhoneName().equals("CDMA")) {
386a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                mPhone.registerForCallWaiting(mStateChangeHandler,
387a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                              PHONE_CDMA_CALL_WAITING, null);
388a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman            }
389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            filter.addAction(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mContext.registerReceiver(mStateReceiver, filter);
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
394a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        private void updateBtPhoneStateAfterRadioTechnologyChange() {
3958eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
396a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
397a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Unregister all events from the old obsolete phone
398a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            mPhone.unregisterForServiceStateChanged(mStateChangeHandler);
39919dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            mPhone.unregisterForPreciseCallStateChanged(mStateChangeHandler);
400a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman            mPhone.unregisterForCallWaiting(mStateChangeHandler);
401a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
402a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Register all events new to the new active phone
40319dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            mPhone.registerForServiceStateChanged(mStateChangeHandler,
40419dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh                                                  SERVICE_STATE_CHANGED, null);
40519dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            mPhone.registerForPreciseCallStateChanged(mStateChangeHandler,
40619dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh                                                      PHONE_STATE_CHANGED, null);
407a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman            if (mPhone.getPhoneName().equals("CDMA")) {
408a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                mPhone.registerForCallWaiting(mStateChangeHandler,
409a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                              PHONE_CDMA_CALL_WAITING, null);
410a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman            }
411a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        }
412a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
413b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendUpdate() {
414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled;
415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendClipUpdate() {
418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mClip;
419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,31] ASU signal strength to the [0,5] expected by
422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * bluetooth devices. Scale is similar to status bar policy
423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
42434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        private int gsmAsuToSignal(SignalStrength signalStrength) {
42534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int asu = signalStrength.getGsmSignalStrength();
426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if      (asu >= 16) return 5;
427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 8)  return 4;
428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 4)  return 3;
429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 2)  return 2;
430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 1)  return 1;
431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else                return 0;
432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
43434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        /**
43534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * Convert the cdma / evdo db levels to appropriate icon level.
43634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * The scale is similar to the one used in status bar policy.
43734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         *
43834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * @param signalStrength
43934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh         * @return the icon level
440404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville         */
44134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh        private int cdmaDbmEcioToSignal(SignalStrength signalStrength) {
44234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int levelDbm = 0;
44334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int levelEcio = 0;
44434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaIconLevel = 0;
44534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int evdoIconLevel = 0;
44634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaDbm = signalStrength.getCdmaDbm();
44734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            int cdmaEcio = signalStrength.getCdmaEcio();
44834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
44934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (cdmaDbm >= -75) levelDbm = 4;
45034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -85) levelDbm = 3;
45134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -95) levelDbm = 2;
45234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaDbm >= -100) levelDbm = 1;
45334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else levelDbm = 0;
45434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
45534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            // Ec/Io are in dB*10
45634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (cdmaEcio >= -90) levelEcio = 4;
45734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -110) levelEcio = 3;
45834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -130) levelEcio = 2;
45934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else if (cdmaEcio >= -150) levelEcio = 1;
46034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            else levelEcio = 0;
46134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
46234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
46334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
46413df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh            if (mServiceState != null &&
465b1164d370e8d83a8a4f3cbdc73dffc087254cabdJaikumar Ganesh                  (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0 ||
466b1164d370e8d83a8a4f3cbdc73dffc087254cabdJaikumar Ganesh                   mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
46734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int evdoEcio = signalStrength.getEvdoEcio();
46834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int evdoSnr = signalStrength.getEvdoSnr();
46934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int levelEvdoEcio = 0;
47034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  int levelEvdoSnr = 0;
47134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
47234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  // Ec/Io are in dB*10
47334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  if (evdoEcio >= -650) levelEvdoEcio = 4;
47434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -750) levelEvdoEcio = 3;
47534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -900) levelEvdoEcio = 2;
47634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoEcio >= -1050) levelEvdoEcio = 1;
47734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else levelEvdoEcio = 0;
47834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
47934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  if (evdoSnr > 7) levelEvdoSnr = 4;
48034b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 5) levelEvdoSnr = 3;
48134b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 3) levelEvdoSnr = 2;
48234b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else if (evdoSnr > 1) levelEvdoSnr = 1;
48334b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  else levelEvdoSnr = 0;
48434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
48534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                  evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
48634b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            }
48734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            // TODO(): There is a bug open regarding what should be sent.
48834b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            return (cdmaIconLevel > evdoIconLevel) ?  cdmaIconLevel : evdoIconLevel;
48934b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh
490404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
491404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
492404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
493404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        private int asuToSignal(SignalStrength signalStrength) {
49434b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh            if (signalStrength.isGsm()) {
49534b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                return gsmAsuToSignal(signalStrength);
496404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
49734b9266fbd8c9c4d52e8faf708e02037a7ddcc4cJaikumar Ganesh                return cdmaDbmEcioToSignal(signalStrength);
498404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            }
499404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
500404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
501404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,5] signal strength to a rssi signal strength for CSQ
503b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * which is [0,31]. Despite the same scale, this is not the same value
504b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * as ASU.
505b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
506b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int signalToRssi(int signal) {
507b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // using C4A suggested values
508b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (signal) {
509b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 0: return 0;
510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 1: return 4;
511b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 2: return 8;
512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 3: return 13;
513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 4: return 19;
514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 5: return 31;
515b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return 0;
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void onReceive(Context context, Intent intent) {
523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateBatteryState(intent);
525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (intent.getAction().equals(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED)) {
526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateSignalState(intent);
527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateBatteryState(Intent intent) {
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int batteryLevel = intent.getIntExtra("level", -1);
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int scale = intent.getIntExtra("scale", -1);
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (batteryLevel == -1 || scale == -1) {
535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return;  // ignore
536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            batteryLevel = batteryLevel * 5 / scale;
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mBattchg != batteryLevel) {
539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mBattchg = batteryLevel;
540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate()) {
541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC("+CIEV: 7," + mBattchg);
542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateSignalState(Intent intent) {
547404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent
548404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread
549404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras());
550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int signal;
551404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
552404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            if (signalStrength != null) {
553404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                signal = asuToSignal(signalStrength);
554404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                mRssi = signalToRssi(signal);  // no unsolicited CSQ
555404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                if (signal != mSignal) {
556404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    mSignal = signal;
557404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    if (sendUpdate()) {
558404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                        sendURC("+CIEV: 5," + mSignal);
559404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    }
560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
561404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
562404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                Log.e(TAG, "Signal Strength null");
563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateServiceState(boolean sendUpdate, ServiceState state) {
567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int service = state.getState() == ServiceState.STATE_IN_SERVICE ? 1 : 0;
568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int roam = state.getRoaming() ? 1 : 0;
569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int stat;
570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
57113df4bba7e39d516317d005b4b917b1f1c6baf8dJaikumar Ganesh            mServiceState = state;
572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service == 0) {
573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = 0;
574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = (roam == 1) ? 5 : 1;
576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service != mService) {
579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mService = service;
580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 1," + mService);
582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (roam != mRoam) {
585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mRoam = roam;
586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 6," + mRoam);
588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (stat != mStat) {
591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStat = stat;
592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(toCregString());
594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updatePhoneState(boolean sendUpdate, Connection connection) {
601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int call = 0;
602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callsetup = 0;
603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callheld = 0;
604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int prevCallsetup = mCallsetup;
605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6078eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("updatePhoneState()");
608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6091dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh            Phone.State newState = mPhone.getState();
6101dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh            if (newState != mPhoneState) {
6111dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                mPhoneState = newState;
6121dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                switch (mPhoneState) {
6131dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                case IDLE:
6141dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mUserWantsAudio = true;  // out of call - reset state
6151dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    audioOff();
6161dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    break;
6171dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                default:
6181dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    callStarted();
6191dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                }
620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mForegroundCall.getState()) {
623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ACTIVE:
624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                call = 1;
625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DIALING:
628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 2;
629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = false;
630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ALERTING:
632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 3;
633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Open the SCO channel for the outgoing call.
634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                audioOn();
635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = false;
639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mRingingCall.getState()) {
642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case INCOMING:
643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case WAITING:
644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 1;
645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mBackgroundCall.getState()) {
649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case HOLDING:
650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 1;
652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    call = 1;
654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 2;
655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCall != call) {
660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This means that a call has transitioned from NOT ACTIVE to ACTIVE.
662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Switch on audio.
663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCall = call;
666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 2," + mCall);
668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallsetup != callsetup) {
671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallsetup = callsetup;
672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
6734b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // If mCall = 0, send CIEV
6744b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 0, send CIEV
6754b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 1, send CIEV after CCWA,
6764b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way supported.
6774b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 2 / 3 -> send CIEV,
6784b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way is supported
6794b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    if (mCall != 1 || mCallsetup == 0 ||
6804b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CIEV: 3," + mCallsetup);
682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
686c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            if (mPhone.getPhoneName().equals("CDMA")) {
687c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                PhoneApp app = PhoneApp.getInstance();
68860877272381161201c6969dea501e683705d6e32w                if (app.cdmaPhoneCallState != null) {
68960877272381161201c6969dea501e683705d6e32w                    CdmaPhoneCallState.PhoneCallState currCdmaCallState =
69060877272381161201c6969dea501e683705d6e32w                            app.cdmaPhoneCallState.getCurrentCallState();
691ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
692ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        app.cdmaPhoneCallState.getPreviousCallState();
693ed1d155825eb32990fde95eef9d89a7260e4c3f1w
694ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    // Update the Call held information
695ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
696ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
697ed1d155825eb32990fde95eef9d89a7260e4c3f1w                            callheld = 0; //0: no calls held, as now *both* the caller are active
698ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        } else {
699ed1d155825eb32990fde95eef9d89a7260e4c3f1w                            callheld = 1; //1: held call and active call, as on answering a
700ed1d155825eb32990fde95eef9d89a7260e4c3f1w                                          // Call Waiting, one of the caller *is* put on hold
701ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        }
702ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    } else if (currCdmaCallState ==
703ed1d155825eb32990fde95eef9d89a7260e4c3f1w                            CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
704ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        callheld = 1; //1: held call and active call, as on make a 3 Way Call
705ed1d155825eb32990fde95eef9d89a7260e4c3f1w                                      // the first caller *is* put on hold
706ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    } else {
707ed1d155825eb32990fde95eef9d89a7260e4c3f1w                        callheld = 0; //0: no calls held as this is a SINGLE_ACTIVE call
708ed1d155825eb32990fde95eef9d89a7260e4c3f1w                    }
70960877272381161201c6969dea501e683705d6e32w
71060877272381161201c6969dea501e683705d6e32w                    // In CDMA, the network does not provide any feedback to the phone when the
71160877272381161201c6969dea501e683705d6e32w                    // 2nd MO call goes through the stages of DIALING > ALERTING -> ACTIVE
71260877272381161201c6969dea501e683705d6e32w                    // we fake the sequence
71360877272381161201c6969dea501e683705d6e32w                    if ((currCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
71460877272381161201c6969dea501e683705d6e32w                            && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
71560877272381161201c6969dea501e683705d6e32w                        mAudioPossible = true;
71660877272381161201c6969dea501e683705d6e32w                        if (sendUpdate) {
71760877272381161201c6969dea501e683705d6e32w                            if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
71860877272381161201c6969dea501e683705d6e32w                                result.addResponse("+CIEV: 3,2");
71960877272381161201c6969dea501e683705d6e32w                                result.addResponse("+CIEV: 3,3");
72060877272381161201c6969dea501e683705d6e32w                                result.addResponse("+CIEV: 3,0");
72160877272381161201c6969dea501e683705d6e32w                            }
722c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        }
7231b7bc65530abaac8827a92d4df13803d3255f6d4Abhishek Pillai                        // We also need to send a Call started indication for cases where
7241b7bc65530abaac8827a92d4df13803d3255f6d4Abhishek Pillai                        // the 2nd MO was initiated was from a *BT hands free* and is waiting
7251b7bc65530abaac8827a92d4df13803d3255f6d4Abhishek Pillai                        // for a +BLND: OK response
7261b7bc65530abaac8827a92d4df13803d3255f6d4Abhishek Pillai                        callStarted();
727c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    }
728c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
72960877272381161201c6969dea501e683705d6e32w                    // In CDMA, the network does not provide any feedback to the phone when a
73060877272381161201c6969dea501e683705d6e32w                    // user merges a 3way call or swaps between two calls we need to send a
73160877272381161201c6969dea501e683705d6e32w                    // CIEV response indicating that a call state got changed which should trigger a
73260877272381161201c6969dea501e683705d6e32w                    // CLCC update request from the BT client.
73360877272381161201c6969dea501e683705d6e32w                    if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
73460877272381161201c6969dea501e683705d6e32w                        mAudioPossible = true;
73560877272381161201c6969dea501e683705d6e32w                        if (sendUpdate) {
73660877272381161201c6969dea501e683705d6e32w                            if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
73760877272381161201c6969dea501e683705d6e32w                                result.addResponse("+CIEV: 2,1");
73860877272381161201c6969dea501e683705d6e32w                                result.addResponse("+CIEV: 3,0");
73960877272381161201c6969dea501e683705d6e32w                            }
740c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        }
741c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    }
742c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
743c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
744c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean callsSwitched =
746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                (callheld == 1 && ! (mBackgroundCall.getEarliestConnectTime() ==
747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mBgndEarliestConnectionTime));
748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mBgndEarliestConnectionTime = mBackgroundCall.getEarliestConnectTime();
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallheld != callheld || callsSwitched) {
752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallheld = callheld;
753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 4," + mCallheld);
755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (callsetup == 1 && callsetup != prevCallsetup) {
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // new incoming call
760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String number = null;
761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int type = 128;
762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // find incoming phone number and type
763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection == null) {
764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    connection = mRingingCall.getEarliestConnection();
765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (connection == null) {
766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.e(TAG, "Could not get a handle on Connection object for new " +
767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                              "incoming call");
768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection != null) {
771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = connection.getAddress();
772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (number != null) {
773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        type = PhoneNumberUtils.toaFromString(number);
774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = "";
778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if ((call != 0 || callheld != 0) && sendUpdate) {
780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // call waiting
781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CCWA: \"" + number + "\"," + type);
7834b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        result.addResponse("+CIEV: 3," + callsetup);
784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // regular new incoming call
787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingNumber = number;
788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingType = type;
789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mIgnoreRing = false;
790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((mLocalBrsf & BRSF_AG_IN_BAND_RING) == 0x1) {
792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResult(ring());
795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private AtCommandResult ring() {
801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!mIgnoreRing && mRingingCall.isRinging()) {
802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
803b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                result.addResponse("RING");
804b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendClipUpdate()) {
805b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CLIP: \"" + mRingingNumber + "\"," + mRingingType);
806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Message msg = mStateChangeHandler.obtainMessage(RING);
809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStateChangeHandler.sendMessageDelayed(msg, 3000);
810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return result;
811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;
813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized String toCregString() {
816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new String("+CREG: 1," + mStat);
817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCindResult() {
820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CIND: " + mService + "," + mCall + "," + mCallsetup + "," +
822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mCallheld + "," + mSignal + "," + mRoam + "," + mBattchg;
823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCsqResult() {
828b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CSQ: " + mRssi + ",99";
830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
832b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult getCindTestResult() {
836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult("+CIND: (\"service\",(0-1))," + "(\"call\",(0-1))," +
837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))," +
838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"roam\",(0-1)),(\"battchg\",(0-5))");
839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void ignoreRing() {
842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mCallsetup = 0;
843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIgnoreRing = true;
844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (sendUpdate()) {
845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                sendURC("+CIEV: 3," + mCallsetup);
846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_ACCEPTED = 1;
852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CONNECTED = 2;
853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CLOSED = 3;
854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_CALL_STARTED = 4;
855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_VOICE_RECOGNITION_STARTED = 5;
856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final Handler mHandler = new Handler() {
858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
8597757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh        public void handleMessage(Message msg) {
8607757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh            synchronized (BluetoothHandsfree.this) {
8617757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                switch (msg.what) {
8627757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_ACCEPTED:
8637757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
8647757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        if (isHeadsetConnected() && (mAudioPossible || allowAudioAnytime()) &&
8657757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                                mConnectedSco == null) {
8667757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            Log.i(TAG, "Routing audio for incoming SCO connection");
8677757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mConnectedSco = (ScoSocket)msg.obj;
8687757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mAudioManager.setBluetoothScoOn(true);
869db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED,
870db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                                    mHeadset.getRemoteDevice());
8717757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        } else {
8727757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            Log.i(TAG, "Rejecting incoming SCO connection");
8737757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            ((ScoSocket)msg.obj).close();
8747757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        }
8757757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } // else error trying to accept, try again
8767757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    mIncomingSco = createScoSocket();
8777757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    mIncomingSco.accept();
8787757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
8797757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_CONNECTED:
8807757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (msg.arg1 == ScoSocket.STATE_CONNECTED && isHeadsetConnected() &&
881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mConnectedSco == null) {
8828eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                        if (VDBG) log("Routing audio for outgoing SCO conection");
883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mConnectedSco = (ScoSocket)msg.obj;
884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mAudioManager.setBluetoothScoOn(true);
885db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED,
886db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                                mHeadset.getRemoteDevice());
8877757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } else if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
8888eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                        if (VDBG) log("Rejecting new connected outgoing SCO socket");
889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        ((ScoSocket)msg.obj).close();
8907757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mOutgoingSco.close();
891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mOutgoingSco = null;
8937757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
8947757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case SCO_CLOSED:
8957757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mConnectedSco == (ScoSocket)msg.obj) {
8967757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mConnectedSco = null;
8977757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mAudioManager.setBluetoothScoOn(false);
898db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED,
899db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                                mHeadset.getRemoteDevice());
9007757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } else if (mOutgoingSco == (ScoSocket)msg.obj) {
9017757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mOutgoingSco = null;
9027757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    } else if (mIncomingSco == (ScoSocket)msg.obj) {
9037757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mIncomingSco = null;
904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
9057757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
9067757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case CHECK_CALL_STARTED:
9077757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mWaitingForCallStart) {
9087757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mWaitingForCallStart = false;
9097757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        Log.e(TAG, "Timeout waiting for call to start");
9107757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        sendURC("ERROR");
9117757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        if (mStartCallWakeLock.isHeld()) {
9127757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                            mStartCallWakeLock.release();
9137757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        }
9147757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    }
9157757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
9167757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                case CHECK_VOICE_RECOGNITION_STARTED:
9177757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    if (mWaitingForVoiceRecognition) {
9187757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        mWaitingForVoiceRecognition = false;
9197757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        Log.e(TAG, "Timeout waiting for voice recognition to start");
9207757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                        sendURC("ERROR");
9217757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    }
9227757ebca8f27cd580bc85b6afe66ca43122b8c39Jaikumar Ganesh                    break;
923b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
924b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
925b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
926b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
927b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
928b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket createScoSocket() {
929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new ScoSocket(mPowerManager, mHandler, SCO_ACCEPTED, SCO_CONNECTED, SCO_CLOSED);
930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
932db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly    private void broadcastAudioStateIntent(int state, BluetoothDevice device) {
9334079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        if (VDBG) log("broadcastAudioStateIntent(" + state + ")");
9344079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        Intent intent = new Intent(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION);
9354079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        intent.putExtra(BluetoothIntent.HEADSET_AUDIO_STATE, state);
936db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        intent.putExtra(BluetoothIntent.DEVICE, device);
9374079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
9384079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    }
9394079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project
940a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
941a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    void updateBtHandsfreeAfterRadioTechnologyChange() {
9428eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if(VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
943a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
944a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        //Get the Call references from the new active phone again
945a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mRingingCall = mPhone.getRingingCall();
946a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mForegroundCall = mPhone.getForegroundCall();
947a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mBackgroundCall = mPhone.getBackgroundCall();
948a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
9491dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState.updateBtPhoneStateAfterRadioTechnologyChange();
950a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    }
951a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to establish SCO (audio) connection to bluetooth
953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns false if the user has requested audio off, or if there
955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * is some other immediate problem that will prevent BT audio.
956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean audioOn() {
958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (VDBG) log("audioOn()");
959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!isHeadsetConnected()) {
960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): headset is not connected!");
961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
9630966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        if (mHeadsetType == TYPE_HANDSFREE && !mServiceConnectionEstablished) {
9640966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly            if (DBG) log("audioOn(): service connection not yet established!");
9650966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly            return false;
9660966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly        }
967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): audio is already connected");
970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mUserWantsAudio) {
974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): user requested no audio, ignoring");
975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): outgoing SCO already in progress");
980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mOutgoingSco = createScoSocket();
983db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly        if (!mOutgoingSco.connect(mHeadset.getRemoteDevice().getAddress())) {
984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio on.
991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will establish SCO (BT audio), even if the user requested it off
992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  previously on this call.
993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOn() {
995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOn();
997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio off.
999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will prevent us from establishing BT audio again during this call
1000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  if audioOn() is called.
1001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOff() {
1003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = false;
1004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
1005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1007b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to disconnect SCO (audio) connection to bluetooth
1008b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
1009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void audioOff() {
1011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (VDBG) log("audioOff()");
1012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
1014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mAudioManager.setBluetoothScoOn(false);
1015db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED,
1016db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly                    mHeadset.getRemoteDevice());
1017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco.close();
1018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco = null;
1019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
1021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco.close();
1022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
1023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1025b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1026b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ boolean isAudioOn() {
1027b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (mConnectedSco != null);
1028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void ignoreRing() {
10311dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh        mBluetoothPhoneState.ignoreRing();
1032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void sendURC(String urc) {
1035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isHeadsetConnected()) {
1036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mHeadset.sendURC(urc);
1037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** helper to redial last dialled number */
1041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AtCommandResult redial() {
1042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = mPhonebook.getLastDialledNumber();
1043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number == null) {
1044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // spec seems to suggest sending ERROR if we dont have a
1045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // number to redial
10468eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("Bluetooth redial requested (+BLDN), but no previous " +
1047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                  "outgoing calls found. Ignoring");
1048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
1049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
1051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Uri.fromParts("tel", number, null));
1052b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext.startActivity(intent);
1054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // We do not immediately respond OK, wait until we get a phone state
1056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // update. If we return OK now and the handsfree immeidately requests
1057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // our phone state it will say we are not in call yet which confuses
1058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // some devices
1059b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        expectCallStart();
1060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
1061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1063b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Build the +CLCC result
1064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  The complexity arises from the fact that we need to maintain the same
1065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  CLCC index even as a call moves between states. */
1066c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private synchronized AtCommandResult gsmGetClccResult() {
1067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Collect all known connections
1068c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS];  // indexed by CLCC index
1069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> newConnections = new LinkedList<Connection>();
1070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> connections = new LinkedList<Connection>();
1071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mRingingCall.getState().isAlive()) {
1072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mRingingCall.getConnections());
1073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mForegroundCall.getState().isAlive()) {
1075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mForegroundCall.getConnections());
1076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mBackgroundCall.getState().isAlive()) {
1078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mBackgroundCall.getConnections());
1079b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1080b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1081b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mark connections that we already known about
1082c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS];
1083c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
1084b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccUsed[i] = mClccUsed[i];
1085b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
1086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (Connection c : connections) {
1088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean found = false;
1089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long timestamp = c.getCreateTime();
1090c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
1091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
1092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClccUsed[i] = true;
1093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    found = true;
1094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    clccConnections[i] = c;
1095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!found) {
1099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newConnections.add(c);
1100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Find a CLCC index for new connections
1104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        while (!newConnections.isEmpty()) {
1105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find lowest empty index
1106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int i = 0;
1107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (mClccUsed[i]) i++;
1108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find earliest connection
1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long earliestTimestamp = newConnections.get(0).getCreateTime();
1110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Connection earliestConnection = newConnections.get(0);
1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            for (int j = 0; j < newConnections.size(); j++) {
1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                long timestamp = newConnections.get(j).getCreateTime();
1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (timestamp < earliestTimestamp) {
1114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestTimestamp = timestamp;
1115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestConnection = newConnections.get(j);
1116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // update
1120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = true;
1121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccTimestamps[i] = earliestTimestamp;
1122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccConnections[i] = earliestConnection;
1123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            newConnections.remove(earliestConnection);
1124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Build CLCC
1127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
1128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int i = 0; i < clccConnections.length; i++) {
1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mClccUsed[i]) {
1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String clccEntry = connectionToClccEntry(i, clccConnections[i]);
1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccEntry != null) {
1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(clccEntry);
1133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
1138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Convert a Connection object into a single +CLCC result */
1141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private String connectionToClccEntry(int index, Connection c) {
1142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int state;
1143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (c.getState()) {
1144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ACTIVE:
1145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 0;
1146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case HOLDING:
1148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 1;
1149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case DIALING:
1151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 2;
1152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ALERTING:
1154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 3;
1155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case INCOMING:
1157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 4;
1158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case WAITING:
1160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 5;
1161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        default:
1163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;  // bad state
1164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int mpty = 0;
1167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call call = c.getCall();
1168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (call != null) {
1169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mpty = call.isMultiparty() ? 1 : 0;
1170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int direction = c.isIncoming() ? 1 : 0;
1173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = c.getAddress();
1175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int type = -1;
1176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            type = PhoneNumberUtils.toaFromString(number);
1178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
1181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result += ",\"" + number + "\"," + type;
1183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
1185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1186c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1187c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    /** Build the +CLCC result for CDMA
1188c9d9ed30aa547b79b81adc13a4d148a003b6ee62w     *  The complexity arises from the fact that we need to maintain the same
1189c9d9ed30aa547b79b81adc13a4d148a003b6ee62w     *  CLCC index even as a call moves between states. */
1190c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private synchronized AtCommandResult cdmaGetClccResult() {
1191c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // In CDMA at one time a user can have only two live/active connections
1192c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index
1193c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1194c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        Call.State ringingCallState = mRingingCall.getState();
1195c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // If the Ringing Call state is INCOMING, that means this is the very first call
1196c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // hence there should not be any Foreground Call
1197c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (ringingCallState == Call.State.INCOMING) {
11988eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan            if (VDBG) log("Filling clccConnections[0] for INCOMING state");
1199c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            clccConnections[0] = mRingingCall.getLatestConnection();
1200c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else if (mForegroundCall.getState().isAlive()) {
1201c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // Getting Foreground Call connection based on Call state
1202c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            if (mRingingCall.isRinging()) {
12038eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state");
1204c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                clccConnections[0] = mForegroundCall.getEarliestConnection();
1205c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                clccConnections[1] = mRingingCall.getLatestConnection();
1206c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            } else {
1207c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                if (mForegroundCall.getConnections().size() <= 1) {
1208c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // Single call scenario
12098eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                    if (VDBG) log("Filling clccConnections[0] with ForgroundCall latest connection");
1210c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    clccConnections[0] = mForegroundCall.getLatestConnection();
1211c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                } else {
1212c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // Multiple Call scenario. This would be true for both
1213c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    // CONF_CALL and THRWAY_ACTIVE state
12148eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                    if (VDBG) log("Filling clccConnections[0] & [1] with ForgroundCall connections");
1215c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    clccConnections[0] = mForegroundCall.getEarliestConnection();
1216c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    clccConnections[1] = mForegroundCall.getLatestConnection();
1217c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1218c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1219c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1220c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1221c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // Update the mCdmaIsSecondCallActive flag based on the Phone call state
1222c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1223c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
1224c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            cdmaSetSecondCallState(false);
1225c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1226c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
1227c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            cdmaSetSecondCallState(true);
1228c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1229c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1230c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        // Build CLCC
1231c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
1232c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) {
1233c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            String clccEntry = cdmaConnectionToClccEntry(i, clccConnections[i]);
1234c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            if (clccEntry != null) {
1235c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                result.addResponse(clccEntry);
1236c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1237c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1238c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1239c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        return result;
1240c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
1241c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1242c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    /** Convert a Connection object into a single +CLCC result for CDMA phones */
1243c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    private String cdmaConnectionToClccEntry(int index, Connection c) {
1244c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int state;
1245c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        PhoneApp app = PhoneApp.getInstance();
1246c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        CdmaPhoneCallState.PhoneCallState currCdmaCallState =
1247c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                app.cdmaPhoneCallState.getCurrentCallState();
1248c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
1249c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                app.cdmaPhoneCallState.getPreviousCallState();
1250c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1251c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
1252c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) {
1253c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // If the current state is reached after merging two calls
1254c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            // we set the state of all the connections as ACTIVE
1255c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            state = 0;
1256c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else {
1257c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            switch (c.getState()) {
1258c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case ACTIVE:
1259c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // For CDMA since both the connections are set as active by FW after accepting
1260c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // a Call waiting or making a 3 way call, we need to set the state specifically
1261c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the
1262c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                // CLCC result will allow BT devices to enable the swap or merge options
1263c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                if (index == 0) { // For the 1st active connection
1264c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    state = mCdmaIsSecondCallActive ? 1 : 0;
1265c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                } else { // for the 2nd active connection
1266c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    state = mCdmaIsSecondCallActive ? 0 : 1;
1267c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1268c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1269c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case HOLDING:
1270c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 1;
1271c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1272c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case DIALING:
1273c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 2;
1274c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1275c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case ALERTING:
1276c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 3;
1277c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1278c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case INCOMING:
1279c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 4;
1280c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1281c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            case WAITING:
1282c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                state = 5;
1283c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                break;
1284c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            default:
1285c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                return null;  // bad state
1286c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            }
1287c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1288c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1289c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int mpty = 0;
1290c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
1291c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            mpty = 0;
1292c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        } else {
1293c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            mpty = 1;
1294c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1295c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1296c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int direction = c.isIncoming() ? 1 : 0;
1297c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1298c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        String number = c.getAddress();
1299c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        int type = -1;
1300c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (number != null) {
1301c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            type = PhoneNumberUtils.toaFromString(number);
1302c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1303c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1304c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
1305c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        if (number != null) {
1306c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            result += ",\"" + number + "\"," + type;
1307c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        }
1308c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        return result;
1309c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
1310c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
1311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Headset profile
1313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHeadsetAtParser() {
13158eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("Registering Headset AT commands");
1316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
1317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Headset's usually only have one button, which is meant to cause the
1318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // HS to send us AT+CKPD=200 or AT+CKPD.
1319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CKPD", new AtCommandHandler() {
1320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult headsetButtonPress() {
1321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mRingingCall.isRinging()) {
1322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Answer the call
1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.answerCall(mPhone);
1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // If in-band ring tone is supported, SCO connection will already
1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // be up and the following call will just return.
1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (mForegroundCall.getState().isAlive()) {
1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (!isAudioOn()) {
1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Transfer audio from AG to HS
1330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mHeadset.getDirection() == HeadsetBase.DIRECTION_INCOMING &&
1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                          (System.currentTimeMillis() - mHeadset.getConnectTimestamp()) < 5000) {
1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Headset made a recent ACL connection to us - and
1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // made a mandatory AT+CKPD request to connect
1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // audio which races with our automatic audio
1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // setup.  ignore
1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Hang up the call
1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            audioOff();
1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            PhoneUtils.hangup(mPhone);
1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // No current call - redial last number
1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return redial();
1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Handsfree profile
1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHandsfreeAtParser() {
13658eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("Registering Handsfree AT commands");
1366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
1367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Answer
1369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('A', new AtCommandHandler() {
1370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
1372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                PhoneUtils.answerCall(mPhone);
1373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('D', new AtCommandHandler() {
1377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
1379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length() > 0) {
1380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args.charAt(0) == '>') {
1381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Yuck - memory dialling requested.
1382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Just dial last number for now
1383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.startsWith(">9999")) {   // for PTS test
1384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return redial();
1387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Remove trailing ';'
1389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.charAt(args.length() - 1) == ';') {
1390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            args = args.substring(0, args.length() - 1);
1391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
1393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                Uri.fromParts("tel", args, null));
1394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mContext.startActivity(intent);
1396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        expectCallStart();
1398b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
1399b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Hang-up command
1406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHUP", new AtCommandHandler() {
1407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1409586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh                sendURC("OK");
1410fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                if (!mRingingCall.isIdle()) {
1411fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                    PhoneUtils.hangupRingingCall(mPhone);
1412fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                } else if (!mForegroundCall.isIdle()) {
1413fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                    PhoneUtils.hangupActiveCall(mPhone);
1414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!mBackgroundCall.isIdle()) {
1415fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                    PhoneUtils.hangupHoldingCall(mPhone);
1416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1417586668fe6a1259083fbbc67de8ecac850c1475f1Jaikumar Ganesh                return new AtCommandResult(AtCommandResult.UNSOLICITED);
1418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Retrieve Supported Features command
1422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BRSF", new AtCommandHandler() {
1423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult sendBRSF() {
1424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+BRSF: " + mLocalBrsf);
1425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+BRSF=<handsfree supported features bitmap>
1429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is telling us which features it supports. We
1430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // send the features we support
1431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 1 && (args[0] instanceof Integer)) {
1432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRemoteBrsf = (Integer) args[0];
1433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Log.w(TAG, "HF didn't sent BRSF assuming 0");
1435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1436b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call waiting notification on/off
1451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CCWA", new AtCommandHandler() {
1452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Seems to be out of spec, but lets return nicely
1455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Call waiting is always on
1460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: 1");
1461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CCWA=<n>
1465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is trying to enable/disable call waiting. We
1466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // cannot disable in the current implementation.
1467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Request for range of supported CCWA paramters
1472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: (\"n\",(1))");
1473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Event Reporting enable/disable command
1477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Of the full 3GPP syntax paramters (mode, keyp, disp, ind, bfr) we
1478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // only support paramter ind (disable/enable evert reporting using
1479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // +CDEV)
1480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMER", new AtCommandHandler() {
1481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(
1484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "+CMER: 3,0,0," + (mIndicatorsEnabled ? "1" : "0"));
1485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1488b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length < 4) {
1489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This is a syntax error
1490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(3) && args[1].equals(0) &&
1492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           args[2].equals(0)) {
14930966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    boolean valid = false;
1494b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[3].equals(0)) {
1495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = false;
14960966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        valid = true;
1497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[3].equals(1)) {
1498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = true;
14990966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        valid = true;
15000966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    }
15010966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    if (valid) {
15020966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) == 0x0) {
15030966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            mServiceConnectionEstablished = true;
15040966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            sendURC("OK");  // send immediately, then initiate audio
15050966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            if (isIncallAudio()) {
15060966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                                audioOn();
15070966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            }
15080966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            // only send OK once
15090966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            return new AtCommandResult(AtCommandResult.UNSOLICITED);
15100966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        } else {
15110966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                            return new AtCommandResult(AtCommandResult.OK);
15120966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                        }
1513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
15150966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMER: (3),(0),(0),(0-1)");
1520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Error Reporting enable/disable
1524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMEE", new AtCommandHandler() {
1525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // out of spec, assume they want to enable
1528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCmee = true;
1529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: " + (mCmee ? "1" : "0"));
1534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CMEE=<n>
1538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 0) {
1539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // <n> ommitted - default to 0
1540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = false;
1541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!(args[0] instanceof Integer)) {
1543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Syntax error
1544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = ((Integer)args[0] == 1);
1547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Probably not required but spec, but no harm done
1553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: (0-1)");
1554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Last Dialled Number
1558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BLDN", new AtCommandHandler() {
1559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return redial();
1562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Indicator Update command
1566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIND", new AtCommandHandler() {
1567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
15691dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.toCindResult();
1570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
15731dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.getCindTestResult();
1574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query Signal Quality (legacy)
1578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CSQ", new AtCommandHandler() {
1579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
15811dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return mBluetoothPhoneState.toCsqResult();
1582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query network registration state
1586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CREG", new AtCommandHandler() {
1587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
15891dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                return new AtCommandResult(mBluetoothPhoneState.toCregString());
1590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Send DTMF. I don't know if we are also expected to play the DTMF tone
1594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // locally, right now we don't
1595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VTS", new AtCommandHandler() {
1596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    char c;
1600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0] instanceof Integer) {
1601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((Integer) args[0]).toString().charAt(0);
1602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((String) args[0]).charAt(0);
1604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (isValidDtmf(c)) {
1606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mPhone.sendDtmf(c);
1607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private boolean isValidDtmf(char c) {
1613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (c) {
1614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '#':
1615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '*':
1616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return true;
1617b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                default:
1618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (Character.digit(c, 14) != -1) {
1619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return true;  // 0-9 and A-D
1620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return false;
1622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // List calls
1627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLCC", new AtCommandHandler() {
1628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1630c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                if (mPhone.getPhoneName().equals("CDMA")) {
1631c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    return cdmaGetClccResult();
1632c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                } else {
1633c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    return gsmGetClccResult();
1634c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                }
1635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call Hold and Multiparty Handling command
1639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHLD", new AtCommandHandler() {
1640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0].equals(0)) {
1644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        boolean result;
1645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mRingingCall.isRinging()) {
1646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            result = PhoneUtils.hangupRingingCall(mPhone);
1647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            result = PhoneUtils.hangupHoldingCall(mPhone);
1649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (result) {
1651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
1652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(1)) {
1656a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                        if (mPhone.getPhoneName().equals("CDMA")) {
1657c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            if (mRingingCall.isRinging()) {
1658c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // If there is Call waiting then answer the call and
1659c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // put the first call on hold.
16608eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:1 Callwaiting Answer call");
1661c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.answerCall(mPhone);
1662c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.setMute(mPhone, false);
1663c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Setting the second callers state flag to TRUE (i.e. active)
1664c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSetSecondCallState(true);
1665c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            } else {
1666c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // If there is no Call waiting then just hangup
1667c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // the active call. In CDMA this mean that the complete
1668c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // call session would be ended
16698eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:1 Hangup Call");
1670c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.hangup(mPhone);
1671c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
1672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
1673c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        } else { // GSM
1674a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // Hangup active call, answer held call
1675a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            if (PhoneUtils.answerAndEndActive(mPhone)) {
1676a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                return new AtCommandResult(AtCommandResult.OK);
1677a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            } else {
1678a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                                return new AtCommandResult(AtCommandResult.ERROR);
1679a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            }
1680b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(2)) {
1682a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                        if (mPhone.getPhoneName().equals("CDMA")) {
1683a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // For CDMA, the way we switch to a new incoming call is by
1684a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // calling PhoneUtils.answerCall(). switchAndHoldActive() won't
1685a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            // properly update the call state within telephony.
1686c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // If the Phone state is already in CONF_CALL then we simply send
1687c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // a flash cmd by calling switchHoldingAndActive()
1688c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            if (mRingingCall.isRinging()) {
16898eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:2 Callwaiting Answer call");
1690c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.answerCall(mPhone);
1691c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.setMute(mPhone, false);
1692c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Setting the second callers state flag to TRUE (i.e. active)
1693c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSetSecondCallState(true);
1694c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            } else if (PhoneApp.getInstance().cdmaPhoneCallState
1695c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    .getCurrentCallState()
1696c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
16978eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:2 Swap Calls");
1698c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.switchHoldingAndActive(mPhone);
1699c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                // Toggle the second callers active state flag
1700c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                cdmaSwapSecondCallState();
1701c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
1702c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        } else { // GSM
1703a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                            PhoneUtils.switchHoldingAndActive(mPhone);
1704a76113dcb0def438d0b3019aeb88fdbfbfbe90d4Paul Berman                        }
1705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(3)) {
1707c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        if (mPhone.getPhoneName().equals("CDMA")) {
1708c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            // For CDMA, we need to check if the call is in THRWAY_ACTIVE state
1709c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
1710c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
17118eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan                                if (VDBG) log("CHLD:3 Merge Calls");
1712c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.mergeCalls(mPhone);
1713c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
1714c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        } else { // GSM
1715c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            if (mForegroundCall.getState().isAlive() &&
1716c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                    mBackgroundCall.getState().isAlive()) {
1717c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                                PhoneUtils.mergeCalls(mPhone);
1718c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            }
1719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
17270966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                mServiceConnectionEstablished = true;
1728d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly                sendURC("+CHLD: (0,1,2,3)");
1729d2b5e78809bc2532b2377ba2c351d48710097c0cNick Pelly                sendURC("OK");  // send reply first, then connect audio
17300966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                if (isIncallAudio()) {
17310966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                    audioOn();
17320966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                }
17330966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                // already replied
17340966f42d45611b961635c8d23fc4a4df0f5e29c4Nick Pelly                return new AtCommandResult(AtCommandResult.UNSOLICITED);
1735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Get Network operator name
1739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+COPS", new AtCommandHandler() {
1740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String operatorName = mPhone.getServiceState().getOperatorAlphaLong();
1743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (operatorName != null) {
1744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (operatorName.length() > 16) {
1745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        operatorName = operatorName.substring(0, 16);
1746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
1748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            "+COPS: 0,0,\"" + operatorName + "\"");
1749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
1751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            "+COPS: 0,0,\"UNKNOWN\",0");
1752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree only supports AT+COPS=3,0
1757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 2 || !(args[0] instanceof Integer)
1758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    || !(args[1] instanceof Integer)) {
1759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // syntax error
1760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if ((Integer)args[0] != 3 || (Integer)args[1] != 0) {
1762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Out of spec, but lets be friendly
1770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+COPS: (3),(0)");
1771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile PIN
1775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CPIN is not in the handsfree spec (although it is in 3GPP)
1776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPIN", new AtCommandHandler() {
1777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPIN: READY");
1780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Response and Hold
1784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Only supported on PDC (Japan) and CDMA networks.
1785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BTRH", new AtCommandHandler() {
1786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Replying with just OK indicates no response and hold
1789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // features in use now
1790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Neeed PDC or CDMA
1795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Request International Mobile Subscriber Identity (IMSI)
1800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Not in bluetooth handset spec
1801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIMI", new AtCommandHandler() {
1802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1803b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1804b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CIMI
1805b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String imsi = mPhone.getSubscriberId();
1806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (imsi == null || imsi.length() == 0) {
1807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.SIM_FAILURE);
1808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(imsi);
1810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Calling Line Identification Presentation
1815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLIP", new AtCommandHandler() {
1816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Currently assumes the network is provisioned for CLIP
1819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: " + (mClip ? "1" : "0") + ",1");
1820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CLIP=<n>
1824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && (args[0].equals(0) || args[0].equals(1))) {
1825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClip = args[0].equals(1);
1826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1828b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1832b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: (0-1)");
1834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGSN - Returns the device IMEI number.
1838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGSN", new AtCommandHandler() {
1839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Get the IMEI of the device.
1842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // mPhone will not be NULL at this point.
1843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CGSN: " + mPhone.getDeviceId());
1844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMM - Query Model Information
1848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMM", new AtCommandHandler() {
1849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
1852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String model = SystemProperties.get("ro.product.model");
1853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (model != null) {
1854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMM: " + model);
1855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1859b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1860b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1861b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMI - Query Manufacturer Information
1862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMI", new AtCommandHandler() {
1863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1865b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
1866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String manuf = SystemProperties.get("ro.product.manufacturer");
1867b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (manuf != null) {
1868b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMI: " + manuf);
1869b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Noise Reduction and Echo Cancellation control
1876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+NREC", new AtCommandHandler() {
1877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args[0].equals(0)) {
1880aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent                    mAudioManager.setParameters(HEADSET_NREC+"=off");
1881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(1)) {
1883aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent                    mAudioManager.setParameters(HEADSET_NREC+"=on");
1884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1888b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1890b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Voice recognition (dialing)
1891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BVRA", new AtCommandHandler() {
1892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1893b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
18946967e2d953bc077c99c4831946201f3d333b833fNick Pelly                if (BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
18956967e2d953bc077c99c4831946201f3d333b833fNick Pelly                    return new AtCommandResult(AtCommandResult.ERROR);
18966967e2d953bc077c99c4831946201f3d333b833fNick Pelly                }
1897b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && args[0].equals(1)) {
1898b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    synchronized (BluetoothHandsfree.this) {
1899b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (!mWaitingForVoiceRecognition) {
1900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            try {
1901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                mContext.startActivity(sVoiceCommandIntent);
1902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            } catch (ActivityNotFoundException e) {
1903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                return new AtCommandResult(AtCommandResult.ERROR);
1904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            }
1905b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            expectVoiceRecognition();
1906b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1907b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1908b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing yet
1909b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args.length >= 1 && args[0].equals(0)) {
1910b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOff();
1911b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1912b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1913b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1914b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1915b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1916b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
19176967e2d953bc077c99c4831946201f3d333b833fNick Pelly                return new AtCommandResult("+BVRA: (0-1)");
1918b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1919b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1920b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1921b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Retrieve Subscriber Number
1922b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CNUM", new AtCommandHandler() {
1923b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1924b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1925b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String number = mPhone.getLine1Number();
1926b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
1927b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1928b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CNUM: ,\"" + number + "\"," +
1930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        PhoneNumberUtils.toaFromString(number) + ",,4");
1931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Microphone Gain
1935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGM", new AtCommandHandler() {
1936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGM=<gain>    in range [0,15]
1939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Headset/Handsfree is reporting its current gain setting
1940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Speaker Gain
1945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGS", new AtCommandHandler() {
1946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGS=<gain>    in range [0,15]
1949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 1 || !(args[0] instanceof Integer)) {
1950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mScoGain = (Integer) args[0];
1953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int flag =  mAudioManager.isBluetoothScoOn() ? AudioManager.FLAG_SHOW_UI:0;
1954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, mScoGain, flag);
1956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Phone activity status
1961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPAS", new AtCommandHandler() {
1962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int status = 0;
1965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (mPhone.getState()) {
1966b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case IDLE:
1967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 0;
1968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RINGING:
1970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 3;
1971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case OFFHOOK:
1973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 4;
1974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPAS: " + status);
1977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook.register(parser);
1980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void sendScoGainUpdate(int gain) {
1983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mScoGain != gain && (mRemoteBrsf & BRSF_HF_REMOTE_VOL_CONTROL) != 0x0) {
1984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+VGS:" + gain);
1985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mScoGain = gain;
1986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public AtCommandResult reportCmeError(int error) {
1990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mCmee) {
1991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
1992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse("+CME ERROR: " + error);
1993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
1994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
1996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_CALL_TIMEOUT = 10000;  // ms
2000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectCallStart() {
2002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForCallStart = true;
2003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_CALL_STARTED);
2004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_CALL_TIMEOUT);
2005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartCallWakeLock.isHeld()) {
2006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartCallWakeLock.acquire(START_CALL_TIMEOUT);
2007b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2008b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void callStarted() {
2011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForCallStart) {
2012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForCallStart = false;
2013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
2014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mStartCallWakeLock.isHeld()) {
2015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStartCallWakeLock.release();
2016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_VOICE_RECOGNITION_TIMEOUT = 5000;  // ms
2021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectVoiceRecognition() {
2023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForVoiceRecognition = true;
2024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_VOICE_RECOGNITION_STARTED);
2025b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_VOICE_RECOGNITION_TIMEOUT);
2026b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartVoiceRecognitionWakeLock.isHeld()) {
2027b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.acquire(START_VOICE_RECOGNITION_TIMEOUT);
2028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean startVoiceRecognition() {
2032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForVoiceRecognition) {
2033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // HF initiated
2034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForVoiceRecognition = false;
2035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
2036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
2037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // AG initiated
2038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+BVRA: 1");
2039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean ret = audioOn();
2041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mStartVoiceRecognitionWakeLock.isHeld()) {
2042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.release();
2043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return ret;
2045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean stopVoiceRecognition() {
2048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        sendURC("+BVRA: 0");
2049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
2050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
2051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2052b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean inDebug() {
2054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return DBG && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE, false);
2055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean allowAudioAnytime() {
2058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return inDebug() && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE_AUDIO_ANYTIME,
2059b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                false);
2060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void startDebug() {
2063b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG && mDebugThread == null) {
2064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = new DebugThread();
2065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.start();
2066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void stopDebug() {
2070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mDebugThread != null) {
2071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.interrupt();
2072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = null;
2073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Debug thread to read debug properties - runs when debug.bt.hfp is true
2077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  at the time a bluetooth handsfree device is connected. Debug properties
2078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  are polled and mock updates sent every 1 second */
2079b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class DebugThread extends Thread {
2080b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Turns on/off handsfree profile debugging mode */
2081b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE = "debug.bt.hfp";
2082b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2083b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock battery level change - use 0 to 5 */
2084b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_BATTERY = "debug.bt.hfp.battery";
2085b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock no cellular service when false */
2087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SERVICE = "debug.bt.hfp.service";
2088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock cellular roaming when true */
2090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_ROAM = "debug.bt.hfp.roam";
2091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** false to true transition will force an audio (SCO) connection to
2093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         *  be established. true to false will force audio to be disconnected
2094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO = "debug.bt.hfp.audio";
2096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** true allows incoming SCO connection out of call.
2098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO_ANYTIME = "debug.bt.hfp.audio_anytime";
2100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock signal strength change in ASU - use 0 to 31 */
2102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SIGNAL = "debug.bt.hfp.signal";
2103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+CLCC: print +CLCC result */
2105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_CLCC = "debug.bt.hfp.clcc";
2106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+BSIR - Send In Band Ringtones Unsolicited AT command.
2108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 0 => AT+BSIR = 0 sent by the AG
2109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 1 => AT+BSIR = 0 sent by the AG
2110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Other values are ignored.
2111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
2112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_UNSOL_INBAND_RINGTONE =
2114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            "debug.bt.unsol.inband";
2115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
2117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public void run() {
2118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldService = true;
2119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldRoam = false;
2120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldAudio = false;
2121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (!isInterrupted() && inDebug()) {
2123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int batteryLevel = SystemProperties.getInt(DEBUG_HANDSFREE_BATTERY, -1);
2124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (batteryLevel >= 0 && batteryLevel <= 5) {
2125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
2126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("level", batteryLevel);
2127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("scale", 5);
21281dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateBatteryState(intent);
2129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                boolean serviceStateChanged = false;
2132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_SERVICE, true) != oldService) {
2133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldService = !oldService;
2134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
2135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_ROAM, false) != oldRoam) {
2137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldRoam = !oldRoam;
2138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
2139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (serviceStateChanged) {
2141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Bundle b = new Bundle();
2142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putInt("state", oldService ? 0 : 1);
2143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putBoolean("roaming", oldRoam);
21441dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateServiceState(true, ServiceState.newFromBundle(b));
2145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_AUDIO, false) != oldAudio) {
2148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldAudio = !oldAudio;
2149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (oldAudio) {
2150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
2151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
2152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOff();
2153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
2154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1);
2157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (signalLevel >= 0 && signalLevel <= 31) {
2158404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1,
2159404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                            -1, -1, -1, true);
2160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
2161404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    Bundle data = new Bundle();
2162404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    signalStrength.fillInNotifierBundle(data);
2163404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    intent.putExtras(data);
21641dad0387bf2f280c12bdac172604e9779134fbcdJaikumar Ganesh                    mBluetoothPhoneState.updateSignalState(intent);
2165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_CLCC, false)) {
2168c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                    log(gsmGetClccResult().toString());
2169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                try {
2171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sleep(1000);  // 1 second
2172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } catch (InterruptedException e) {
2173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
2174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int inBandRing =
2177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    SystemProperties.getInt(DEBUG_UNSOL_INBAND_RINGTONE, -1);
2178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (inBandRing == 0 || inBandRing == 1) {
2179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result =
2180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        new AtCommandResult(AtCommandResult.UNSOLICITED);
2181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+BSIR: " + inBandRing);
2182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC(result.toString());
2183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
2184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
2185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
2186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2188c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    public void cdmaSwapSecondCallState() {
21898eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("cdmaSetSecondCallState: Toggling mCdmaIsSecondCallActive");
2190c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive;
2191c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
2192c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
2193c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    public void cdmaSetSecondCallState(boolean state) {
21948eb32ddb60cfe1a0d0733735c30ecfc814452806Jackson Fan        if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state);
2195c9d9ed30aa547b79b81adc13a4d148a003b6ee62w        mCdmaIsSecondCallActive = state;
2196c9d9ed30aa547b79b81adc13a4d148a003b6ee62w    }
2197c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
2198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static void log(String msg) {
2199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Log.d(TAG, msg);
2200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
2202