BluetoothHandsfree.java revision 404edc94de563aef5fd5ba48be9114a970cb93bb
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;
22b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
234079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Projectimport android.bluetooth.BluetoothHeadset;
244079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Projectimport android.bluetooth.BluetoothIntent;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.HeadsetBase;
26b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.ScoSocket;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.ActivityNotFoundException;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.IntentFilter;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.AsyncResult;
35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle;
36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message;
38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager;
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager.WakeLock;
40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.SystemProperties;
41b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.ServiceState;
43404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.telephony.SignalStrength;
44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
45b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Call;
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Connection;
48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Phone;
49b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.TelephonyIntents;
50b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.LinkedList;
52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Bluetooth headset manager for the Phone app.
54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * @hide
55b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class BluetoothHandsfree {
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String TAG = "BT HS/HF";
58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final boolean DBG = false;
59b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final boolean VDBG = false;  // even more logging
60b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_UNKNOWN           = 0;
62b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HEADSET           = 1;
63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final int TYPE_HANDSFREE         = 2;
64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
654079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private final Context mContext;
664079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private final Phone mPhone;
67b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ServiceState mServiceState;
68b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private HeadsetBase mHeadset;  // null when not connected
69b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mHeadsetType;
70b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mAudioPossible;
71b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mIncomingSco;
72b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mOutgoingSco;
73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket mConnectedSco;
74b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
75b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mForegroundCall;
76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mBackgroundCall;
77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Call mRingingCall;
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AudioManager mAudioManager;
80b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private PowerManager mPowerManager;
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mUserWantsAudio;
83b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private WakeLock mStartVoiceRecognitionWakeLock;  // held while waiting for voice recognition
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
86b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // AT command state
87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
88b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
89b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long mBgndEarliestConnectionTime = 0;
90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mClip = false;  // Calling Line Information Presentation
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mIndicatorsEnabled = false;
92b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mCmee = false;  // Extended Error reporting
93b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private long[] mClccTimestamps; // Timestamps associated with each clcc index
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean[] mClccUsed;     // Is this clcc index in use
95b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForCallStart;
96b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean mWaitingForVoiceRecognition;
97b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
98b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final BluetoothPhoneState mPhoneState;  // for CIND and CIEV updates
99b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final BluetoothAtPhonebook mPhonebook;
100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private DebugThread mDebugThread;
102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mScoGain = Integer.MIN_VALUE;
103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static Intent sVoiceCommandIntent;
105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Audio parameters
107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NREC = "bt_headset_nrec";
108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String HEADSET_NAME = "bt_headset_name";
109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mRemoteBrsf = 0;
111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private int mLocalBrsf = 0;
112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */
1146967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
1156967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_EC_NR = 1 << 1;
1166967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_RECOG = 1 << 2;
1176967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_IN_BAND_RING = 1 << 3;
1186967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
1196967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_REJECT_CALL = 1 << 5;
1206967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
1216967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
1226967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
1236967e2d953bc077c99c4831946201f3d333b833fNick Pelly
1246967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_EC_NR = 1 << 0;
1256967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
1266967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_CLIP = 1 << 2;
1276967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
1286967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
1296967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
1306967e2d953bc077c99c4831946201f3d333b833fNick Pelly    private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static String typeToString(int type) {
133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (type) {
134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_UNKNOWN:
135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "unknown";
136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HEADSET:
137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "headset";
138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case TYPE_HANDSFREE:
139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return "handsfree";
140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return null;
142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public BluetoothHandsfree(Context context, Phone phone) {
145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhone = phone;
146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext = context;
147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        BluetoothDevice bluetooth =
148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                (BluetoothDevice)context.getSystemService(Context.BLUETOOTH_SERVICE);
149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean bluetoothCapable = (bluetooth != null);
150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;  // nothing connected yet
151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":StartCall");
155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartCallWakeLock.setReferenceCounted(false);
156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                       TAG + ":VoiceRecognition");
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mStartVoiceRecognitionWakeLock.setReferenceCounted(false);
159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mLocalBrsf = BRSF_AG_THREE_WAY_CALLING |
161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_EC_NR |
162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_REJECT_CALL |
163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                     BRSF_AG_ENHANCED_CALL_STATUS;
1644b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (sVoiceCommandIntent == null) {
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1696967e2d953bc077c99c4831946201f3d333b833fNick Pelly        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null &&
1706967e2d953bc077c99c4831946201f3d333b833fNick Pelly                !BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mLocalBrsf |= BRSF_AG_VOICE_RECOG;
172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (bluetoothCapable) {
175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            resetAtState();
176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mRingingCall = mPhone.getRingingCall();
179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mForegroundCall = mPhone.getForegroundCall();
180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mBackgroundCall = mPhone.getBackgroundCall();
181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhoneState = new BluetoothPhoneState();
182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook = new BluetoothAtPhonebook(mContext, this);
184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothEnabled() {
188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* Bluez has a bug where it will always accept and then orphan
189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * incoming SCO connections, regardless of whether we have a listening
190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * SCO socket. So the best thing to do is always run a listening socket
191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * while bluetooth is on so that at least we can diconnect it
192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * immediately when we don't want it.
193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco == null) {
195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = createScoSocket();
196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.accept();
197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void onBluetoothDisabled() {
201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mAudioManager.setBluetoothScoOn(false);
2034079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco.close();
205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco = null;
206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco.close();
209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mIncomingSco != null) {
212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco.close();
213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIncomingSco = null;
214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isHeadsetConnected() {
218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadset == null) {
219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mHeadset.isConnected();
222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void connectHeadset(HeadsetBase headset, int headsetType) {
225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = headset;
226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadsetType = headsetType;
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mHeadsetType == TYPE_HEADSET) {
228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHeadsetAtParser();
229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            initializeHandsfreeAtParser();
231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        headset.startEventThread();
233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        configAudioParameters();
234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (inDebug()) {
236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            startDebug();
237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isIncallAudio()) {
240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            audioOn();
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* returns true if there is some kind of in-call audio we may wish to route
245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * bluetooth to */
246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean isIncallAudio() {
247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call.State state = mForegroundCall.getState();
248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (state == Call.State.ACTIVE || state == Call.State.ALERTING);
250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void disconnectHeadset() {
253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHeadset = null;
254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        stopDebug();
255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        resetAtState();
256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void resetAtState() {
259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mClip = false;
260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mIndicatorsEnabled = false;
261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mCmee = false;
262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mClccTimestamps = new long[MAX_CONNECTIONS];
263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mClccUsed = new boolean[MAX_CONNECTIONS];
264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int i = 0; i < MAX_CONNECTIONS; i++) {
265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mRemoteBrsf = 0;
268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void configAudioParameters() {
271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String name = mHeadset.getName();
272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (name == null) {
273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            name = "<unknown>";
274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mAudioManager.setParameter(HEADSET_NAME, name);
276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mAudioManager.setParameter(HEADSET_NREC, "on");
277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Represents the data that we send in a +CIND or +CIEV command to the HF
281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class BluetoothPhoneState {
283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no service
284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: service
285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mService;
286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no active call
288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: active call (where active means audio is routed - not held call)
289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCall;
290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not in call setup
292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: incoming call setup
293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: outgoing call setup
294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 3: remote party being alerted in an outgoing call setup
295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallsetup;
296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: no calls held
298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: held call and active call
299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 2: held call only
300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mCallheld;
301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength of AG: 0-5
303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mSignal;
304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // cellular signal strength in CSQ rssi scale
306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRssi;  // for CSQ
307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: roaming not active (home)
309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: roaming active
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mRoam;
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // battery charge of AG: 0-5
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mBattchg;
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 0: not registered
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 1: registered, home network
317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // 5: registered, roaming
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int mStat;  // for CREG
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private String mRingingNumber;  // Context for in-progress RING's
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int    mRingingType;
322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean mIgnoreRing = false;
323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int SERVICE_STATE_CHANGED = 1;
325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int PHONE_STATE_CHANGED = 2;
326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final int RING = 3;
327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private Handler mStateChangeHandler = new Handler() {
329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void handleMessage(Message msg) {
331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch(msg.what) {
332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RING:
333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result = ring();
334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (result != null) {
335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        sendURC(result.toString());
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case SERVICE_STATE_CHANGED:
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateServiceState(sendUpdate(), state);
341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case PHONE_STATE_CHANGED:
343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Connection connection = null;
344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (((AsyncResult) msg.obj).result instanceof Connection) {
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        connection = (Connection) ((AsyncResult) msg.obj).result;
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updatePhoneState(sendUpdate(), connection);
348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private BluetoothPhoneState() {
354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // init members
355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updateServiceState(false, mPhone.getServiceState());
356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            updatePhoneState(false, null);
357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mBattchg = 5;  // There is currently no API to get battery level
358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           // on demand, so set to 5 and wait for an update
359404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            mSignal = asuToSignal(mPhone.getSignalStrength());
360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // register for updates
362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhone.registerForServiceStateChanged(mStateChangeHandler,
363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                  SERVICE_STATE_CHANGED, null);
364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mPhone.registerForPhoneStateChanged(mStateChangeHandler,
365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                                PHONE_STATE_CHANGED, null);
366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            filter.addAction(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mContext.registerReceiver(mStateReceiver, filter);
369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
371a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        private void updateBtPhoneStateAfterRadioTechnologyChange() {
372a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            if(DBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
373a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
374a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Unregister all events from the old obsolete phone
375a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            mPhone.unregisterForServiceStateChanged(mStateChangeHandler);
376a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            mPhone.unregisterForPhoneStateChanged(mStateChangeHandler);
377a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
378a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            //Register all events new to the new active phone
379a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            mPhone.registerForServiceStateChanged(mStateChangeHandler, SERVICE_STATE_CHANGED, null);
380a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville            mPhone.registerForPhoneStateChanged(mStateChangeHandler, PHONE_STATE_CHANGED, null);
381a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        }
382a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendUpdate() {
384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled;
385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean sendClipUpdate() {
388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mClip;
389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,31] ASU signal strength to the [0,5] expected by
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * bluetooth devices. Scale is similar to status bar policy
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
394404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        private int gsmAsuToSignal(int asu) {
395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if      (asu >= 16) return 5;
396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 8)  return 4;
397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 4)  return 3;
398b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 2)  return 2;
399b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else if (asu >= 1)  return 1;
400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            else                return 0;
401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
403404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        /* convert cdma dBm signal strength to the [0,5] expected by
404404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville         * bluetooth devices. Scale is similar to status bar policy
405404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville         */
406404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        private int cdmaDbmToSignal(int cdmaDbm) {
407404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            if (cdmaDbm >= -75)       return 5;
408404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            else if (cdmaDbm >= -85)  return 4;
409404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            else if (cdmaDbm >= -95)  return 3;
410404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            else if (cdmaDbm >= -100) return 2;
411404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            else if (cdmaDbm >= -105) return 2;
412404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            else return 0;
413404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
414404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
415404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
416404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        private int asuToSignal(SignalStrength signalStrength) {
417404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            if (!signalStrength.isGsm()) {
418404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                return gsmAsuToSignal(signalStrength.getCdmaDbm());
419404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
420404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                return cdmaDbmToSignal(signalStrength.getGsmSignalStrength());
421404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            }
422404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville        }
423404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
424404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* convert [0,5] signal strength to a rssi signal strength for CSQ
426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * which is [0,31]. Despite the same scale, this is not the same value
427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * as ASU.
428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private int signalToRssi(int signal) {
430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // using C4A suggested values
431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (signal) {
432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 0: return 0;
433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 1: return 4;
434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 2: return 8;
435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 3: return 13;
436b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 4: return 19;
437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case 5: return 31;
438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return 0;
440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public void onReceive(Context context, Intent intent) {
446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateBatteryState(intent);
448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (intent.getAction().equals(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED)) {
449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    updateSignalState(intent);
450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateBatteryState(Intent intent) {
455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int batteryLevel = intent.getIntExtra("level", -1);
456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int scale = intent.getIntExtra("scale", -1);
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (batteryLevel == -1 || scale == -1) {
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return;  // ignore
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            batteryLevel = batteryLevel * 5 / scale;
461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mBattchg != batteryLevel) {
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mBattchg = batteryLevel;
463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate()) {
464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC("+CIEV: 7," + mBattchg);
465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateSignalState(Intent intent) {
470404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent
471404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread
472404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras());
473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int signal;
474404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville
475404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            if (signalStrength != null) {
476404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                signal = asuToSignal(signalStrength);
477404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                mRssi = signalToRssi(signal);  // no unsolicited CSQ
478404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                if (signal != mSignal) {
479404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    mSignal = signal;
480404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    if (sendUpdate()) {
481404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                        sendURC("+CIEV: 5," + mSignal);
482404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    }
483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
484404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville            } else {
485404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                Log.e(TAG, "Signal Strength null");
486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
488b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updateServiceState(boolean sendUpdate, ServiceState state) {
490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int service = state.getState() == ServiceState.STATE_IN_SERVICE ? 1 : 0;
491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int roam = state.getRoaming() ? 1 : 0;
492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int stat;
493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
494b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service == 0) {
496b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = 0;
497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stat = (roam == 1) ? 5 : 1;
499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (service != mService) {
502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mService = service;
503b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
504b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 1," + mService);
505b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
506b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
507b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (roam != mRoam) {
508b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mRoam = roam;
509b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 6," + mRoam);
511b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (stat != mStat) {
514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStat = stat;
515b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(toCregString());
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void updatePhoneState(boolean sendUpdate, Connection connection) {
524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int call = 0;
525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callsetup = 0;
526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int callheld = 0;
527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int prevCallsetup = mCallsetup;
528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("updatePhoneState()");
531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (mPhone.getState()) {
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case IDLE:
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mUserWantsAudio = true;  // out of call - reset state
535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                audioOff();
536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callStarted();
539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mForegroundCall.getState()) {
542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ACTIVE:
543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                call = 1;
544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case DIALING:
547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 2;
548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = false;
549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case ALERTING:
551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 3;
552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Open the SCO channel for the outgoing call.
553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                audioOn();
554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = true;
555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioPossible = false;
558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mRingingCall.getState()) {
561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case INCOMING:
562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case WAITING:
563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                callsetup = 1;
564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch(mBackgroundCall.getState()) {
568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case HOLDING:
569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 1;
571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    call = 1;
573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    callheld = 2;
574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCall != call) {
579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (call == 1) {
580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This means that a call has transitioned from NOT ACTIVE to ACTIVE.
581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Switch on audio.
582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCall = call;
585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 2," + mCall);
587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallsetup != callsetup) {
590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallsetup = callsetup;
591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
5924b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // If mCall = 0, send CIEV
5934b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 0, send CIEV
5944b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 1, send CIEV after CCWA,
5954b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way supported.
5964b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // mCall = 1, mCallsetup = 2 / 3 -> send CIEV,
5974b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    // if 3 way is supported
5984b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                    if (mCall != 1 || mCallsetup == 0 ||
5994b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CIEV: 3," + mCallsetup);
601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean callsSwitched =
606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                (callheld == 1 && ! (mBackgroundCall.getEarliestConnectTime() ==
607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mBgndEarliestConnectionTime));
608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mBgndEarliestConnectionTime = mBackgroundCall.getEarliestConnectTime();
610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mCallheld != callheld || callsSwitched) {
612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCallheld = callheld;
613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendUpdate) {
614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CIEV: 4," + mCallheld);
615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
617b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (callsetup == 1 && callsetup != prevCallsetup) {
619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // new incoming call
620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String number = null;
621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int type = 128;
622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // find incoming phone number and type
623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection == null) {
624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    connection = mRingingCall.getEarliestConnection();
625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (connection == null) {
626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.e(TAG, "Could not get a handle on Connection object for new " +
627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                              "incoming call");
628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (connection != null) {
631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = connection.getAddress();
632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (number != null) {
633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        type = PhoneNumberUtils.toaFromString(number);
634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    number = "";
638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if ((call != 0 || callheld != 0) && sendUpdate) {
640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // call waiting
641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        result.addResponse("+CCWA: \"" + number + "\"," + type);
6434b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project                        result.addResponse("+CIEV: 3," + callsetup);
644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // regular new incoming call
647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingNumber = number;
648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRingingType = type;
649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mIgnoreRing = false;
650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if ((mLocalBrsf & BRSF_AG_IN_BAND_RING) == 0x1) {
652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResult(ring());
655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC(result.toString());
658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private AtCommandResult ring() {
661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!mIgnoreRing && mRingingCall.isRinging()) {
662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                result.addResponse("RING");
664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (sendClipUpdate()) {
665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+CLIP: \"" + mRingingNumber + "\"," + mRingingType);
666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Message msg = mStateChangeHandler.obtainMessage(RING);
669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStateChangeHandler.sendMessageDelayed(msg, 3000);
670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return result;
671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;
673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized String toCregString() {
676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new String("+CREG: 1," + mStat);
677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCindResult() {
680b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CIND: " + mService + "," + mCall + "," + mCallsetup + "," +
682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mCallheld + "," + mSignal + "," + mRoam + "," + mBattchg;
683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult toCsqResult() {
688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String status = "+CSQ: " + mRssi + ",99";
690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse(status);
691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized AtCommandResult getCindTestResult() {
696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult("+CIND: (\"service\",(0-1))," + "(\"call\",(0-1))," +
697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))," +
698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "(\"roam\",(0-1)),(\"battchg\",(0-5))");
699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private synchronized void ignoreRing() {
702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mCallsetup = 0;
703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mIgnoreRing = true;
704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (sendUpdate()) {
705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                sendURC("+CIEV: 3," + mCallsetup);
706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_ACCEPTED = 1;
712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CONNECTED = 2;
713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int SCO_CLOSED = 3;
714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_CALL_STARTED = 4;
715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int CHECK_VOICE_RECOGNITION_STARTED = 5;
716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final Handler mHandler = new Handler() {
718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public synchronized void handleMessage(Message msg) {
720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (msg.what) {
721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case SCO_ACCEPTED:
722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (isHeadsetConnected() && (mAudioPossible || allowAudioAnytime()) &&
724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mConnectedSco == null) {
725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.i(TAG, "Routing audio for incoming SCO connection");
726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mConnectedSco = (ScoSocket)msg.obj;
727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mAudioManager.setBluetoothScoOn(true);
7284079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project                        broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED);
729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Log.i(TAG, "Rejecting incoming SCO connection");
731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        ((ScoSocket)msg.obj).close();
732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } // else error trying to accept, try again
734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mIncomingSco = createScoSocket();
735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mIncomingSco.accept();
736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case SCO_CONNECTED:
738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (msg.arg1 == ScoSocket.STATE_CONNECTED && isHeadsetConnected() &&
739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mConnectedSco == null) {
740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("Routing audio for outgoing SCO conection");
741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mConnectedSco = (ScoSocket)msg.obj;
742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mAudioManager.setBluetoothScoOn(true);
7434079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project                    broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_CONNECTED);
744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("Rejecting new connected outgoing SCO socket");
746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    ((ScoSocket)msg.obj).close();
747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mOutgoingSco.close();
748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mOutgoingSco = null;
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case SCO_CLOSED:
752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mConnectedSco == (ScoSocket)msg.obj) {
753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mConnectedSco = null;
754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mAudioManager.setBluetoothScoOn(false);
7554079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project                    broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (mOutgoingSco == (ScoSocket)msg.obj) {
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mOutgoingSco = null;
758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (mIncomingSco == (ScoSocket)msg.obj) {
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mIncomingSco = null;
760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case CHECK_CALL_STARTED:
763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mWaitingForCallStart) {
764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mWaitingForCallStart = false;
765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Log.e(TAG, "Timeout waiting for call to start");
766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC("ERROR");
767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (mStartCallWakeLock.isHeld()) {
768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mStartCallWakeLock.release();
769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case CHECK_VOICE_RECOGNITION_STARTED:
773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mWaitingForVoiceRecognition) {
774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mWaitingForVoiceRecognition = false;
775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Log.e(TAG, "Timeout waiting for voice recognition to start");
776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC("ERROR");
777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ScoSocket createScoSocket() {
784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new ScoSocket(mPowerManager, mHandler, SCO_ACCEPTED, SCO_CONNECTED, SCO_CLOSED);
785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7874079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    private void broadcastAudioStateIntent(int state) {
7884079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        if (VDBG) log("broadcastAudioStateIntent(" + state + ")");
7894079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        Intent intent = new Intent(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION);
7904079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        intent.putExtra(BluetoothIntent.HEADSET_AUDIO_STATE, state);
7914079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
7924079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project    }
7934079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project
794a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
795a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    void updateBtHandsfreeAfterRadioTechnologyChange() {
796a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        if(DBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
797a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
798a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        //Get the Call references from the new active phone again
799a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mRingingCall = mPhone.getRingingCall();
800a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mForegroundCall = mPhone.getForegroundCall();
801a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mBackgroundCall = mPhone.getBackgroundCall();
802a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
803a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville        mPhoneState.updateBtPhoneStateAfterRadioTechnologyChange();
804a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville    }
805a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to establish SCO (audio) connection to bluetooth
807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns false if the user has requested audio off, or if there
809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * is some other immediate problem that will prevent BT audio.
810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean audioOn() {
812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (VDBG) log("audioOn()");
813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!isHeadsetConnected()) {
814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): headset is not connected!");
815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): audio is already connected");
820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mUserWantsAudio) {
824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): user requested no audio, ignoring");
825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
828b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("audioOn(): outgoing SCO already in progress");
830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
832b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mOutgoingSco = createScoSocket();
833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mOutgoingSco.connect(mHeadset.getAddress())) {
834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio on.
841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will establish SCO (BT audio), even if the user requested it off
842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  previously on this call.
843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOn() {
845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = true;
846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOn();
847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Used to indicate the user requested BT audio off.
849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  This will prevent us from establishing BT audio again during this call
850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  if audioOn() is called.
851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void userWantsAudioOff() {
853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mUserWantsAudio = false;
854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Request to disconnect SCO (audio) connection to bluetooth
858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * headset/handsfree, if one is connected. Does not block.
859b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
860b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized void audioOff() {
861b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (VDBG) log("audioOff()");
862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectedSco != null) {
864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mAudioManager.setBluetoothScoOn(false);
8654079f559beb3e414036056b4b33ad40de5e89c4aThe Android Open Source Project            broadcastAudioStateIntent(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco.close();
867b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectedSco = null;
868b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
869b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mOutgoingSco != null) {
870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco.close();
871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mOutgoingSco = null;
872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ boolean isAudioOn() {
876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (mConnectedSco != null);
877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void ignoreRing() {
880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhoneState.ignoreRing();
881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void sendURC(String urc) {
884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isHeadsetConnected()) {
885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mHeadset.sendURC(urc);
886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
888b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** helper to redial last dialled number */
890b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private AtCommandResult redial() {
891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = mPhonebook.getLastDialledNumber();
892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number == null) {
893b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // spec seems to suggest sending ERROR if we dont have a
894b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // number to redial
895b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("Bluetooth redial requested (+BLDN), but no previous " +
896b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                  "outgoing calls found. Ignoring");
897b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
898b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
899b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Uri.fromParts("tel", number, null));
901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mContext.startActivity(intent);
903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // We do not immediately respond OK, wait until we get a phone state
905b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // update. If we return OK now and the handsfree immeidately requests
906b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // our phone state it will say we are not in call yet which confuses
907b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // some devices
908b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        expectCallStart();
909b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
910b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
911b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
912b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Build the +CLCC result
913b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  The complexity arises from the fact that we need to maintain the same
914b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  CLCC index even as a call moves between states. */
915b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized AtCommandResult getClccResult() {
916b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Collect all known connections
917b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Connection[] clccConnections = new Connection[MAX_CONNECTIONS];  // indexed by CLCC index
918b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> newConnections = new LinkedList<Connection>();
919b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        LinkedList<Connection> connections = new LinkedList<Connection>();
920b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mRingingCall.getState().isAlive()) {
921b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mRingingCall.getConnections());
922b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
923b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mForegroundCall.getState().isAlive()) {
924b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mForegroundCall.getConnections());
925b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
926b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mBackgroundCall.getState().isAlive()) {
927b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            connections.addAll(mBackgroundCall.getConnections());
928b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mark connections that we already known about
931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean clccUsed[] = new boolean[MAX_CONNECTIONS];
932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int i = 0; i < MAX_CONNECTIONS; i++) {
933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccUsed[i] = mClccUsed[i];
934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = false;
935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (Connection c : connections) {
937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean found = false;
938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long timestamp = c.getCreateTime();
939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            for (int i = 0; i < MAX_CONNECTIONS; i++) {
940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClccUsed[i] = true;
942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    found = true;
943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    clccConnections[i] = c;
944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!found) {
948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newConnections.add(c);
949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Find a CLCC index for new connections
953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        while (!newConnections.isEmpty()) {
954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find lowest empty index
955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int i = 0;
956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (mClccUsed[i]) i++;
957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Find earliest connection
958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            long earliestTimestamp = newConnections.get(0).getCreateTime();
959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Connection earliestConnection = newConnections.get(0);
960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            for (int j = 0; j < newConnections.size(); j++) {
961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                long timestamp = newConnections.get(j).getCreateTime();
962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (timestamp < earliestTimestamp) {
963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestTimestamp = timestamp;
964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    earliestConnection = newConnections.get(j);
965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
966b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // update
969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccUsed[i] = true;
970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mClccTimestamps[i] = earliestTimestamp;
971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            clccConnections[i] = earliestConnection;
972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            newConnections.remove(earliestConnection);
973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Build CLCC
976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int i = 0; i < clccConnections.length; i++) {
978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mClccUsed[i]) {
979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String clccEntry = connectionToClccEntry(i, clccConnections[i]);
980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (clccEntry != null) {
981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse(clccEntry);
982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Convert a Connection object into a single +CLCC result */
990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private String connectionToClccEntry(int index, Connection c) {
991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int state;
992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (c.getState()) {
993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ACTIVE:
994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 0;
995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case HOLDING:
997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 1;
998b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
999b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case DIALING:
1000b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 2;
1001b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1002b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case ALERTING:
1003b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 3;
1004b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1005b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case INCOMING:
1006b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 4;
1007b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1008b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        case WAITING:
1009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            state = 5;
1010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            break;
1011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        default:
1012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;  // bad state
1013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int mpty = 0;
1016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Call call = c.getCall();
1017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (call != null) {
1018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mpty = call.isMultiparty() ? 1 : 0;
1019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int direction = c.isIncoming() ? 1 : 0;
1022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = c.getAddress();
1024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int type = -1;
1025b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1026b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            type = PhoneNumberUtils.toaFromString(number);
1027b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
1030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
1031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result += ",\"" + number + "\"," + type;
1032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return result;
1034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Headset profile
1037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHeadsetAtParser() {
1039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("Registering Headset AT commands");
1040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
1041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Headset's usually only have one button, which is meant to cause the
1042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // HS to send us AT+CKPD=200 or AT+CKPD.
1043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CKPD", new AtCommandHandler() {
1044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult headsetButtonPress() {
1045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mRingingCall.isRinging()) {
1046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Answer the call
1047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.answerCall(mPhone);
1048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // If in-band ring tone is supported, SCO connection will already
1049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // be up and the following call will just return.
1050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOn();
1051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (mForegroundCall.getState().isAlive()) {
1052b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (!isAudioOn()) {
1053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Transfer audio from AG to HS
1054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
1055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mHeadset.getDirection() == HeadsetBase.DIRECTION_INCOMING &&
1057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                          (System.currentTimeMillis() - mHeadset.getConnectTimestamp()) < 5000) {
1058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Headset made a recent ACL connection to us - and
1059b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // made a mandatory AT+CKPD request to connect
1060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // audio which races with our automatic audio
1061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // setup.  ignore
1062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1063b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            // Hang up the call
1064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            audioOff();
1065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            PhoneUtils.hangup(mPhone);
1066b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // No current call - redial last number
1070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return redial();
1071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1079b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1080b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return headsetButtonPress();
1081b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1082b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1083b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1084b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1085b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register AT Command handlers to implement the Handsfree profile
1087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void initializeHandsfreeAtParser() {
1089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("Registering Handsfree AT commands");
1090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AtParser parser = mHeadset.getAtParser();
1091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Answer
1093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('A', new AtCommandHandler() {
1094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
1096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                PhoneUtils.answerCall(mPhone);
1097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register('D', new AtCommandHandler() {
1101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleBasicCommand(String args) {
1103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length() > 0) {
1104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args.charAt(0) == '>') {
1105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Yuck - memory dialling requested.
1106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Just dial last number for now
1107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.startsWith(">9999")) {   // for PTS test
1108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return redial();
1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Remove trailing ';'
1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (args.charAt(args.length() - 1) == ';') {
1114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            args = args.substring(0, args.length() - 1);
1115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                Uri.fromParts("tel", args, null));
1118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mContext.startActivity(intent);
1120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        expectCallStart();
1122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
1123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Hang-up command
1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHUP", new AtCommandHandler() {
1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (!mForegroundCall.isIdle()) {
1134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.hangup(mForegroundCall);
1135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!mRingingCall.isIdle()) {
1136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.hangup(mRingingCall);
1137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!mBackgroundCall.isIdle()) {
1138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    PhoneUtils.hangup(mBackgroundCall);
1139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Retrieve Supported Features command
1145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BRSF", new AtCommandHandler() {
1146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private AtCommandResult sendBRSF() {
1147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+BRSF: " + mLocalBrsf);
1148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+BRSF=<handsfree supported features bitmap>
1152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is telling us which features it supports. We
1153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // send the features we support
1154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 1 && (args[0] instanceof Integer)) {
1155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mRemoteBrsf = (Integer) args[0];
1156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Log.w(TAG, "HF didn't sent BRSF assuming 0");
1158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This seems to be out of spec, but lets do the nice thing
1169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return sendBRSF();
1170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call waiting notification on/off
1174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CCWA", new AtCommandHandler() {
1175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Seems to be out of spec, but lets return nicely
1178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Call waiting is always on
1183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: 1");
1184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CCWA=<n>
1188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree is trying to enable/disable call waiting. We
1189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // cannot disable in the current implementation.
1190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Request for range of supported CCWA paramters
1195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CCWA: (\"n\",(1))");
1196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Event Reporting enable/disable command
1200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Of the full 3GPP syntax paramters (mode, keyp, disp, ind, bfr) we
1201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // only support paramter ind (disable/enable evert reporting using
1202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // +CDEV)
1203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMER", new AtCommandHandler() {
1204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(
1207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        "+CMER: 3,0,0," + (mIndicatorsEnabled ? "1" : "0"));
1208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length < 4) {
1212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // This is a syntax error
1213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(3) && args[1].equals(0) &&
1215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                           args[2].equals(0)) {
1216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[3].equals(0)) {
1217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = false;
1218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[3].equals(1)) {
1220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mIndicatorsEnabled = true;
1221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMER: (3),(0),(0),(0-1)");
1231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile Equipment Error Reporting enable/disable
1235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CMEE", new AtCommandHandler() {
1236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // out of spec, assume they want to enable
1239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mCmee = true;
1240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: " + (mCmee ? "1" : "0"));
1245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CMEE=<n>
1249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length == 0) {
1250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // <n> ommitted - default to 0
1251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = false;
1252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (!(args[0] instanceof Integer)) {
1254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Syntax error
1255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mCmee = ((Integer)args[0] == 1);
1258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Probably not required but spec, but no harm done
1264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CMEE: (0-1)");
1265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Last Dialled Number
1269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BLDN", new AtCommandHandler() {
1270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return redial();
1273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Indicator Update command
1277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIND", new AtCommandHandler() {
1278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return mPhoneState.toCindResult();
1281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return mPhoneState.getCindTestResult();
1285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query Signal Quality (legacy)
1289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CSQ", new AtCommandHandler() {
1290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return mPhoneState.toCsqResult();
1293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Query network registration state
1297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CREG", new AtCommandHandler() {
1298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(mPhoneState.toCregString());
1301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Send DTMF. I don't know if we are also expected to play the DTMF tone
1305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // locally, right now we don't
1306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VTS", new AtCommandHandler() {
1307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    char c;
1311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0] instanceof Integer) {
1312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((Integer) args[0]).toString().charAt(0);
1313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        c = ((String) args[0]).charAt(0);
1315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (isValidDtmf(c)) {
1317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mPhone.sendDtmf(c);
1318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            private boolean isValidDtmf(char c) {
1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (c) {
1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '#':
1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case '*':
1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return true;
1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                default:
1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (Character.digit(c, 14) != -1) {
1330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return true;  // 0-9 and A-D
1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return false;
1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // List calls
1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLCC", new AtCommandHandler() {
1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return getClccResult();
1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Call Hold and Multiparty Handling command
1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CHLD", new AtCommandHandler() {
1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1) {
1350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (args[0].equals(0)) {
1351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        boolean result;
1352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mRingingCall.isRinging()) {
1353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            result = PhoneUtils.hangupRingingCall(mPhone);
1354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            result = PhoneUtils.hangupHoldingCall(mPhone);
1356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (result) {
1358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
1359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(1)) {
1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        // Hangup active call, answer held call
1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (PhoneUtils.answerAndEndActive(mPhone)) {
1365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.OK);
1366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
1367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return new AtCommandResult(AtCommandResult.ERROR);
1368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(2)) {
1370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        PhoneUtils.switchHoldingAndActive(mPhone);
1371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else if (args[0].equals(3)) {
1373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (mForegroundCall.getState().isAlive() &&
1374b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            mBackgroundCall.getState().isAlive()) {
1375b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            PhoneUtils.mergeCalls(mPhone);
1376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1377b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        return new AtCommandResult(AtCommandResult.OK);
1378b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1379b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1380b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1384b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CHLD: (0,1,2,3)");
1385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Get Network operator name
1389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+COPS", new AtCommandHandler() {
1390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String operatorName = mPhone.getServiceState().getOperatorAlphaLong();
1393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (operatorName != null) {
1394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (operatorName.length() > 16) {
1395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        operatorName = operatorName.substring(0, 16);
1396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
1398b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            "+COPS: 0,0,\"" + operatorName + "\"");
1399b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(
1401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            "+COPS: 0,0,\"UNKNOWN\",0");
1402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Handsfree only supports AT+COPS=3,0
1407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 2 || !(args[0] instanceof Integer)
1408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    || !(args[1] instanceof Integer)) {
1409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // syntax error
1410b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1411b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if ((Integer)args[0] != 3 || (Integer)args[1] != 0) {
1412b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
1413b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Out of spec, but lets be friendly
1420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+COPS: (3),(0)");
1421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Mobile PIN
1425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CPIN is not in the handsfree spec (although it is in 3GPP)
1426b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPIN", new AtCommandHandler() {
1427b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPIN: READY");
1430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Bluetooth Response and Hold
1434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Only supported on PDC (Japan) and CDMA networks.
1435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BTRH", new AtCommandHandler() {
1436b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Replying with just OK indicates no response and hold
1439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // features in use now
1440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Neeed PDC or CDMA
1445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Request International Mobile Subscriber Identity (IMSI)
1450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Not in bluetooth handset spec
1451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CIMI", new AtCommandHandler() {
1452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CIMI
1455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String imsi = mPhone.getSubscriberId();
1456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (imsi == null || imsi.length() == 0) {
1457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return reportCmeError(BluetoothCmeError.SIM_FAILURE);
1458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(imsi);
1460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Calling Line Identification Presentation
1465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CLIP", new AtCommandHandler() {
1466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleReadCommand() {
1468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Currently assumes the network is provisioned for CLIP
1469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: " + (mClip ? "1" : "0") + ",1");
1470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+CLIP=<n>
1474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && (args[0].equals(0) || args[0].equals(1))) {
1475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mClip = args[0].equals(1);
1476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
1483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CLIP: (0-1)");
1484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGSN - Returns the device IMEI number.
1488b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGSN", new AtCommandHandler() {
1489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Get the IMEI of the device.
1492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // mPhone will not be NULL at this point.
1493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CGSN: " + mPhone.getDeviceId());
1494b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1496b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMM - Query Model Information
1498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMM", new AtCommandHandler() {
1499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
1502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String model = SystemProperties.get("ro.product.model");
1503b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (model != null) {
1504b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMM: " + model);
1505b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1506b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1507b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1508b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1509b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1511b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // AT+CGMI - Query Manufacturer Information
1512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CGMI", new AtCommandHandler() {
1513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1515b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Return the Model Information.
1516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String manuf = SystemProperties.get("ro.product.manufacturer");
1517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (manuf != null) {
1518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult("+CGMI: " + manuf);
1519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1521b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Noise Reduction and Echo Cancellation control
1526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+NREC", new AtCommandHandler() {
1527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args[0].equals(0)) {
1530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mAudioManager.setParameter(HEADSET_NREC, "off");
1531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args[0].equals(1)) {
1533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mAudioManager.setParameter(HEADSET_NREC, "on");
1534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Voice recognition (dialing)
1541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+BVRA", new AtCommandHandler() {
1542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
15446967e2d953bc077c99c4831946201f3d333b833fNick Pelly                if (BluetoothHeadset.DISABLE_BT_VOICE_DIALING) {
15456967e2d953bc077c99c4831946201f3d333b833fNick Pelly                    return new AtCommandResult(AtCommandResult.ERROR);
15466967e2d953bc077c99c4831946201f3d333b833fNick Pelly                }
1547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length >= 1 && args[0].equals(1)) {
1548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    synchronized (BluetoothHandsfree.this) {
1549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (!mWaitingForVoiceRecognition) {
1550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            try {
1551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                mContext.startActivity(sVoiceCommandIntent);
1552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            } catch (ActivityNotFoundException e) {
1553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                return new AtCommandResult(AtCommandResult.ERROR);
1554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            }
1555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            expectVoiceRecognition();
1556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing yet
1559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (args.length >= 1 && args[0].equals(0)) {
1560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    audioOff();
1561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.ERROR);
1564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleTestCommand() {
15676967e2d953bc077c99c4831946201f3d333b833fNick Pelly                return new AtCommandResult("+BVRA: (0-1)");
1568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Retrieve Subscriber Number
1572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CNUM", new AtCommandHandler() {
1573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String number = mPhone.getLine1Number();
1576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (number == null) {
1577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.OK);
1578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CNUM: ,\"" + number + "\"," +
1580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        PhoneNumberUtils.toaFromString(number) + ",,4");
1581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Microphone Gain
1585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGM", new AtCommandHandler() {
1586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGM=<gain>    in range [0,15]
1589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // Headset/Handsfree is reporting its current gain setting
1590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Speaker Gain
1595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+VGS", new AtCommandHandler() {
1596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleSetCommand(Object[] args) {
1598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // AT+VGS=<gain>    in range [0,15]
1599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (args.length != 1 || !(args[0] instanceof Integer)) {
1600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return new AtCommandResult(AtCommandResult.ERROR);
1601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mScoGain = (Integer) args[0];
1603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int flag =  mAudioManager.isBluetoothScoOn() ? AudioManager.FLAG_SHOW_UI:0;
1604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, mScoGain, flag);
1606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult(AtCommandResult.OK);
1607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Phone activity status
1611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        parser.register("+CPAS", new AtCommandHandler() {
1612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            @Override
1613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            public AtCommandResult handleActionCommand() {
1614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int status = 0;
1615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (mPhone.getState()) {
1616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case IDLE:
1617b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 0;
1618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case RINGING:
1620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 3;
1621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case OFFHOOK:
1623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    status = 4;
1624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return new AtCommandResult("+CPAS: " + status);
1627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        });
1629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mPhonebook.register(parser);
1630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void sendScoGainUpdate(int gain) {
1633b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mScoGain != gain && (mRemoteBrsf & BRSF_HF_REMOTE_VOL_CONTROL) != 0x0) {
1634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+VGS:" + gain);
1635b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mScoGain = gain;
1636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public AtCommandResult reportCmeError(int error) {
1640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mCmee) {
1641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
1642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            result.addResponse("+CME ERROR: " + error);
1643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return result;
1644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return new AtCommandResult(AtCommandResult.ERROR);
1646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_CALL_TIMEOUT = 10000;  // ms
1650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectCallStart() {
1652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForCallStart = true;
1653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_CALL_STARTED);
1654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_CALL_TIMEOUT);
1655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartCallWakeLock.isHeld()) {
1656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartCallWakeLock.acquire(START_CALL_TIMEOUT);
1657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1658b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1659b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void callStarted() {
1661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForCallStart) {
1662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForCallStart = false;
1663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
1664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mStartCallWakeLock.isHeld()) {
1665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mStartCallWakeLock.release();
1666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int START_VOICE_RECOGNITION_TIMEOUT = 5000;  // ms
1671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private synchronized void expectVoiceRecognition() {
1673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mWaitingForVoiceRecognition = true;
1674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Message msg = Message.obtain(mHandler, CHECK_VOICE_RECOGNITION_STARTED);
1675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mHandler.sendMessageDelayed(msg, START_VOICE_RECOGNITION_TIMEOUT);
1676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!mStartVoiceRecognitionWakeLock.isHeld()) {
1677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.acquire(START_VOICE_RECOGNITION_TIMEOUT);
1678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1680b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1681b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean startVoiceRecognition() {
1682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mWaitingForVoiceRecognition) {
1683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // HF initiated
1684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mWaitingForVoiceRecognition = false;
1685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("OK");
1686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // AG initiated
1688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sendURC("+BVRA: 1");
1689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean ret = audioOn();
1691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mStartVoiceRecognitionWakeLock.isHeld()) {
1692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mStartVoiceRecognitionWakeLock.release();
1693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return ret;
1695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ synchronized boolean stopVoiceRecognition() {
1698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        sendURC("+BVRA: 0");
1699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioOff();
1700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
1701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean inDebug() {
1704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return DBG && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE, false);
1705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private boolean allowAudioAnytime() {
1708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return inDebug() && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE_AUDIO_ANYTIME,
1709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                false);
1710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void startDebug() {
1713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG && mDebugThread == null) {
1714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = new DebugThread();
1715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.start();
1716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void stopDebug() {
1720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mDebugThread != null) {
1721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread.interrupt();
1722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDebugThread = null;
1723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Debug thread to read debug properties - runs when debug.bt.hfp is true
1727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  at the time a bluetooth handsfree device is connected. Debug properties
1728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *  are polled and mock updates sent every 1 second */
1729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class DebugThread extends Thread {
1730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Turns on/off handsfree profile debugging mode */
1731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE = "debug.bt.hfp";
1732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock battery level change - use 0 to 5 */
1734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_BATTERY = "debug.bt.hfp.battery";
1735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock no cellular service when false */
1737b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SERVICE = "debug.bt.hfp.service";
1738b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1739b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock cellular roaming when true */
1740b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_ROAM = "debug.bt.hfp.roam";
1741b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1742b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** false to true transition will force an audio (SCO) connection to
1743b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         *  be established. true to false will force audio to be disconnected
1744b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
1745b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO = "debug.bt.hfp.audio";
1746b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** true allows incoming SCO connection out of call.
1748b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
1749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_AUDIO_ANYTIME = "debug.bt.hfp.audio_anytime";
1750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Mock signal strength change in ASU - use 0 to 31 */
1752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_SIGNAL = "debug.bt.hfp.signal";
1753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+CLCC: print +CLCC result */
1755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_HANDSFREE_CLCC = "debug.bt.hfp.clcc";
1756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** Debug AT+BSIR - Send In Band Ringtones Unsolicited AT command.
1758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 0 => AT+BSIR = 0 sent by the AG
1759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * debug.bt.unsol.inband = 1 => AT+BSIR = 0 sent by the AG
1760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Other values are ignored.
1761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
1762b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1763b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private static final String DEBUG_UNSOL_INBAND_RINGTONE =
1764b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            "debug.bt.unsol.inband";
1765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1766b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
1767b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public void run() {
1768b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldService = true;
1769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldRoam = false;
1770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean oldAudio = false;
1771b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            while (!isInterrupted() && inDebug()) {
1773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int batteryLevel = SystemProperties.getInt(DEBUG_HANDSFREE_BATTERY, -1);
1774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (batteryLevel >= 0 && batteryLevel <= 5) {
1775b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
1776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("level", batteryLevel);
1777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    intent.putExtra("scale", 5);
1778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mPhoneState.updateBatteryState(intent);
1779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                boolean serviceStateChanged = false;
1782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_SERVICE, true) != oldService) {
1783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldService = !oldService;
1784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
1785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_ROAM, false) != oldRoam) {
1787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldRoam = !oldRoam;
1788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    serviceStateChanged = true;
1789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (serviceStateChanged) {
1791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Bundle b = new Bundle();
1792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putInt("state", oldService ? 0 : 1);
1793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    b.putBoolean("roaming", oldRoam);
1794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mPhoneState.updateServiceState(true, ServiceState.newFromBundle(b));
1795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_AUDIO, false) != oldAudio) {
1798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    oldAudio = !oldAudio;
1799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (oldAudio) {
1800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOn();
1801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
1802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        audioOff();
1803b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1804b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1805b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1);
1807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (signalLevel >= 0 && signalLevel <= 31) {
1808404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1,
1809404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                            -1, -1, -1, true);
1810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Intent intent = new Intent();
1811404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    Bundle data = new Bundle();
1812404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    signalStrength.fillInNotifierBundle(data);
1813404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                    intent.putExtras(data);
1814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    mPhoneState.updateSignalState(intent);
1815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_CLCC, false)) {
1818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    log(getClccResult().toString());
1819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                try {
1821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sleep(1000);  // 1 second
1822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } catch (InterruptedException e) {
1823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
1824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int inBandRing =
1827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    SystemProperties.getInt(DEBUG_UNSOL_INBAND_RINGTONE, -1);
1828b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (inBandRing == 0 || inBandRing == 1) {
1829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    AtCommandResult result =
1830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        new AtCommandResult(AtCommandResult.UNSOLICITED);
1831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    result.addResponse("+BSIR: " + inBandRing);
1832b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    sendURC(result.toString());
1833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static void log(String msg) {
1839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Log.d(TAG, msg);
1840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
1842a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
1843a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
1844a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
1845