16c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/* 2ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Copyright (C) 2012 The Android Open Source Project 3ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 4ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * you may not use this file except in compliance with the License. 6ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * You may obtain a copy of the License at 7ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 8ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 10ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Unless required by applicable law or agreed to in writing, software 11ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * See the License for the specific language governing permissions and 14ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * limitations under the License. 156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */ 166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepackage com.android.bluetooth.hfp; 186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 19dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xuimport android.bluetooth.BluetoothAssignedNumbers; 206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothDevice; 216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothHeadset; 226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothProfile; 236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Intent; 246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.media.AudioManager; 250420b4fe3c7794139218821fab49f7f149d0075eJack Heimport android.os.Looper; 266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.os.Message; 2767ccceab9600aaeec6dc34658c45c074de39aa38Jack Heimport android.os.SystemClock; 282287bc2b01df774378123fe7bc7bca14fee549f7Benjamin Franzimport android.os.UserHandle; 29122e077f24750ee0e7fd650cbfa832edeb216d07Jack Heimport android.support.annotation.VisibleForTesting; 306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.telephony.PhoneNumberUtils; 31448309eada01c130b2fee8977f7fd74875978cbcJack Heimport android.telephony.PhoneStateListener; 326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log; 33c4fbd756e2645147470c486ae96f2253f5e13a52Jack He 34caa5d6ab09bf61f4379413299ae1ab436c503710Jack Heimport com.android.bluetooth.btservice.AdapterService; 35838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwoodimport com.android.bluetooth.btservice.ProfileService; 366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport com.android.internal.util.State; 376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport com.android.internal.util.StateMachine; 38c4fbd756e2645147470c486ae96f2253f5e13a52Jack He 39122e077f24750ee0e7fd650cbfa832edeb216d07Jack Heimport java.io.FileDescriptor; 40122e077f24750ee0e7fd650cbfa832edeb216d07Jack Heimport java.io.PrintWriter; 41122e077f24750ee0e7fd650cbfa832edeb216d07Jack Heimport java.io.StringWriter; 426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport java.util.ArrayList; 43cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jeeimport java.util.HashMap; 44cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jeeimport java.util.Map; 4567ccceab9600aaeec6dc34658c45c074de39aa38Jack Heimport java.util.Objects; 4667ccceab9600aaeec6dc34658c45c074de39aa38Jack Heimport java.util.Scanner; 476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 48122e077f24750ee0e7fd650cbfa832edeb216d07Jack He/** 4967ccceab9600aaeec6dc34658c45c074de39aa38Jack He * A Bluetooth Handset StateMachine 50122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * (Disconnected) 51122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * | ^ 52122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * CONNECT | | DISCONNECTED 53122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * V | 54122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * (Connecting) (Disconnecting) 55122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * | ^ 56122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * CONNECTED | | DISCONNECT 57122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * V | 58122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * (Connected) 59122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * | ^ 60122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * CONNECT_AUDIO | | AUDIO_DISCONNECTED 61122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * V | 62122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * (AudioConnecting) (AudioDiconnecting) 63122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * | ^ 64122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * AUDIO_CONNECTED | | DISCONNECT_AUDIO 65122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * V | 66122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * (AudioOn) 67122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 6867ccceab9600aaeec6dc34658c45c074de39aa38Jack He@VisibleForTesting 6967ccceab9600aaeec6dc34658c45c074de39aa38Jack Hepublic class HeadsetStateMachine extends StateMachine { 706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie private static final String TAG = "HeadsetStateMachine"; 712e8302083499fdf5bb391d055e54c3402b0dc556Andre Eisenbach private static final boolean DBG = false; 726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 7368e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan private static final String HEADSET_NAME = "bt_headset_name"; 7468e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan private static final String HEADSET_NREC = "bt_headset_nrec"; 75bf765c090de4b973f4eede4f4248f5e422454c2dMatthew Xie private static final String HEADSET_WBS = "bt_wbs"; 7667ccceab9600aaeec6dc34658c45c074de39aa38Jack He private static final String HEADSET_AUDIO_FEATURE_ON = "on"; 7767ccceab9600aaeec6dc34658c45c074de39aa38Jack He private static final String HEADSET_AUDIO_FEATURE_OFF = "off"; 7868e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan 796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int CONNECT = 1; 806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int DISCONNECT = 2; 816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int CONNECT_AUDIO = 3; 826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int DISCONNECT_AUDIO = 4; 836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int VOICE_RECOGNITION_START = 5; 846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int VOICE_RECOGNITION_STOP = 6; 856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie // message.obj is an intent AudioManager.VOLUME_CHANGED_ACTION 876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie // EXTRA_VOLUME_STREAM_TYPE is STREAM_BLUETOOTH_SCO 886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int INTENT_SCO_VOLUME_CHANGED = 7; 8950b51beb3bd0885ced514d1bcfda3050f60833ffJack He static final int INTENT_CONNECTION_ACCESS_REPLY = 8; 906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static final int CALL_STATE_CHANGED = 9; 9167ccceab9600aaeec6dc34658c45c074de39aa38Jack He static final int DEVICE_STATE_CHANGED = 10; 9267ccceab9600aaeec6dc34658c45c074de39aa38Jack He static final int SEND_CCLC_RESPONSE = 11; 9367ccceab9600aaeec6dc34658c45c074de39aa38Jack He static final int SEND_VENDOR_SPECIFIC_RESULT_CODE = 12; 9467ccceab9600aaeec6dc34658c45c074de39aa38Jack He static final int SEND_BSIR = 13; 95a639b81f96c534c2f1066354b4a574c0dda2f713Jack He static final int DIALING_OUT_RESULT = 14; 96ff5993924ef627e8b723d33ccb5514cb15bb134dJack He static final int VOICE_RECOGNITION_RESULT = 15; 976b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M 980420b4fe3c7794139218821fab49f7f149d0075eJack He static final int STACK_EVENT = 101; 9969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private static final int CLCC_RSP_TIMEOUT = 104; 1006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie private static final int CONNECT_TIMEOUT = 201; 1026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 10367ccceab9600aaeec6dc34658c45c074de39aa38Jack He private static final int CLCC_RSP_TIMEOUT_MS = 5000; 104122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // NOTE: the value is not "final" - it is modified in the unit tests 10567ccceab9600aaeec6dc34658c45c074de39aa38Jack He @VisibleForTesting static int sConnectTimeoutMs = 30000; 106122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 107448309eada01c130b2fee8977f7fd74875978cbcJack He private static final HeadsetAgIndicatorEnableState DEFAULT_AG_INDICATOR_ENABLE_STATE = 108448309eada01c130b2fee8977f7fd74875978cbcJack He new HeadsetAgIndicatorEnableState(true, true, true, true); 109448309eada01c130b2fee8977f7fd74875978cbcJack He 11067ccceab9600aaeec6dc34658c45c074de39aa38Jack He private final BluetoothDevice mDevice; 111122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 112122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // State machine states 113122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final Disconnected mDisconnected = new Disconnected(); 114122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final Connecting mConnecting = new Connecting(); 115122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final Disconnecting mDisconnecting = new Disconnecting(); 116122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final Connected mConnected = new Connected(); 117122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final AudioOn mAudioOn = new AudioOn(); 118122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final AudioConnecting mAudioConnecting = new AudioConnecting(); 119122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private final AudioDisconnecting mAudioDisconnecting = new AudioDisconnecting(); 120122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private HeadsetStateBase mPrevState; 121122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 122122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Run time dependencies 123caa5d6ab09bf61f4379413299ae1ab436c503710Jack He private final HeadsetService mHeadsetService; 124caa5d6ab09bf61f4379413299ae1ab436c503710Jack He private final AdapterService mAdapterService; 12550b51beb3bd0885ced514d1bcfda3050f60833ffJack He private final HeadsetNativeInterface mNativeInterface; 12650b51beb3bd0885ced514d1bcfda3050f60833ffJack He private final HeadsetSystemInterface mSystemInterface; 1276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 128122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Runtime states 12950b51beb3bd0885ced514d1bcfda3050f60833ffJack He private int mSpeakerVolume; 13050b51beb3bd0885ced514d1bcfda3050f60833ffJack He private int mMicVolume; 131448309eada01c130b2fee8977f7fd74875978cbcJack He private HeadsetAgIndicatorEnableState mAgIndicatorEnableState; 13267ccceab9600aaeec6dc34658c45c074de39aa38Jack He // The timestamp when the device entered connecting/connected state 13367ccceab9600aaeec6dc34658c45c074de39aa38Jack He private long mConnectingTimestampMs = Long.MIN_VALUE; 134122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Audio Parameters like NREC 13567ccceab9600aaeec6dc34658c45c074de39aa38Jack He private final HashMap<String, String> mAudioParams = new HashMap<>(); 13650b51beb3bd0885ced514d1bcfda3050f60833ffJack He // AT Phone book keeps a group of states used by AT+CPBR commands 13750b51beb3bd0885ced514d1bcfda3050f60833ffJack He private final AtPhonebook mPhonebook; 138a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // HSP specific 139a639b81f96c534c2f1066354b4a574c0dda2f713Jack He private boolean mNeedDialingOutReply; 140122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 141122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Keys are AT commands, and values are the company IDs. 142122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID; 1436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie static { 145122e077f24750ee0e7fd650cbfa832edeb216d07Jack He VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID = new HashMap<>(); 1468536d97c0196cdbf1ee288ffe4edc377f3833019Jack He VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put( 1478536d97c0196cdbf1ee288ffe4edc377f3833019Jack He BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT, 1488536d97c0196cdbf1ee288ffe4edc377f3833019Jack He BluetoothAssignedNumbers.PLANTRONICS); 1498536d97c0196cdbf1ee288ffe4edc377f3833019Jack He VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put( 1508536d97c0196cdbf1ee288ffe4edc377f3833019Jack He BluetoothHeadset.VENDOR_RESULT_CODE_COMMAND_ANDROID, 1518536d97c0196cdbf1ee288ffe4edc377f3833019Jack He BluetoothAssignedNumbers.GOOGLE); 152f27d360b7ec35eaddee66cac173c51c18c238b03Jack He VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put( 153f27d360b7ec35eaddee66cac173c51c18c238b03Jack He BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XAPL, 154f27d360b7ec35eaddee66cac173c51c18c238b03Jack He BluetoothAssignedNumbers.APPLE); 155f27d360b7ec35eaddee66cac173c51c18c238b03Jack He VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put( 156f27d360b7ec35eaddee66cac173c51c18c238b03Jack He BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV, 157f27d360b7ec35eaddee66cac173c51c18c238b03Jack He BluetoothAssignedNumbers.APPLE); 1586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 160caa5d6ab09bf61f4379413299ae1ab436c503710Jack He private HeadsetStateMachine(BluetoothDevice device, Looper looper, 161caa5d6ab09bf61f4379413299ae1ab436c503710Jack He HeadsetService headsetService, AdapterService adapterService, 16250b51beb3bd0885ced514d1bcfda3050f60833ffJack He HeadsetNativeInterface nativeInterface, HeadsetSystemInterface systemInterface) { 16367ccceab9600aaeec6dc34658c45c074de39aa38Jack He super(TAG, Objects.requireNonNull(looper, "looper cannot be null")); 164122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Enable/Disable StateMachine debug logs 165122e077f24750ee0e7fd650cbfa832edeb216d07Jack He setDbg(DBG); 16667ccceab9600aaeec6dc34658c45c074de39aa38Jack He mDevice = Objects.requireNonNull(device, "device cannot be null"); 167caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService = Objects.requireNonNull(headsetService, "headsetService cannot be null"); 16867ccceab9600aaeec6dc34658c45c074de39aa38Jack He mNativeInterface = 16967ccceab9600aaeec6dc34658c45c074de39aa38Jack He Objects.requireNonNull(nativeInterface, "nativeInterface cannot be null"); 17067ccceab9600aaeec6dc34658c45c074de39aa38Jack He mSystemInterface = 17167ccceab9600aaeec6dc34658c45c074de39aa38Jack He Objects.requireNonNull(systemInterface, "systemInterface cannot be null"); 172caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mAdapterService = Objects.requireNonNull(adapterService, "AdapterService cannot be null"); 17367ccceab9600aaeec6dc34658c45c074de39aa38Jack He // Create phonebook helper 174caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mPhonebook = new AtPhonebook(mHeadsetService, mNativeInterface); 175122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Initialize state machine 1766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie addState(mDisconnected); 177122e077f24750ee0e7fd650cbfa832edeb216d07Jack He addState(mConnecting); 178122e077f24750ee0e7fd650cbfa832edeb216d07Jack He addState(mDisconnecting); 1796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie addState(mConnected); 1806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie addState(mAudioOn); 181122e077f24750ee0e7fd650cbfa832edeb216d07Jack He addState(mAudioConnecting); 182122e077f24750ee0e7fd650cbfa832edeb216d07Jack He addState(mAudioDisconnecting); 1836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie setInitialState(mDisconnected); 1846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 186caa5d6ab09bf61f4379413299ae1ab436c503710Jack He static HeadsetStateMachine make(BluetoothDevice device, Looper looper, 187caa5d6ab09bf61f4379413299ae1ab436c503710Jack He HeadsetService headsetService, AdapterService adapterService, 18850b51beb3bd0885ced514d1bcfda3050f60833ffJack He HeadsetNativeInterface nativeInterface, HeadsetSystemInterface systemInterface) { 1890420b4fe3c7794139218821fab49f7f149d0075eJack He HeadsetStateMachine stateMachine = 190caa5d6ab09bf61f4379413299ae1ab436c503710Jack He new HeadsetStateMachine(device, looper, headsetService, adapterService, 191caa5d6ab09bf61f4379413299ae1ab436c503710Jack He nativeInterface, systemInterface); 1920420b4fe3c7794139218821fab49f7f149d0075eJack He stateMachine.start(); 193caa5d6ab09bf61f4379413299ae1ab436c503710Jack He Log.i(TAG, "Created state machine " + stateMachine + " for " + device); 1940420b4fe3c7794139218821fab49f7f149d0075eJack He return stateMachine; 1950420b4fe3c7794139218821fab49f7f149d0075eJack He } 1960420b4fe3c7794139218821fab49f7f149d0075eJack He 1970420b4fe3c7794139218821fab49f7f149d0075eJack He static void destroy(HeadsetStateMachine stateMachine) { 1980420b4fe3c7794139218821fab49f7f149d0075eJack He Log.i(TAG, "destroy"); 1990420b4fe3c7794139218821fab49f7f149d0075eJack He if (stateMachine == null) { 2000420b4fe3c7794139218821fab49f7f149d0075eJack He Log.w(TAG, "destroy(), stateMachine is null"); 2010420b4fe3c7794139218821fab49f7f149d0075eJack He return; 2020420b4fe3c7794139218821fab49f7f149d0075eJack He } 203122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateMachine.quitNow(); 2040420b4fe3c7794139218821fab49f7f149d0075eJack He stateMachine.cleanup(); 2056893668d1ccf0cc6361ef31ace52fedc2e37e35aWink Saville } 2066893668d1ccf0cc6361ef31ace52fedc2e37e35aWink Saville 2076654f5c903de510a70f9e72cd5ad7837b615d93ffredc public void cleanup() { 20874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mPhonebook != null) { 20974ae04c73312403e89db0f8e9bd9601d403b4783fredc mPhonebook.cleanup(); 21074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 211122e077f24750ee0e7fd650cbfa832edeb216d07Jack He mAudioParams.clear(); 2126654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 2136654f5c903de510a70f9e72cd5ad7837b615d93ffredc 214838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood public void dump(StringBuilder sb) { 21567ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mCurrentDevice: " + mDevice); 21667ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mCurrentState: " + getCurrentState()); 21767ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mPrevState: " + mPrevState); 21867ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mConnectionState: " + getConnectionState()); 21967ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mAudioState: " + getAudioState()); 220a639b81f96c534c2f1066354b4a574c0dda2f713Jack He ProfileService.println(sb, " mNeedDialingOutReply: " + mNeedDialingOutReply); 22167ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mSpeakerVolume: " + mSpeakerVolume); 22267ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " mMicVolume: " + mMicVolume); 22367ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, 22467ccceab9600aaeec6dc34658c45c074de39aa38Jack He " mConnectingTimestampMs(uptimeMillis): " + mConnectingTimestampMs); 22567ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " StateMachine: " + this); 226122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Dump the state machine logs 227122e077f24750ee0e7fd650cbfa832edeb216d07Jack He StringWriter stringWriter = new StringWriter(); 228122e077f24750ee0e7fd650cbfa832edeb216d07Jack He PrintWriter printWriter = new PrintWriter(stringWriter); 229122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.dump(new FileDescriptor(), printWriter, new String[]{}); 230122e077f24750ee0e7fd650cbfa832edeb216d07Jack He printWriter.flush(); 231122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stringWriter.flush(); 23267ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " StateMachineLog:"); 23367ccceab9600aaeec6dc34658c45c074de39aa38Jack He Scanner scanner = new Scanner(stringWriter.toString()); 23467ccceab9600aaeec6dc34658c45c074de39aa38Jack He while (scanner.hasNextLine()) { 23567ccceab9600aaeec6dc34658c45c074de39aa38Jack He String line = scanner.nextLine(); 23667ccceab9600aaeec6dc34658c45c074de39aa38Jack He ProfileService.println(sb, " " + line); 23767ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 23867ccceab9600aaeec6dc34658c45c074de39aa38Jack He scanner.close(); 239838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 240838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 241122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 242122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Base class for states used in this state machine to share common infrastructures 243122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 244122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private abstract class HeadsetStateBase extends State { 245122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 246122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void enter() { 247122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Crash if mPrevState is null and state is not Disconnected 248122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (!(this instanceof Disconnected) && mPrevState == null) { 249122e077f24750ee0e7fd650cbfa832edeb216d07Jack He throw new IllegalStateException("mPrevState is null on enter()"); 250122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 251122e077f24750ee0e7fd650cbfa832edeb216d07Jack He enforceValidConnectionStateTransition(); 252122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 253122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 254122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 255122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void exit() { 256122e077f24750ee0e7fd650cbfa832edeb216d07Jack He mPrevState = this; 257122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 258122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 259122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 260122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public String toString() { 261122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return getName(); 262122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 263122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 264122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 265122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Broadcast audio and connection state changes to the system. This should be called at the 266122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * end of enter() method after all the setup is done 267122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 268122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void broadcastStateTransitions() { 26967ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (mPrevState == null) { 270122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return; 271122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 272122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: Add STATE_AUDIO_DISCONNECTING constant to get rid of the 2nd part of this logic 273122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (getAudioStateInt() != mPrevState.getAudioStateInt() || ( 274122e077f24750ee0e7fd650cbfa832edeb216d07Jack He mPrevState instanceof AudioDisconnecting && this instanceof AudioOn)) { 27567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("audio state changed: " + mDevice + ": " + mPrevState + " -> " + this); 27667ccceab9600aaeec6dc34658c45c074de39aa38Jack He broadcastAudioState(mDevice, mPrevState.getAudioStateInt(), getAudioStateInt()); 277122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 278122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (getConnectionStateInt() != mPrevState.getConnectionStateInt()) { 27967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD( 28067ccceab9600aaeec6dc34658c45c074de39aa38Jack He "connection state changed: " + mDevice + ": " + mPrevState + " -> " + this); 28167ccceab9600aaeec6dc34658c45c074de39aa38Jack He broadcastConnectionState(mDevice, mPrevState.getConnectionStateInt(), 282122e077f24750ee0e7fd650cbfa832edeb216d07Jack He getConnectionStateInt()); 283122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 284122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 285122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 286122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Should not be called from enter() method 287122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void broadcastConnectionState(BluetoothDevice device, int fromState, int toState) { 288122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("broadcastConnectionState " + device + ": " + fromState + "->" + toState); 289caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.onConnectionStateChangedFromStateMachine(device, fromState, toState); 290122e077f24750ee0e7fd650cbfa832edeb216d07Jack He Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 291122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState); 292122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothProfile.EXTRA_STATE, toState); 293122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 294122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 295caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.sendBroadcastAsUser(intent, UserHandle.ALL, 296caa5d6ab09bf61f4379413299ae1ab436c503710Jack He HeadsetService.BLUETOOTH_PERM); 297122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 298122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 299122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Should not be called from enter() method 300122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void broadcastAudioState(BluetoothDevice device, int fromState, int toState) { 301122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("broadcastAudioState: " + device + ": " + fromState + "->" + toState); 302caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.onAudioStateChangedFromStateMachine(device, fromState, toState); 303122e077f24750ee0e7fd650cbfa832edeb216d07Jack He Intent intent = new Intent(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 304122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState); 305122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothProfile.EXTRA_STATE, toState); 306122e077f24750ee0e7fd650cbfa832edeb216d07Jack He intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 307caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.sendBroadcastAsUser(intent, UserHandle.ALL, 308caa5d6ab09bf61f4379413299ae1ab436c503710Jack He HeadsetService.BLUETOOTH_PERM); 309122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 310122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 311122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 312122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Verify if the current state transition is legal. This is supposed to be called from 313122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * enter() method and crash if the state transition is out of the specification 314122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 315122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Note: 316122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * This method uses state objects to verify transition because these objects should be final 317122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * and any other instances are invalid 318122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 319122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void enforceValidConnectionStateTransition() { 320122e077f24750ee0e7fd650cbfa832edeb216d07Jack He boolean result = false; 321122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (this == mDisconnected) { 322122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == null || mPrevState == mConnecting 323122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mDisconnecting 324122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: edges to be removed after native stack refactoring 325122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // all transitions to disconnected state should go through a pending state 326122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // also, states should not go directly from an active audio state to 327122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // disconnected state 328122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mConnected || mPrevState == mAudioOn 329122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mAudioConnecting || mPrevState == mAudioDisconnecting; 330122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mConnecting) { 331122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mDisconnected; 332122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mDisconnecting) { 333122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mConnected 334122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: edges to be removed after native stack refactoring 335122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // all transitions to disconnecting state should go through connected state 336122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mAudioConnecting || mPrevState == mAudioOn 337122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mAudioDisconnecting; 338122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mConnected) { 339122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mConnecting || mPrevState == mAudioDisconnecting 340122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mDisconnecting || mPrevState == mAudioConnecting 341122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: edges to be removed after native stack refactoring 342122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // all transitions to connected state should go through a pending state 343122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mAudioOn || mPrevState == mDisconnected; 344122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mAudioConnecting) { 345122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mConnected; 346122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mAudioDisconnecting) { 347122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mAudioOn; 348122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } else if (this == mAudioOn) { 349122e077f24750ee0e7fd650cbfa832edeb216d07Jack He result = mPrevState == mAudioConnecting || mPrevState == mAudioDisconnecting 350122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: edges to be removed after native stack refactoring 351122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // all transitions to audio connected state should go through a pending 352122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // state 353122e077f24750ee0e7fd650cbfa832edeb216d07Jack He || mPrevState == mConnected; 354122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 355122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (!result) { 356122e077f24750ee0e7fd650cbfa832edeb216d07Jack He throw new IllegalStateException( 357122e077f24750ee0e7fd650cbfa832edeb216d07Jack He "Invalid state transition from " + mPrevState + " to " + this 35867ccceab9600aaeec6dc34658c45c074de39aa38Jack He + " for device " + mDevice); 359122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 360122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 361122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 362122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogD(String msg) { 36367ccceab9600aaeec6dc34658c45c074de39aa38Jack He log(getName() + ": currentDevice=" + mDevice + ", msg=" + msg); 364122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 365122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 366122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogW(String msg) { 36767ccceab9600aaeec6dc34658c45c074de39aa38Jack He logw(getName() + ": currentDevice=" + mDevice + ", msg=" + msg); 368122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 369122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 370122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogE(String msg) { 37167ccceab9600aaeec6dc34658c45c074de39aa38Jack He loge(getName() + ": currentDevice=" + mDevice + ", msg=" + msg); 372122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 373122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 374122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogV(String msg) { 37567ccceab9600aaeec6dc34658c45c074de39aa38Jack He logv(getName() + ": currentDevice=" + mDevice + ", msg=" + msg); 376122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 377122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 378122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogI(String msg) { 37967ccceab9600aaeec6dc34658c45c074de39aa38Jack He logi(getName() + ": currentDevice=" + mDevice + ", msg=" + msg); 380122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 381122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 382122e077f24750ee0e7fd650cbfa832edeb216d07Jack He void stateLogWtfStack(String msg) { 383122e077f24750ee0e7fd650cbfa832edeb216d07Jack He Log.wtfStack(TAG, getName() + ": " + msg); 384122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 385122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 386122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 387122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Process connection event 388122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 389122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @param message the current message for the event 390122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @param state connection state to transition to 391122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 39267ccceab9600aaeec6dc34658c45c074de39aa38Jack He public abstract void processConnectionEvent(Message message, int state); 393122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 394122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 395122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Get a state value from {@link BluetoothProfile} that represents the connection state of 396122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * this headset state 397122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 398122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @return a value in {@link BluetoothProfile#STATE_DISCONNECTED}, 399122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or 400122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * {@link BluetoothProfile#STATE_DISCONNECTING} 401122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 402122e077f24750ee0e7fd650cbfa832edeb216d07Jack He abstract int getConnectionStateInt(); 403122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 404122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 405122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Get an audio state value from {@link BluetoothHeadset} 406122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @return a value in {@link BluetoothHeadset#STATE_AUDIO_DISCONNECTED}, 407122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * {@link BluetoothHeadset#STATE_AUDIO_CONNECTING}, or 408122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * {@link BluetoothHeadset#STATE_AUDIO_CONNECTED} 409122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 410122e077f24750ee0e7fd650cbfa832edeb216d07Jack He abstract int getAudioStateInt(); 411122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 412122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 413122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 414122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class Disconnected extends HeadsetStateBase { 415122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 416122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getConnectionStateInt() { 417122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothProfile.STATE_DISCONNECTED; 418122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 419122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 420122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 421122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 422122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 423122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 424122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 4256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 4266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void enter() { 427122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 42867ccceab9600aaeec6dc34658c45c074de39aa38Jack He mConnectingTimestampMs = Long.MIN_VALUE; 429405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T mPhonebook.resetAtState(); 430448309eada01c130b2fee8977f7fd74875978cbcJack He updateAgIndicatorEnableState(null); 431a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNeedDialingOutReply = false; 432122e077f24750ee0e7fd650cbfa832edeb216d07Jack He mAudioParams.clear(); 433122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 434caa5d6ab09bf61f4379413299ae1ab436c503710Jack He // Remove the state machine for unbonded devices 435caa5d6ab09bf61f4379413299ae1ab436c503710Jack He if (mPrevState != null 436caa5d6ab09bf61f4379413299ae1ab436c503710Jack He && mAdapterService.getBondState(mDevice) == BluetoothDevice.BOND_NONE) { 437caa5d6ab09bf61f4379413299ae1ab436c503710Jack He getHandler().post(() -> mHeadsetService.removeStateMachine(mDevice)); 438caa5d6ab09bf61f4379413299ae1ab436c503710Jack He } 4396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 4406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 4416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 4426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean processMessage(Message message) { 4433659dee2b21c7f269a2bef051483093fe07e5682Jack He switch (message.what) { 4446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case CONNECT: 4456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie BluetoothDevice device = (BluetoothDevice) message.obj; 446122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("Connecting to " + device); 44767ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 44867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE( 44967ccceab9600aaeec6dc34658c45c074de39aa38Jack He "CONNECT failed, device=" + device + ", currentDevice=" + mDevice); 45067ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 45167ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 4520420b4fe3c7794139218821fab49f7f149d0075eJack He if (!mNativeInterface.connectHfp(device)) { 45367ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("CONNECT failed for connectHfp(" + device + ")"); 454122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // No state transition is involved, fire broadcast immediately 4556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 456122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothProfile.STATE_DISCONNECTED); 4576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 459122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnecting); 4606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case DISCONNECT: 4626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie // ignore 4636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case CALL_STATE_CHANGED: 46567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("Ignoring CALL_STATE_CHANGED event"); 4666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 46739af3989003fd06fb3da55904ee074f706e1d448Jack He case DEVICE_STATE_CHANGED: 468122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("Ignoring DEVICE_STATE_CHANGED event"); 46939af3989003fd06fb3da55904ee074f706e1d448Jack He break; 4706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case STACK_EVENT: 4710420b4fe3c7794139218821fab49f7f149d0075eJack He HeadsetStackEvent event = (HeadsetStackEvent) message.obj; 472122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("STACK_EVENT: " + event); 47367ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(event.device)) { 47467ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Event device does not match currentDevice[" + mDevice 47567ccceab9600aaeec6dc34658c45c074de39aa38Jack He + "], event: " + event); 47667ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 47767ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 4786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (event.type) { 4790420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: 48067ccceab9600aaeec6dc34658c45c074de39aa38Jack He processConnectionEvent(message, event.valueInt); 4816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 483122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected stack event: " + event); 4846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 4866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 4876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 488122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected msg " + getMessageName(message.what) + ": " + message); 4896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return NOT_HANDLED; 4906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 491c6231925ec13a432770a879c49b3c4f008ee96e1Jack He return HANDLED; 4926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 4936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 494122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 49567ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processConnectionEvent(Message message, int state) { 49667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processConnectionEvent, state=" + state); 4976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (state) { 4983659dee2b21c7f269a2bef051483093fe07e5682Jack He case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED: 49967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("ignore DISCONNECTED event"); 5003659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 501122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Both events result in Connecting state as SLC establishment is still required 50239af3989003fd06fb3da55904ee074f706e1d448Jack He case HeadsetHalConstants.CONNECTION_STATE_CONNECTED: 5033659dee2b21c7f269a2bef051483093fe07e5682Jack He case HeadsetHalConstants.CONNECTION_STATE_CONNECTING: 504caa5d6ab09bf61f4379413299ae1ab436c503710Jack He if (mHeadsetService.okToAcceptConnection(mDevice)) { 50567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("accept incoming connection"); 506122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnecting); 5073659dee2b21c7f269a2bef051483093fe07e5682Jack He } else { 508caa5d6ab09bf61f4379413299ae1ab436c503710Jack He stateLogI("rejected incoming HF, priority=" + mHeadsetService.getPriority( 509caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mDevice) + " bondState=" + mAdapterService.getBondState(mDevice)); 510122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Reject the connection and stay in Disconnected state itself 51167ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mNativeInterface.disconnectHfp(mDevice)) { 51267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("failed to disconnect"); 513122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 514122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Indicate rejection to other components. 51567ccceab9600aaeec6dc34658c45c074de39aa38Jack He broadcastConnectionState(mDevice, BluetoothProfile.STATE_DISCONNECTED, 516bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He BluetoothProfile.STATE_DISCONNECTED); 51775e9fd59f4d4011ba7155732a41b06f0df40badaSwaminatha Balaji } 5183659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 5193659dee2b21c7f269a2bef051483093fe07e5682Jack He case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING: 52067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("Ignore DISCONNECTING event"); 5213659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 5223659dee2b21c7f269a2bef051483093fe07e5682Jack He default: 523122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Incorrect state: " + state); 5243659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 5256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 5266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 5276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 5286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 52939af3989003fd06fb3da55904ee074f706e1d448Jack He // Per HFP 1.7.1 spec page 23/144, Pending state needs to handle 53039af3989003fd06fb3da55904ee074f706e1d448Jack He // AT+BRSF, AT+CIND, AT+CMER, AT+BIND, +CHLD 53139af3989003fd06fb3da55904ee074f706e1d448Jack He // commands during SLC establishment 532122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class Connecting extends HeadsetStateBase { 533122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 534122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getConnectionStateInt() { 535122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothProfile.STATE_CONNECTING; 536122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 537122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 538122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 539122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 540122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 541122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 542122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 5436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 5446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void enter() { 545122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 54667ccceab9600aaeec6dc34658c45c074de39aa38Jack He mConnectingTimestampMs = SystemClock.uptimeMillis(); 54767ccceab9600aaeec6dc34658c45c074de39aa38Jack He sendMessageDelayed(CONNECT_TIMEOUT, mDevice, sConnectTimeoutMs); 548122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 5496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 5506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 5516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 5526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean processMessage(Message message) { 5533659dee2b21c7f269a2bef051483093fe07e5682Jack He switch (message.what) { 5546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case CONNECT: 555345d21b0575a4b866bfc9ccfde9c654e7b859ac6Matthew Xie case CONNECT_AUDIO: 556122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 5576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie deferMessage(message); 5586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 55967ccceab9600aaeec6dc34658c45c074de39aa38Jack He case CONNECT_TIMEOUT: { 560122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // We timed out trying to connect, transition to Disconnected state 56167ccceab9600aaeec6dc34658c45c074de39aa38Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 56267ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 56367ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Unknown device timeout " + device); 56467ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 56567ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 56667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("CONNECT_TIMEOUT"); 567122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnected); 5686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 56967ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 5706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case CALL_STATE_CHANGED: 57167ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("ignoring CALL_STATE_CHANGED event"); 5726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 57339af3989003fd06fb3da55904ee074f706e1d448Jack He case DEVICE_STATE_CHANGED: 574122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("ignoring DEVICE_STATE_CHANGED event"); 57539af3989003fd06fb3da55904ee074f706e1d448Jack He break; 5766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case STACK_EVENT: 5770420b4fe3c7794139218821fab49f7f149d0075eJack He HeadsetStackEvent event = (HeadsetStackEvent) message.obj; 578122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("STACK_EVENT: " + event); 57967ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(event.device)) { 58067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Event device does not match currentDevice[" + mDevice 58167ccceab9600aaeec6dc34658c45c074de39aa38Jack He + "], event: " + event); 58267ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 58367ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 5846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (event.type) { 5850420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: 58667ccceab9600aaeec6dc34658c45c074de39aa38Jack He processConnectionEvent(message, event.valueInt); 5876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 5880420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CHLD: 58939af3989003fd06fb3da55904ee074f706e1d448Jack He processAtChld(event.valueInt, event.device); 59039af3989003fd06fb3da55904ee074f706e1d448Jack He break; 5910420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CIND: 59239af3989003fd06fb3da55904ee074f706e1d448Jack He processAtCind(event.device); 59339af3989003fd06fb3da55904ee074f706e1d448Jack He break; 5940420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_WBS: 595122e077f24750ee0e7fd650cbfa832edeb216d07Jack He processWBSEvent(event.valueInt); 59639af3989003fd06fb3da55904ee074f706e1d448Jack He break; 5970420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_BIND: 5982ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth processAtBind(event.valueString, event.device); 5992ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 600bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He // Unexpected AT commands, we only handle them for comparability reasons 6010420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED: 602122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected VR event, device=" + event.device + ", state=" 603122e077f24750ee0e7fd650cbfa832edeb216d07Jack He + event.valueInt); 604ff5993924ef627e8b723d33ccb5514cb15bb134dJack He processVrEvent(event.valueInt); 605bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6060420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_DIAL_CALL: 607122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected dial event, device=" + event.device); 608a639b81f96c534c2f1066354b4a574c0dda2f713Jack He processDialCall(event.valueString); 609bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6100420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_SUBSCRIBER_NUMBER_REQUEST: 611122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected subscriber number event for" + event.device 612122e077f24750ee0e7fd650cbfa832edeb216d07Jack He + ", state=" + event.valueInt); 613bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processSubscriberNumberRequest(event.device); 614bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6150420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_COPS: 616122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected COPS event for " + event.device); 617bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processAtCops(event.device); 618bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6190420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CLCC: 620122e077f24750ee0e7fd650cbfa832edeb216d07Jack He Log.w(TAG, "Connecting: Unexpected CLCC event for" + event.device); 621bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processAtClcc(event.device); 622bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6230420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_UNKNOWN_AT: 624122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected unknown AT event for" + event.device + ", cmd=" 625122e077f24750ee0e7fd650cbfa832edeb216d07Jack He + event.valueString); 626bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processUnknownAt(event.valueString, event.device); 627bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6280420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED: 629122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected key-press event for " + event.device); 630bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processKeyPressed(event.device); 631bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6320420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_BIEV: 633122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected BIEV event for " + event.device + ", indId=" 634122e077f24750ee0e7fd650cbfa832edeb216d07Jack He + event.valueInt + ", indVal=" + event.valueInt2); 635bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He processAtBiev(event.valueInt, event.valueInt2, event.device); 636bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6370420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_VOLUME_CHANGED: 638122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected volume event for " + event.device); 63967ccceab9600aaeec6dc34658c45c074de39aa38Jack He processVolumeEvent(event.valueInt, event.valueInt2); 640bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6410420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_ANSWER_CALL: 642122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected answer event for " + event.device); 64350b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSystemInterface.answerCall(event.device); 644bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6450420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_HANGUP_CALL: 646122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("Unexpected hangup event for " + event.device); 647a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mSystemInterface.hangupCall(event.device); 648bc67ac7b9ef7a6b33fc550257b75726d86641923Jack He break; 6496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 650122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected event: " + event); 6516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 6526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 6536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 6546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 655122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected msg " + getMessageName(message.what) + ": " + message); 6566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return NOT_HANDLED; 6576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 658c6231925ec13a432770a879c49b3c4f008ee96e1Jack He return HANDLED; 6596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 6606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 661122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 66267ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processConnectionEvent(Message message, int state) { 66367ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processConnectionEvent, state=" + state); 6646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (state) { 6656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED: 66667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("Disconnected"); 667122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnected); 6686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 66969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.CONNECTION_STATE_CONNECTED: 67067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("RFCOMM connected"); 67139af3989003fd06fb3da55904ee074f706e1d448Jack He break; 67239af3989003fd06fb3da55904ee074f706e1d448Jack He case HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED: 67367ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("SLC connected"); 674122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 67569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 67669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.CONNECTION_STATE_CONNECTING: 677122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Ignored 67869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 67969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING: 68067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("Disconnecting"); 68169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 68269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava default: 683122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Incorrect state " + state); 68469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 6856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 6866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 6876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 688122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 689122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void exit() { 690122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeMessages(CONNECT_TIMEOUT); 691122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.exit(); 69269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 6936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 6946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 695122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class Disconnecting extends HeadsetStateBase { 696122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 697122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getConnectionStateInt() { 698122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothProfile.STATE_DISCONNECTING; 699122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 700122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 701122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 702122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 703122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 704122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 705122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 7066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 7076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void enter() { 708122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 70967ccceab9600aaeec6dc34658c45c074de39aa38Jack He sendMessageDelayed(CONNECT_TIMEOUT, mDevice, sConnectTimeoutMs); 710122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 7116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 7126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 7136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 7146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean processMessage(Message message) { 7153659dee2b21c7f269a2bef051483093fe07e5682Jack He switch (message.what) { 716122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: 717122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 718122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 719122e077f24750ee0e7fd650cbfa832edeb216d07Jack He deferMessage(message); 720122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 72167ccceab9600aaeec6dc34658c45c074de39aa38Jack He case CONNECT_TIMEOUT: { 72267ccceab9600aaeec6dc34658c45c074de39aa38Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 72367ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 72467ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Unknown device timeout " + device); 72567ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 72667ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 727122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("timeout"); 728122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnected); 729122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 73067ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 731122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case STACK_EVENT: 732122e077f24750ee0e7fd650cbfa832edeb216d07Jack He HeadsetStackEvent event = (HeadsetStackEvent) message.obj; 733122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("STACK_EVENT: " + event); 73467ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(event.device)) { 73567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Event device does not match currentDevice[" + mDevice 73667ccceab9600aaeec6dc34658c45c074de39aa38Jack He + "], event: " + event); 73767ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 73867ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 739122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (event.type) { 740122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: 74167ccceab9600aaeec6dc34658c45c074de39aa38Jack He processConnectionEvent(message, event.valueInt); 7423659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 743122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 744122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected event: " + event); 7453659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 74669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 747122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 748122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 749122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected msg " + getMessageName(message.what) + ": " + message); 750122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return NOT_HANDLED; 751122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 752122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return HANDLED; 753122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 754122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 755122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // in Disconnecting state 756122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 75767ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processConnectionEvent(Message message, int state) { 758122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (state) { 759122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED: 76067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processConnectionEvent: Disconnected"); 761122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnected); 762122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 763122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED: 76467ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processConnectionEvent: Connected"); 765122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 766122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 767122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 76867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processConnectionEvent: Bad state: " + state); 769122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 770122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 771122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 772122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 773122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 774122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void exit() { 775122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeMessages(CONNECT_TIMEOUT); 776122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.exit(); 777122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 778122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 779122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 780122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 781122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Base class for Connected, AudioConnecting, AudioOn, AudioDisconnecting states 782122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 783122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private abstract class ConnectedBase extends HeadsetStateBase { 784122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 785122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getConnectionStateInt() { 786122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothProfile.STATE_CONNECTED; 787122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 788122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 789122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 790122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Handle common messages in connected states. However, state specific messages must be 791122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * handled individually. 792122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 793122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @param message Incoming message to handle 794122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @return True if handled successfully, False otherwise 795122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 796122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 797122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public boolean processMessage(Message message) { 798122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (message.what) { 799122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: 800122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 801122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 802122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT_AUDIO: 803122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_TIMEOUT: 80467ccceab9600aaeec6dc34658c45c074de39aa38Jack He throw new IllegalStateException( 80567ccceab9600aaeec6dc34658c45c074de39aa38Jack He "Illegal message in generic handler: " + message); 80667ccceab9600aaeec6dc34658c45c074de39aa38Jack He case VOICE_RECOGNITION_START: { 80767ccceab9600aaeec6dc34658c45c074de39aa38Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 80867ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 80967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("VOICE_RECOGNITION_START failed " + device 81067ccceab9600aaeec6dc34658c45c074de39aa38Jack He + " is not currentDevice"); 81167ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 81267ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 813ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (!mNativeInterface.startVoiceRecognition(mDevice)) { 814ff5993924ef627e8b723d33ccb5514cb15bb134dJack He stateLogW("Failed to start voice recognition"); 815ff5993924ef627e8b723d33ccb5514cb15bb134dJack He break; 816ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 817b18d6a7da48a6847df88abadd42fbb51316cb76dRavi Nagarajan break; 81867ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 81967ccceab9600aaeec6dc34658c45c074de39aa38Jack He case VOICE_RECOGNITION_STOP: { 82067ccceab9600aaeec6dc34658c45c074de39aa38Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 82167ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 82267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("VOICE_RECOGNITION_STOP failed " + device 82367ccceab9600aaeec6dc34658c45c074de39aa38Jack He + " is not currentDevice"); 82467ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 82567ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 826ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (!mNativeInterface.stopVoiceRecognition(mDevice)) { 827ff5993924ef627e8b723d33ccb5514cb15bb134dJack He stateLogW("Failed to stop voice recognition"); 828ff5993924ef627e8b723d33ccb5514cb15bb134dJack He break; 829ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 8306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 83167ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 832a639b81f96c534c2f1066354b4a574c0dda2f713Jack He case CALL_STATE_CHANGED: { 833a639b81f96c534c2f1066354b4a574c0dda2f713Jack He HeadsetCallState callState = (HeadsetCallState) message.obj; 834a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (!mNativeInterface.phoneStateChange(mDevice, callState)) { 835a639b81f96c534c2f1066354b4a574c0dda2f713Jack He stateLogW("processCallState: failed to update call state " + callState); 836a639b81f96c534c2f1066354b4a574c0dda2f713Jack He break; 837a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 8386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 839a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 8406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case DEVICE_STATE_CHANGED: 84167ccceab9600aaeec6dc34658c45c074de39aa38Jack He mNativeInterface.notifyDeviceStatus(mDevice, (HeadsetDeviceState) message.obj); 8426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 8436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case SEND_CCLC_RESPONSE: 8446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie processSendClccResponse((HeadsetClccResponse) message.obj); 8456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 8463659dee2b21c7f269a2bef051483093fe07e5682Jack He case CLCC_RSP_TIMEOUT: { 84769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava BluetoothDevice device = (BluetoothDevice) message.obj; 84867ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 84967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("CLCC_RSP_TIMEOUT failed " + device + " is not currentDevice"); 85067ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 85167ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 8520420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.clccResponse(device, 0, 0, 0, 0, false, "", 0); 853c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 854c4fbd756e2645147470c486ae96f2253f5e13a52Jack He break; 855cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee case SEND_VENDOR_SPECIFIC_RESULT_CODE: 856cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee processSendVendorSpecificResultCode( 857cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee (HeadsetVendorSpecificResultCode) message.obj); 858cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee break; 85967ccceab9600aaeec6dc34658c45c074de39aa38Jack He case SEND_BSIR: 86067ccceab9600aaeec6dc34658c45c074de39aa38Jack He mNativeInterface.sendBsir(mDevice, message.arg1 == 1); 86167ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 862ff5993924ef627e8b723d33ccb5514cb15bb134dJack He case VOICE_RECOGNITION_RESULT: { 863ff5993924ef627e8b723d33ccb5514cb15bb134dJack He BluetoothDevice device = (BluetoothDevice) message.obj; 864ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (!mDevice.equals(device)) { 865ff5993924ef627e8b723d33ccb5514cb15bb134dJack He stateLogW("VOICE_RECOGNITION_RESULT failed " + device 866ff5993924ef627e8b723d33ccb5514cb15bb134dJack He + " is not currentDevice"); 867ff5993924ef627e8b723d33ccb5514cb15bb134dJack He break; 868ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 869ff5993924ef627e8b723d33ccb5514cb15bb134dJack He mNativeInterface.atResponseCode(mDevice, 870ff5993924ef627e8b723d33ccb5514cb15bb134dJack He message.arg1 == 1 ? HeadsetHalConstants.AT_RESPONSE_OK 871ff5993924ef627e8b723d33ccb5514cb15bb134dJack He : HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 872ff5993924ef627e8b723d33ccb5514cb15bb134dJack He break; 873ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 874a639b81f96c534c2f1066354b4a574c0dda2f713Jack He case DIALING_OUT_RESULT: { 87569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava BluetoothDevice device = (BluetoothDevice) message.obj; 87667ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 877ff5993924ef627e8b723d33ccb5514cb15bb134dJack He stateLogW("DIALING_OUT_RESULT failed " + device + " is not currentDevice"); 87867ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 87967ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 880a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (mNeedDialingOutReply) { 881a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNeedDialingOutReply = false; 882a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, 883a639b81f96c534c2f1066354b4a574c0dda2f713Jack He message.arg1 == 1 ? HeadsetHalConstants.AT_RESPONSE_OK 884a639b81f96c534c2f1066354b4a574c0dda2f713Jack He : HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 8856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 886c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 887c4fbd756e2645147470c486ae96f2253f5e13a52Jack He break; 88850b51beb3bd0885ced514d1bcfda3050f60833ffJack He case INTENT_CONNECTION_ACCESS_REPLY: 88950b51beb3bd0885ced514d1bcfda3050f60833ffJack He handleAccessPermissionResult((Intent) message.obj); 89050b51beb3bd0885ced514d1bcfda3050f60833ffJack He break; 8916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case STACK_EVENT: 8920420b4fe3c7794139218821fab49f7f149d0075eJack He HeadsetStackEvent event = (HeadsetStackEvent) message.obj; 893122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("STACK_EVENT: " + event); 89467ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(event.device)) { 89567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Event device does not match currentDevice[" + mDevice 89667ccceab9600aaeec6dc34658c45c074de39aa38Jack He + "], event: " + event); 89767ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 89867ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 8996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (event.type) { 9000420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED: 90167ccceab9600aaeec6dc34658c45c074de39aa38Jack He processConnectionEvent(message, event.valueInt); 9026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9030420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED: 90467ccceab9600aaeec6dc34658c45c074de39aa38Jack He processAudioEvent(event.valueInt); 9056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9060420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED: 907ff5993924ef627e8b723d33ccb5514cb15bb134dJack He processVrEvent(event.valueInt); 908b18d6a7da48a6847df88abadd42fbb51316cb76dRavi Nagarajan break; 9090420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_ANSWER_CALL: 91050b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSystemInterface.answerCall(event.device); 9116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9120420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_HANGUP_CALL: 913a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mSystemInterface.hangupCall(event.device); 9146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9150420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_VOLUME_CHANGED: 91667ccceab9600aaeec6dc34658c45c074de39aa38Jack He processVolumeEvent(event.valueInt, event.valueInt2); 9176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9180420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_DIAL_CALL: 919a639b81f96c534c2f1066354b4a574c0dda2f713Jack He processDialCall(event.valueString); 9206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9210420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_SEND_DTMF: 92250b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSystemInterface.sendDtmf(event.valueInt, event.device); 9236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9240420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_NOICE_REDUCTION: 92567ccceab9600aaeec6dc34658c45c074de39aa38Jack He processNoiseReductionEvent(event.valueInt == 1); 92668e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan break; 9270420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_WBS: 928122e077f24750ee0e7fd650cbfa832edeb216d07Jack He processWBSEvent(event.valueInt); 929b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie break; 9300420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CHLD: 93169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtChld(event.valueInt, event.device); 9326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9330420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_SUBSCRIBER_NUMBER_REQUEST: 93469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processSubscriberNumberRequest(event.device); 9356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9360420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CIND: 93769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtCind(event.device); 9386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9390420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_COPS: 94069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtCops(event.device); 9416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9420420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_AT_CLCC: 94369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtClcc(event.device); 9446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9450420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_UNKNOWN_AT: 94669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processUnknownAt(event.valueString, event.device); 9476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9480420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED: 94969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processKeyPressed(event.device); 9506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9510420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_BIND: 9522ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth processAtBind(event.valueString, event.device); 9532ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 9540420b4fe3c7794139218821fab49f7f149d0075eJack He case HeadsetStackEvent.EVENT_TYPE_BIEV: 9552ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth processAtBiev(event.valueInt, event.valueInt2, event.device); 9562ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 957448309eada01c130b2fee8977f7fd74875978cbcJack He case HeadsetStackEvent.EVENT_TYPE_BIA: 958448309eada01c130b2fee8977f7fd74875978cbcJack He updateAgIndicatorEnableState( 959448309eada01c130b2fee8977f7fd74875978cbcJack He (HeadsetAgIndicatorEnableState) event.valueObject); 960448309eada01c130b2fee8977f7fd74875978cbcJack He break; 9616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 962122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unknown stack event: " + event); 9636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 9656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 967122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("Unexpected msg " + getMessageName(message.what) + ": " + message); 9686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return NOT_HANDLED; 9696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 970c6231925ec13a432770a879c49b3c4f008ee96e1Jack He return HANDLED; 9716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 9726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 973122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 97467ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processConnectionEvent(Message message, int state) { 97567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processConnectionEvent, state=" + state); 9766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (state) { 977122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.CONNECTION_STATE_CONNECTED: 97867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processConnectionEvent: RFCOMM connected again, shouldn't happen"); 9796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 980bcbeaf69468424800a939b3e8678eaef21efa3d6Matthew Xie case HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED: 98167ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processConnectionEvent: SLC connected again, shouldn't happen"); 982122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 983122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING: 98467ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processConnectionEvent: Disconnecting"); 985122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnecting); 98669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 987122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED: 98867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processConnectionEvent: Disconnected"); 989122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnected); 9906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 99267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processConnectionEvent: bad state: " + state); 9936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 9946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 9956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 996bcbeaf69468424800a939b3e8678eaef21efa3d6Matthew Xie 997122e077f24750ee0e7fd650cbfa832edeb216d07Jack He /** 998122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * Each state should handle audio events differently 999122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 1000122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * @param state audio state 1001122e077f24750ee0e7fd650cbfa832edeb216d07Jack He */ 100267ccceab9600aaeec6dc34658c45c074de39aa38Jack He public abstract void processAudioEvent(int state); 10036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 10046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1005122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class Connected extends ConnectedBase { 1006122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1007122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 1008122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 1009122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1010122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 10116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 10126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void enter() { 1013122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 101467ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (mConnectingTimestampMs == Long.MIN_VALUE) { 101567ccceab9600aaeec6dc34658c45c074de39aa38Jack He mConnectingTimestampMs = SystemClock.uptimeMillis(); 101667ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 1017122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (mPrevState == mConnecting) { 10186743e015e076aa1a24f92d3be187f9af6d19b303Chienyuan // Reset AG indicator subscriptions, HF can set this later using AT+BIA command 10196743e015e076aa1a24f92d3be187f9af6d19b303Chienyuan updateAgIndicatorEnableState(DEFAULT_AG_INDICATOR_ENABLE_STATE); 102067ccceab9600aaeec6dc34658c45c074de39aa38Jack He // Reset NREC on connect event. Headset will override later 102167ccceab9600aaeec6dc34658c45c074de39aa38Jack He processNoiseReductionEvent(true); 102267ccceab9600aaeec6dc34658c45c074de39aa38Jack He // Query phone state for initial setup 102367ccceab9600aaeec6dc34658c45c074de39aa38Jack He mSystemInterface.queryPhoneState(); 1024122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Remove pending connection attempts that were deferred during the pending 1025122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // state. This is to prevent auto connect attempts from disconnecting 1026122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // devices that previously successfully connected. 1027122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeDeferredMessages(CONNECT); 1028122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1029122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 10306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 10316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 10326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 10336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean processMessage(Message message) { 10343659dee2b21c7f269a2bef051483093fe07e5682Jack He switch (message.what) { 10353659dee2b21c7f269a2bef051483093fe07e5682Jack He case CONNECT: { 1036345d21b0575a4b866bfc9ccfde9c654e7b859ac6Matthew Xie BluetoothDevice device = (BluetoothDevice) message.obj; 103767ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("CONNECT, ignored, device=" + device + ", currentDevice" + mDevice); 103867ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 1039c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 10403659dee2b21c7f269a2bef051483093fe07e5682Jack He case DISCONNECT: { 10413659dee2b21c7f269a2bef051483093fe07e5682Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 1042122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("DISCONNECT from device=" + device); 104367ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 1044122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("DISCONNECT, device " + device + " not connected"); 104569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 104669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1047122e077f24750ee0e7fd650cbfa832edeb216d07Jack He if (!mNativeInterface.disconnectHfp(device)) { 1048122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // broadcast immediately as no state transition is involved 1049122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogE("DISCONNECT from " + device + " failed"); 1050122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 10513659dee2b21c7f269a2bef051483093fe07e5682Jack He BluetoothProfile.STATE_CONNECTED); 1052122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 105369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1054122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mDisconnecting); 1055c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 1056c4fbd756e2645147470c486ae96f2253f5e13a52Jack He break; 1057122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 105867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("CONNECT_AUDIO, device=" + mDevice); 105927fca676c2809f992575420cf9fe360ae909699bJack He mSystemInterface.getAudioManager().setParameters("A2dpSuspended=true"); 106067ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mNativeInterface.connectAudio(mDevice)) { 106127fca676c2809f992575420cf9fe360ae909699bJack He mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false"); 106267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Failed to connect SCO audio for " + mDevice); 1063122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // No state change involved, fire broadcast immediately 106467ccceab9600aaeec6dc34658c45c074de39aa38Jack He broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 1065122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1066122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 106769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1068122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioConnecting); 106969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 1070122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT_AUDIO: 107167ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("ignore DISCONNECT_AUDIO, device=" + mDevice); 1072122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore 107369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 107469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava default: 1075122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return super.processMessage(message); 107669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1077c6231925ec13a432770a879c49b3c4f008ee96e1Jack He return HANDLED; 107869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 107969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 1080122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 108167ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processAudioEvent(int state) { 108267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("processAudioEvent, state=" + state); 108369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava switch (state) { 1084122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_CONNECTED: 1085a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (!mHeadsetService.isScoAcceptable(mDevice)) { 108667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("processAudioEvent: reject incoming audio connection"); 108767ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mNativeInterface.disconnectAudio(mDevice)) { 108867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: failed to disconnect audio"); 108969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1090a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // Indicate rejection to other components. 1091a639b81f96c534c2f1066354b4a574c0dda2f713Jack He broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 1092a639b81f96c534c2f1066354b4a574c0dda2f713Jack He BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1093122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 109469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 109567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio connected"); 1096122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioOn); 109769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 1098122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_CONNECTING: 1099a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (!mHeadsetService.isScoAcceptable(mDevice)) { 110067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("processAudioEvent: reject incoming pending audio connection"); 110167ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mNativeInterface.disconnectAudio(mDevice)) { 110267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: failed to disconnect pending audio"); 110369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1104a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // Indicate rejection to other components. 1105a639b81f96c534c2f1066354b4a574c0dda2f713Jack He broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 1106a639b81f96c534c2f1066354b4a574c0dda2f713Jack He BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 110739af3989003fd06fb3da55904ee074f706e1d448Jack He break; 110839af3989003fd06fb3da55904ee074f706e1d448Jack He } 110967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio connecting"); 1110122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioConnecting); 1111122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1112122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTED: 1113122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTING: 1114122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore 111569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 111669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava default: 111767ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: bad state: " + state); 111869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 111969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1120122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1121122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1122122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1123122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class AudioConnecting extends ConnectedBase { 1124122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1125122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 1126122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_CONNECTING; 1127122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1128122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1129122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1130122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void enter() { 1131122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 113267ccceab9600aaeec6dc34658c45c074de39aa38Jack He sendMessageDelayed(CONNECT_TIMEOUT, mDevice, sConnectTimeoutMs); 1133122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 1134122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1135122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1136122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1137122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public boolean processMessage(Message message) { 1138122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (message.what) { 1139122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: 1140122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 1141122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 1142122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT_AUDIO: 1143122e077f24750ee0e7fd650cbfa832edeb216d07Jack He deferMessage(message); 1144122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1145122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_TIMEOUT: { 1146122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 114767ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 1148122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_TIMEOUT for unknown device " + device); 1149122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1150122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1151122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_TIMEOUT"); 1152122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 1153122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1154122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1155122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 1156122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return super.processMessage(message); 115739af3989003fd06fb3da55904ee074f706e1d448Jack He } 1158122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return HANDLED; 115969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 116069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 1161122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 116267ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processAudioEvent(int state) { 116369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava switch (state) { 116469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.AUDIO_STATE_DISCONNECTED: 116567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("processAudioEvent: audio connection failed"); 116669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava transitionTo(mConnected); 116769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 1168122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_CONNECTING: 1169122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore, already in audio connecting state 1170122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 117169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.AUDIO_STATE_DISCONNECTING: 1172122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore, there is no BluetoothHeadset.STATE_AUDIO_DISCONNECTING 1173122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1174122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_CONNECTED: 117567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio connected"); 1176122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioOn); 117769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 117869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava default: 117967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: bad state: " + state); 118069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 118169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1182122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 118369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 1184122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1185122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void exit() { 1186122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeMessages(CONNECT_TIMEOUT); 1187122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.exit(); 118869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 118969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 119069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 1191122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class AudioOn extends ConnectedBase { 1192122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1193122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 1194122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_CONNECTED; 1195122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1196122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 119769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava @Override 119869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava public void enter() { 1199122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 1200122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeDeferredMessages(CONNECT_AUDIO); 120167ccceab9600aaeec6dc34658c45c074de39aa38Jack He // Set active device to current active SCO device when the current active device 120267ccceab9600aaeec6dc34658c45c074de39aa38Jack He // is different from mCurrentDevice. This is to accommodate active device state 120367ccceab9600aaeec6dc34658c45c074de39aa38Jack He // mis-match between native and Java. 1204caa5d6ab09bf61f4379413299ae1ab436c503710Jack He if (!mDevice.equals(mHeadsetService.getActiveDevice())) { 1205caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.setActiveDevice(mDevice); 120667ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 120767ccceab9600aaeec6dc34658c45c074de39aa38Jack He setAudioParameters(); 1208122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 120969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 121069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 121169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava @Override 121269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava public boolean processMessage(Message message) { 12133659dee2b21c7f269a2bef051483093fe07e5682Jack He switch (message.what) { 1214122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: { 1215122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 121667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("CONNECT, ignored, device=" + device + ", currentDevice" + mDevice); 121769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 1218122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1219122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: { 1220122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 1221122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("DISCONNECT, device=" + device); 122267ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 1223122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("DISCONNECT, device " + device + " not connected"); 1224122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 122569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1226122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // Disconnect BT SCO first 122767ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mNativeInterface.disconnectAudio(mDevice)) { 122867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("DISCONNECT failed, device=" + mDevice); 1229122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // if disconnect BT SCO failed, transition to mConnected state to force 1230122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // disconnect device 123169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 123267ccceab9600aaeec6dc34658c45c074de39aa38Jack He deferMessage(obtainMessage(DISCONNECT, mDevice)); 123367ccceab9600aaeec6dc34658c45c074de39aa38Jack He transitionTo(mAudioDisconnecting); 123469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 1235122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1236122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: { 123769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava BluetoothDevice device = (BluetoothDevice) message.obj; 123867ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 1239122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_AUDIO device is not connected " + device); 1240122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1241122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1242122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_AUDIO device auido is already connected " + device); 1243122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1244122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 124567ccceab9600aaeec6dc34658c45c074de39aa38Jack He case DISCONNECT_AUDIO: { 124667ccceab9600aaeec6dc34658c45c074de39aa38Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 124767ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 124867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("DISCONNECT_AUDIO, failed, device=" + device + ", currentDevice=" 124967ccceab9600aaeec6dc34658c45c074de39aa38Jack He + mDevice); 125067ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 125167ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 125267ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (mNativeInterface.disconnectAudio(mDevice)) { 125367ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogD("DISCONNECT_AUDIO, device=" + mDevice); 1254122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioDisconnecting); 125569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } else { 125667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("DISCONNECT_AUDIO failed, device=" + mDevice); 1257a639b81f96c534c2f1066354b4a574c0dda2f713Jack He broadcastAudioState(mDevice, BluetoothHeadset.STATE_AUDIO_CONNECTED, 1258a639b81f96c534c2f1066354b4a574c0dda2f713Jack He BluetoothHeadset.STATE_AUDIO_CONNECTED); 12596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 12606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 1261122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 126267ccceab9600aaeec6dc34658c45c074de39aa38Jack He case INTENT_SCO_VOLUME_CHANGED: 126367ccceab9600aaeec6dc34658c45c074de39aa38Jack He processIntentScoVolume((Intent) message.obj, mDevice); 1264b18d6a7da48a6847df88abadd42fbb51316cb76dRavi Nagarajan break; 12656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie case STACK_EVENT: 12660420b4fe3c7794139218821fab49f7f149d0075eJack He HeadsetStackEvent event = (HeadsetStackEvent) message.obj; 1267122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogD("STACK_EVENT: " + event); 126867ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(event.device)) { 126967ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Event device does not match currentDevice[" + mDevice 127067ccceab9600aaeec6dc34658c45c074de39aa38Jack He + "], event: " + event); 127167ccceab9600aaeec6dc34658c45c074de39aa38Jack He break; 127267ccceab9600aaeec6dc34658c45c074de39aa38Jack He } 12736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (event.type) { 127467ccceab9600aaeec6dc34658c45c074de39aa38Jack He case HeadsetStackEvent.EVENT_TYPE_WBS: 127567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("Cannot change WBS state when audio is connected: " + event); 12762ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 12776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 127867ccceab9600aaeec6dc34658c45c074de39aa38Jack He super.processMessage(message); 12796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 12806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 12816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 12826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 128367ccceab9600aaeec6dc34658c45c074de39aa38Jack He return super.processMessage(message); 12846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1285c6231925ec13a432770a879c49b3c4f008ee96e1Jack He return HANDLED; 12866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 12876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1288122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 128967ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processAudioEvent(int state) { 129042a6e53f2ec04cbd78fea952fc926fdf3e5b8cd9Ravi Nagarajan switch (state) { 1291122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTED: 129267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio disconnected by remote"); 1293122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 129442a6e53f2ec04cbd78fea952fc926fdf3e5b8cd9Ravi Nagarajan break; 1295122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTING: 129667ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio being disconnected by remote"); 1297122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioDisconnecting); 129839af3989003fd06fb3da55904ee074f706e1d448Jack He break; 1299122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 130067ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: bad state: " + state); 13013659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 1302122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1303122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1304122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1305122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private void processIntentScoVolume(Intent intent, BluetoothDevice device) { 1306122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int volumeValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 130750b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (mSpeakerVolume != volumeValue) { 130850b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSpeakerVolume = volumeValue; 1309122e077f24750ee0e7fd650cbfa832edeb216d07Jack He mNativeInterface.setVolume(device, HeadsetHalConstants.VOLUME_TYPE_SPK, 131050b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSpeakerVolume); 1311122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1312122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1313122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1314122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1315122e077f24750ee0e7fd650cbfa832edeb216d07Jack He class AudioDisconnecting extends ConnectedBase { 1316122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1317122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int getAudioStateInt() { 1318122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // TODO: need BluetoothHeadset.STATE_AUDIO_DISCONNECTING 1319122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return BluetoothHeadset.STATE_AUDIO_CONNECTED; 1320122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1321122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1322122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1323122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void enter() { 1324122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.enter(); 132567ccceab9600aaeec6dc34658c45c074de39aa38Jack He sendMessageDelayed(CONNECT_TIMEOUT, mDevice, sConnectTimeoutMs); 1326122e077f24750ee0e7fd650cbfa832edeb216d07Jack He broadcastStateTransitions(); 1327122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1328122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 1329122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1330122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public boolean processMessage(Message message) { 1331122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (message.what) { 1332122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: 1333122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 1334122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 1335122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT_AUDIO: 1336122e077f24750ee0e7fd650cbfa832edeb216d07Jack He deferMessage(message); 13373659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 1338122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_TIMEOUT: { 1339122e077f24750ee0e7fd650cbfa832edeb216d07Jack He BluetoothDevice device = (BluetoothDevice) message.obj; 134067ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!mDevice.equals(device)) { 1341122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_TIMEOUT for unknown device " + device); 1342122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 134369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 1344122e077f24750ee0e7fd650cbfa832edeb216d07Jack He stateLogW("CONNECT_TIMEOUT"); 1345122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 13463659dee2b21c7f269a2bef051483093fe07e5682Jack He break; 1347122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 13483659dee2b21c7f269a2bef051483093fe07e5682Jack He default: 1349122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return super.processMessage(message); 135039af3989003fd06fb3da55904ee074f706e1d448Jack He } 1351122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return HANDLED; 135242a6e53f2ec04cbd78fea952fc926fdf3e5b8cd9Ravi Nagarajan } 135342a6e53f2ec04cbd78fea952fc926fdf3e5b8cd9Ravi Nagarajan 1354122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 135567ccceab9600aaeec6dc34658c45c074de39aa38Jack He public void processAudioEvent(int state) { 13566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie switch (state) { 1357122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTED: 135867ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogI("processAudioEvent: audio disconnected"); 1359122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mConnected); 1360122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1361122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.AUDIO_STATE_DISCONNECTING: 1362122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore 1363122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 136469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.AUDIO_STATE_CONNECTED: 136567ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogW("processAudioEvent: audio disconnection failed"); 1366122e077f24750ee0e7fd650cbfa832edeb216d07Jack He transitionTo(mAudioOn); 136769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava break; 136869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava case HeadsetHalConstants.AUDIO_STATE_CONNECTING: 1369122e077f24750ee0e7fd650cbfa832edeb216d07Jack He // ignore, see if it goes into connected state, otherwise, timeout 13706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 13716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie default: 137267ccceab9600aaeec6dc34658c45c074de39aa38Jack He stateLogE("processAudioEvent: bad state: " + state); 13736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie break; 13746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 13756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 13766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1377122e077f24750ee0e7fd650cbfa832edeb216d07Jack He @Override 1378122e077f24750ee0e7fd650cbfa832edeb216d07Jack He public void exit() { 1379122e077f24750ee0e7fd650cbfa832edeb216d07Jack He removeMessages(CONNECT_TIMEOUT); 1380122e077f24750ee0e7fd650cbfa832edeb216d07Jack He super.exit(); 1381c924fea547063adc907a3a25044588aa58ac8879Mallikarjuna GB } 13826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 13836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 138467ccceab9600aaeec6dc34658c45c074de39aa38Jack He /** 138567ccceab9600aaeec6dc34658c45c074de39aa38Jack He * Get the underlying device tracked by this state machine 138667ccceab9600aaeec6dc34658c45c074de39aa38Jack He * 138767ccceab9600aaeec6dc34658c45c074de39aa38Jack He * @return device in focus 138867ccceab9600aaeec6dc34658c45c074de39aa38Jack He */ 138967ccceab9600aaeec6dc34658c45c074de39aa38Jack He @VisibleForTesting 139067ccceab9600aaeec6dc34658c45c074de39aa38Jack He public synchronized BluetoothDevice getDevice() { 139167ccceab9600aaeec6dc34658c45c074de39aa38Jack He return mDevice; 1392122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 1393122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 139467ccceab9600aaeec6dc34658c45c074de39aa38Jack He /** 139567ccceab9600aaeec6dc34658c45c074de39aa38Jack He * Get the current connection state of this state machine 139667ccceab9600aaeec6dc34658c45c074de39aa38Jack He * 139767ccceab9600aaeec6dc34658c45c074de39aa38Jack He * @return current connection state, one of {@link BluetoothProfile#STATE_DISCONNECTED}, 139867ccceab9600aaeec6dc34658c45c074de39aa38Jack He * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or 139967ccceab9600aaeec6dc34658c45c074de39aa38Jack He * {@link BluetoothProfile#STATE_DISCONNECTING} 140067ccceab9600aaeec6dc34658c45c074de39aa38Jack He */ 140167ccceab9600aaeec6dc34658c45c074de39aa38Jack He @VisibleForTesting 140267ccceab9600aaeec6dc34658c45c074de39aa38Jack He public synchronized int getConnectionState() { 140367ccceab9600aaeec6dc34658c45c074de39aa38Jack He HeadsetStateBase state = (HeadsetStateBase) getCurrentState(); 140467ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (state == null) { 140567ccceab9600aaeec6dc34658c45c074de39aa38Jack He return BluetoothHeadset.STATE_DISCONNECTED; 14066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 140767ccceab9600aaeec6dc34658c45c074de39aa38Jack He return state.getConnectionStateInt(); 14086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 14096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 141067ccceab9600aaeec6dc34658c45c074de39aa38Jack He /** 141167ccceab9600aaeec6dc34658c45c074de39aa38Jack He * Get the current audio state of this state machine 141267ccceab9600aaeec6dc34658c45c074de39aa38Jack He * 141367ccceab9600aaeec6dc34658c45c074de39aa38Jack He * @return current audio state, one of {@link BluetoothHeadset#STATE_AUDIO_DISCONNECTED}, 141467ccceab9600aaeec6dc34658c45c074de39aa38Jack He * {@link BluetoothHeadset#STATE_AUDIO_CONNECTING}, or 141567ccceab9600aaeec6dc34658c45c074de39aa38Jack He * {@link BluetoothHeadset#STATE_AUDIO_CONNECTED} 141667ccceab9600aaeec6dc34658c45c074de39aa38Jack He */ 141767ccceab9600aaeec6dc34658c45c074de39aa38Jack He public synchronized int getAudioState() { 141867ccceab9600aaeec6dc34658c45c074de39aa38Jack He HeadsetStateBase state = (HeadsetStateBase) getCurrentState(); 141967ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (state == null) { 142067ccceab9600aaeec6dc34658c45c074de39aa38Jack He return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 14216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 142267ccceab9600aaeec6dc34658c45c074de39aa38Jack He return state.getAudioStateInt(); 14236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 14246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 142567ccceab9600aaeec6dc34658c45c074de39aa38Jack He public long getConnectingTimestampMs() { 142667ccceab9600aaeec6dc34658c45c074de39aa38Jack He return mConnectingTimestampMs; 142769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 142869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 1429dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu /* 1430dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * Put the AT command, company ID, arguments, and device in an Intent and broadcast it. 1431dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu */ 14323659dee2b21c7f269a2bef051483093fe07e5682Jack He private void broadcastVendorSpecificEventIntent(String command, int companyId, int commandType, 14333659dee2b21c7f269a2bef051483093fe07e5682Jack He Object[] arguments, BluetoothDevice device) { 1434dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu log("broadcastVendorSpecificEventIntent(" + command + ")"); 14353659dee2b21c7f269a2bef051483093fe07e5682Jack He Intent intent = new Intent(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT); 1436dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD, command); 14373659dee2b21c7f269a2bef051483093fe07e5682Jack He intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, commandType); 1438dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu // assert: all elements of args are Serializable 1439dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS, arguments); 1440dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 14413659dee2b21c7f269a2bef051483093fe07e5682Jack He intent.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." 14423659dee2b21c7f269a2bef051483093fe07e5682Jack He + Integer.toString(companyId)); 1443caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.sendBroadcastAsUser(intent, UserHandle.ALL, HeadsetService.BLUETOOTH_PERM); 1444dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1445dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 144667ccceab9600aaeec6dc34658c45c074de39aa38Jack He private void setAudioParameters() { 144767ccceab9600aaeec6dc34658c45c074de39aa38Jack He String keyValuePairs = String.join(";", new String[]{ 144867ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_NAME + "=" + getCurrentDeviceName(), 144967ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_NREC + "=" + mAudioParams.getOrDefault(HEADSET_NREC, 145067ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_AUDIO_FEATURE_OFF), 145167ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_WBS + "=" + mAudioParams.getOrDefault(HEADSET_WBS, 145267ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_AUDIO_FEATURE_OFF) 145367ccceab9600aaeec6dc34658c45c074de39aa38Jack He }); 145467ccceab9600aaeec6dc34658c45c074de39aa38Jack He Log.i(TAG, "setAudioParameters for " + mDevice + ": " + keyValuePairs); 145567ccceab9600aaeec6dc34658c45c074de39aa38Jack He mSystemInterface.getAudioManager().setParameters(keyValuePairs); 145668e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan } 145768e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan 14583659dee2b21c7f269a2bef051483093fe07e5682Jack He private String parseUnknownAt(String atString) { 1459405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T StringBuilder atCommand = new StringBuilder(atString.length()); 1460405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 1461405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T for (int i = 0; i < atString.length(); i++) { 1462405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T char c = atString.charAt(i); 1463405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T if (c == '"') { 14643659dee2b21c7f269a2bef051483093fe07e5682Jack He int j = atString.indexOf('"', i + 1); // search for closing " 14653659dee2b21c7f269a2bef051483093fe07e5682Jack He if (j == -1) { // unmatched ", insert one. 1466405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atCommand.append(atString.substring(i, atString.length())); 1467405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atCommand.append('"'); 1468405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T break; 1469405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1470405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atCommand.append(atString.substring(i, j + 1)); 1471405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T i = j; 1472405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } else if (c != ' ') { 1473405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atCommand.append(Character.toUpperCase(c)); 1474405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1475405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 147667ccceab9600aaeec6dc34658c45c074de39aa38Jack He return atCommand.toString(); 1477405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1478405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 14793659dee2b21c7f269a2bef051483093fe07e5682Jack He private int getAtCommandType(String atCommand) { 1480122e077f24750ee0e7fd650cbfa832edeb216d07Jack He int commandType = AtPhonebook.TYPE_UNKNOWN; 1481405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T String atString = null; 1482405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atCommand = atCommand.trim(); 14833659dee2b21c7f269a2bef051483093fe07e5682Jack He if (atCommand.length() > 5) { 1484405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T atString = atCommand.substring(5); 148576a12d7e679ae48f8ab73e01b33fb7c8f077a210Jack He if (atString.startsWith("?")) { // Read 1486122e077f24750ee0e7fd650cbfa832edeb216d07Jack He commandType = AtPhonebook.TYPE_READ; 148776a12d7e679ae48f8ab73e01b33fb7c8f077a210Jack He } else if (atString.startsWith("=?")) { // Test 1488122e077f24750ee0e7fd650cbfa832edeb216d07Jack He commandType = AtPhonebook.TYPE_TEST; 148976a12d7e679ae48f8ab73e01b33fb7c8f077a210Jack He } else if (atString.startsWith("=")) { // Set 1490122e077f24750ee0e7fd650cbfa832edeb216d07Jack He commandType = AtPhonebook.TYPE_SET; 149176a12d7e679ae48f8ab73e01b33fb7c8f077a210Jack He } else { 1492122e077f24750ee0e7fd650cbfa832edeb216d07Jack He commandType = AtPhonebook.TYPE_UNKNOWN; 149376a12d7e679ae48f8ab73e01b33fb7c8f077a210Jack He } 1494405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1495405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T return commandType; 1496405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1497405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 1498a639b81f96c534c2f1066354b4a574c0dda2f713Jack He private void processDialCall(String number) { 14996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String dialNumber; 1500a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (mHeadsetService.hasDeviceInitiatedDialingOut()) { 1501a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processDialCall, already dialling"); 1502a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 15038e79653c4d093d6f6696312f668429feb6d62bf3Mallikarjuna GB return; 15048e79653c4d093d6f6696312f668429feb6d62bf3Mallikarjuna GB } 15058f8e1bdc4dfc5d9d974b0e0b01dbe981707c9c6fRavi Nagarajan if ((number == null) || (number.length() == 0)) { 15066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie dialNumber = mPhonebook.getLastDialledNumber(); 15076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (dialNumber == null) { 1508a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processDialCall, last dial number null"); 1509a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 15106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return; 15116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 15126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else if (number.charAt(0) == '>') { 15136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie // Yuck - memory dialling requested. 15146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie // Just dial last number for now 15153659dee2b21c7f269a2bef051483093fe07e5682Jack He if (number.startsWith(">9999")) { // for PTS test 1516a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "Number is too big"); 1517a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 15186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return; 15196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1520c6231925ec13a432770a879c49b3c4f008ee96e1Jack He log("processDialCall, memory dial do last dial for now"); 15216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie dialNumber = mPhonebook.getLastDialledNumber(); 15229b300c1a33952a22c3bba1521da2d01cbf607b7bMatthew Xie if (dialNumber == null) { 1523a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processDialCall, last dial number null"); 1524a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 15259b300c1a33952a22c3bba1521da2d01cbf607b7bMatthew Xie return; 15269b300c1a33952a22c3bba1521da2d01cbf607b7bMatthew Xie } 15276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else { 15288f8e1bdc4dfc5d9d974b0e0b01dbe981707c9c6fRavi Nagarajan // Remove trailing ';' 15298f8e1bdc4dfc5d9d974b0e0b01dbe981707c9c6fRavi Nagarajan if (number.charAt(number.length() - 1) == ';') { 15308f8e1bdc4dfc5d9d974b0e0b01dbe981707c9c6fRavi Nagarajan number = number.substring(0, number.length() - 1); 15318f8e1bdc4dfc5d9d974b0e0b01dbe981707c9c6fRavi Nagarajan } 15326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie dialNumber = PhoneNumberUtils.convertPreDial(number); 15336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1534a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (!mHeadsetService.dialOutgoingCall(mDevice, dialNumber)) { 1535a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processDialCall, failed to dial in service"); 1536a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1537a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return; 1538a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 1539a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mNeedDialingOutReply = true; 15406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 15416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1542ff5993924ef627e8b723d33ccb5514cb15bb134dJack He private void processVrEvent(int state) { 1543ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (state == HeadsetHalConstants.VR_STATE_STARTED) { 1544ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (!mHeadsetService.startVoiceRecognitionByHeadset(mDevice)) { 1545ff5993924ef627e8b723d33ccb5514cb15bb134dJack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1546ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 1547ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } else if (state == HeadsetHalConstants.VR_STATE_STOPPED) { 1548ff5993924ef627e8b723d33ccb5514cb15bb134dJack He if (mHeadsetService.stopVoiceRecognitionByHeadset(mDevice)) { 1549ff5993924ef627e8b723d33ccb5514cb15bb134dJack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_OK, 0); 1550ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } else { 1551ff5993924ef627e8b723d33ccb5514cb15bb134dJack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1552ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 1553ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } else { 1554ff5993924ef627e8b723d33ccb5514cb15bb134dJack He mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1555ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 1556ff5993924ef627e8b723d33ccb5514cb15bb134dJack He } 1557ff5993924ef627e8b723d33ccb5514cb15bb134dJack He 155867ccceab9600aaeec6dc34658c45c074de39aa38Jack He private void processVolumeEvent(int volumeType, int volume) { 1559dbd53d223fddcad41820c3ded5d36058c5910e7fJack He // Only current active device can change SCO volume 1560dbd53d223fddcad41820c3ded5d36058c5910e7fJack He if (!mDevice.equals(mHeadsetService.getActiveDevice())) { 1561dbd53d223fddcad41820c3ded5d36058c5910e7fJack He Log.w(TAG, "processVolumeEvent, ignored because " + mDevice + " is not active"); 1562dbd53d223fddcad41820c3ded5d36058c5910e7fJack He return; 156350b51beb3bd0885ced514d1bcfda3050f60833ffJack He } 15646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (volumeType == HeadsetHalConstants.VOLUME_TYPE_SPK) { 156550b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSpeakerVolume = volume; 15666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie int flag = (getCurrentState() == mAudioOn) ? AudioManager.FLAG_SHOW_UI : 0; 156750b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSystemInterface.getAudioManager() 156850b51beb3bd0885ced514d1bcfda3050f60833ffJack He .setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, volume, flag); 1569f0b6639617ce2245ffb88968e8a864d0fa99dd8cMatthew Xie } else if (volumeType == HeadsetHalConstants.VOLUME_TYPE_MIC) { 157050b51beb3bd0885ced514d1bcfda3050f60833ffJack He // Not used currently 157150b51beb3bd0885ced514d1bcfda3050f60833ffJack He mMicVolume = volume; 1572f0b6639617ce2245ffb88968e8a864d0fa99dd8cMatthew Xie } else { 1573dbd53d223fddcad41820c3ded5d36058c5910e7fJack He Log.e(TAG, "Bad volume type: " + volumeType); 1574f0b6639617ce2245ffb88968e8a864d0fa99dd8cMatthew Xie } 15756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 15766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 157767ccceab9600aaeec6dc34658c45c074de39aa38Jack He private void processNoiseReductionEvent(boolean enable) { 157867ccceab9600aaeec6dc34658c45c074de39aa38Jack He String prevNrec = mAudioParams.getOrDefault(HEADSET_NREC, HEADSET_AUDIO_FEATURE_OFF); 157967ccceab9600aaeec6dc34658c45c074de39aa38Jack He String newNrec = enable ? HEADSET_AUDIO_FEATURE_ON : HEADSET_AUDIO_FEATURE_OFF; 158067ccceab9600aaeec6dc34658c45c074de39aa38Jack He mAudioParams.put(HEADSET_NREC, newNrec); 158167ccceab9600aaeec6dc34658c45c074de39aa38Jack He log("processNoiseReductionEvent: " + HEADSET_NREC + " change " + prevNrec + " -> " 158267ccceab9600aaeec6dc34658c45c074de39aa38Jack He + newNrec); 158367ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (getAudioState() == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 158467ccceab9600aaeec6dc34658c45c074de39aa38Jack He setAudioParameters(); 15856385f5ec823dd1113708532d20729dba67d9beaaSungmin Choi } 158668e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan } 158768e7fc4f2c62ebc76e86109a919592ad25ec11d7Ravi Nagarajan 1588122e077f24750ee0e7fd650cbfa832edeb216d07Jack He private void processWBSEvent(int wbsConfig) { 158967ccceab9600aaeec6dc34658c45c074de39aa38Jack He String prevWbs = mAudioParams.getOrDefault(HEADSET_WBS, HEADSET_AUDIO_FEATURE_OFF); 1590122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (wbsConfig) { 1591122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.BTHF_WBS_YES: 159267ccceab9600aaeec6dc34658c45c074de39aa38Jack He mAudioParams.put(HEADSET_WBS, HEADSET_AUDIO_FEATURE_ON); 1593122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1594122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.BTHF_WBS_NO: 1595122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case HeadsetHalConstants.BTHF_WBS_NONE: 159667ccceab9600aaeec6dc34658c45c074de39aa38Jack He mAudioParams.put(HEADSET_WBS, HEADSET_AUDIO_FEATURE_OFF); 1597122e077f24750ee0e7fd650cbfa832edeb216d07Jack He break; 1598122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 159967ccceab9600aaeec6dc34658c45c074de39aa38Jack He Log.e(TAG, "processWBSEvent: unknown wbsConfig " + wbsConfig); 160067ccceab9600aaeec6dc34658c45c074de39aa38Jack He return; 1601b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 160267ccceab9600aaeec6dc34658c45c074de39aa38Jack He log("processWBSEvent: " + HEADSET_NREC + " change " + prevWbs + " -> " + mAudioParams.get( 160367ccceab9600aaeec6dc34658c45c074de39aa38Jack He HEADSET_WBS)); 1604b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 1605b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 160669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtChld(int chld, BluetoothDevice device) { 160750b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (mSystemInterface.processChld(chld)) { 160850b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_OK, 0); 16096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else { 16100420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 16116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 161469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processSubscriberNumberRequest(BluetoothDevice device) { 161550b51beb3bd0885ced514d1bcfda3050f60833ffJack He String number = mSystemInterface.getSubscriberNumber(); 161650b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (number != null) { 161750b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.atResponseString(device, 161850b51beb3bd0885ced514d1bcfda3050f60833ffJack He "+CNUM: ,\"" + number + "\"," + PhoneNumberUtils.toaFromString(number) + ",,4"); 161950b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_OK, 0); 16206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else { 162150b51beb3bd0885ced514d1bcfda3050f60833ffJack He Log.e(TAG, "getSubscriberNumber returns null"); 162250b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 16236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 162669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtCind(BluetoothDevice device) { 16275ef52da260f8b4c1baed22bceb2983a694bb022cJack He int call, callSetup; 162850b51beb3bd0885ced514d1bcfda3050f60833ffJack He final HeadsetPhoneState phoneState = mSystemInterface.getHeadsetPhoneState(); 162969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava 16306b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M /* Handsfree carkits expect that +CIND is properly responded to 16316b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M Hence we ensure that a proper response is sent 16326b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M for the virtual call too.*/ 1633a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (mHeadsetService.isVirtualCallStarted()) { 16346b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M call = 1; 16355ef52da260f8b4c1baed22bceb2983a694bb022cJack He callSetup = 0; 16366b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } else { 16376b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M // regular phone call 163850b51beb3bd0885ced514d1bcfda3050f60833ffJack He call = phoneState.getNumActiveCall(); 163950b51beb3bd0885ced514d1bcfda3050f60833ffJack He callSetup = phoneState.getNumHeldCall(); 16406b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } 16416b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M 164250b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.cindResponse(device, phoneState.getCindService(), call, callSetup, 164350b51beb3bd0885ced514d1bcfda3050f60833ffJack He phoneState.getCallState(), phoneState.getCindSignal(), phoneState.getCindRoam(), 164450b51beb3bd0885ced514d1bcfda3050f60833ffJack He phoneState.getCindBatteryCharge()); 16456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 164769d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtCops(BluetoothDevice device) { 164850b51beb3bd0885ced514d1bcfda3050f60833ffJack He String operatorName = mSystemInterface.getNetworkOperator(); 164950b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (operatorName == null) { 165050b51beb3bd0885ced514d1bcfda3050f60833ffJack He operatorName = ""; 16516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 165250b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.copsResponse(device, operatorName); 16536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 165569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtClcc(BluetoothDevice device) { 1656a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (mHeadsetService.isVirtualCallStarted()) { 165750b51beb3bd0885ced514d1bcfda3050f60833ffJack He // In virtual call, send our phone number instead of remote phone number 165850b51beb3bd0885ced514d1bcfda3050f60833ffJack He String phoneNumber = mSystemInterface.getSubscriberNumber(); 165950b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (phoneNumber == null) { 166050b51beb3bd0885ced514d1bcfda3050f60833ffJack He phoneNumber = ""; 16616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 166250b51beb3bd0885ced514d1bcfda3050f60833ffJack He int type = PhoneNumberUtils.toaFromString(phoneNumber); 166350b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.clccResponse(device, 1, 0, 0, 0, false, phoneNumber, type); 16640420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.clccResponse(device, 0, 0, 0, 0, false, "", 0); 166550b51beb3bd0885ced514d1bcfda3050f60833ffJack He } else { 166650b51beb3bd0885ced514d1bcfda3050f60833ffJack He // In Telecom call, ask Telecom to send send remote phone number 166750b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (!mSystemInterface.listCurrentCalls()) { 166850b51beb3bd0885ced514d1bcfda3050f60833ffJack He Log.e(TAG, "processAtClcc: failed to list current calls for " + device); 166950b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.clccResponse(device, 0, 0, 0, 0, false, "", 0); 167050b51beb3bd0885ced514d1bcfda3050f60833ffJack He } else { 167167ccceab9600aaeec6dc34658c45c074de39aa38Jack He sendMessageDelayed(CLCC_RSP_TIMEOUT, device, CLCC_RSP_TIMEOUT_MS); 167250b51beb3bd0885ced514d1bcfda3050f60833ffJack He } 16736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 16756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 167669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtCscs(String atString, int type, BluetoothDevice device) { 16773659dee2b21c7f269a2bef051483093fe07e5682Jack He log("processAtCscs - atString = " + atString); 16783659dee2b21c7f269a2bef051483093fe07e5682Jack He if (mPhonebook != null) { 167969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava mPhonebook.handleCscsCommand(atString, type, device); 16803659dee2b21c7f269a2bef051483093fe07e5682Jack He } else { 1681405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T Log.e(TAG, "Phonebook handle null for At+CSCS"); 16820420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1683405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1684405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1685405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 168669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtCpbs(String atString, int type, BluetoothDevice device) { 16873659dee2b21c7f269a2bef051483093fe07e5682Jack He log("processAtCpbs - atString = " + atString); 16883659dee2b21c7f269a2bef051483093fe07e5682Jack He if (mPhonebook != null) { 168969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava mPhonebook.handleCpbsCommand(atString, type, device); 16903659dee2b21c7f269a2bef051483093fe07e5682Jack He } else { 1691405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T Log.e(TAG, "Phonebook handle null for At+CPBS"); 16920420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1693405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1694405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1695405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 169669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processAtCpbr(String atString, int type, BluetoothDevice device) { 16973659dee2b21c7f269a2bef051483093fe07e5682Jack He log("processAtCpbr - atString = " + atString); 16983659dee2b21c7f269a2bef051483093fe07e5682Jack He if (mPhonebook != null) { 169969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava mPhonebook.handleCpbrCommand(atString, type, device); 17003659dee2b21c7f269a2bef051483093fe07e5682Jack He } else { 1701405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T Log.e(TAG, "Phonebook handle null for At+CPBR"); 17020420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1703405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1704405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1705405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T 1706dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu /** 1707dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * Find a character ch, ignoring quoted sections. 1708dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * Return input.length() if not found. 1709dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu */ 1710dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static int findChar(char ch, String input, int fromIndex) { 1711dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu for (int i = fromIndex; i < input.length(); i++) { 1712dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu char c = input.charAt(i); 1713dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu if (c == '"') { 1714dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu i = input.indexOf('"', i + 1); 1715dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu if (i == -1) { 1716dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu return input.length(); 1717dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1718dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } else if (c == ch) { 1719dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu return i; 1720dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1721dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1722dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu return input.length(); 1723dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1724dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 1725dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu /** 1726dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * Break an argument string into individual arguments (comma delimited). 1727dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * Integer arguments are turned into Integer objects. Otherwise a String 1728dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu * object is used. 1729dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu */ 1730dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static Object[] generateArgs(String input) { 1731dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu int i = 0; 1732dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu int j; 1733dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu ArrayList<Object> out = new ArrayList<Object>(); 1734dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu while (i <= input.length()) { 1735dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu j = findChar(',', input, i); 1736dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 1737dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu String arg = input.substring(i, j); 1738dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu try { 1739dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu out.add(new Integer(arg)); 1740dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } catch (NumberFormatException e) { 1741dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu out.add(arg); 1742dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1743dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 1744dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu i = j + 1; // move past comma 1745dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1746dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu return out.toArray(); 1747dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1748dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 1749cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee /** 1750f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * Process vendor specific AT commands 1751122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 1752f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * @param atString AT command after the "AT+" prefix 1753f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * @param device Remote device that has sent this command 1754cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee */ 1755f27d360b7ec35eaddee66cac173c51c18c238b03Jack He private void processVendorSpecificAt(String atString, BluetoothDevice device) { 1756cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee log("processVendorSpecificAt - atString = " + atString); 1757cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 1758cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee // Currently we accept only SET type commands. 1759cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee int indexOfEqual = atString.indexOf("="); 1760cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (indexOfEqual == -1) { 1761a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processVendorSpecificAt: command type error in " + atString); 17620420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1763f27d360b7ec35eaddee66cac173c51c18c238b03Jack He return; 1764dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1765cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 1766cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String command = atString.substring(0, indexOfEqual); 1767cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee Integer companyId = VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.get(command); 1768cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (companyId == null) { 1769a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.i(TAG, "processVendorSpecificAt: unsupported command: " + atString); 17700420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1771f27d360b7ec35eaddee66cac173c51c18c238b03Jack He return; 1772dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1773cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 1774cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String arg = atString.substring(indexOfEqual + 1); 1775cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (arg.startsWith("?")) { 1776a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processVendorSpecificAt: command type error in " + atString); 17770420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1778f27d360b7ec35eaddee66cac173c51c18c238b03Jack He return; 1779cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 1780cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 1781cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee Object[] args = generateArgs(arg); 1782f27d360b7ec35eaddee66cac173c51c18c238b03Jack He if (command.equals(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XAPL)) { 1783f27d360b7ec35eaddee66cac173c51c18c238b03Jack He processAtXapl(args, device); 1784f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } 1785c4fbd756e2645147470c486ae96f2253f5e13a52Jack He broadcastVendorSpecificEventIntent(command, companyId, BluetoothHeadset.AT_CMD_TYPE_SET, 1786c4fbd756e2645147470c486ae96f2253f5e13a52Jack He args, device); 17870420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseCode(device, HeadsetHalConstants.AT_RESPONSE_OK, 0); 1788f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } 1789f27d360b7ec35eaddee66cac173c51c18c238b03Jack He 1790f27d360b7ec35eaddee66cac173c51c18c238b03Jack He /** 1791f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * Process AT+XAPL AT command 1792122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 1793f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * @param args command arguments after the equal sign 1794f27d360b7ec35eaddee66cac173c51c18c238b03Jack He * @param device Remote device that has sent this command 1795f27d360b7ec35eaddee66cac173c51c18c238b03Jack He */ 1796f27d360b7ec35eaddee66cac173c51c18c238b03Jack He private void processAtXapl(Object[] args, BluetoothDevice device) { 1797f27d360b7ec35eaddee66cac173c51c18c238b03Jack He if (args.length != 2) { 1798f27d360b7ec35eaddee66cac173c51c18c238b03Jack He Log.w(TAG, "processAtXapl() args length must be 2: " + String.valueOf(args.length)); 1799f27d360b7ec35eaddee66cac173c51c18c238b03Jack He return; 1800f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } 1801f27d360b7ec35eaddee66cac173c51c18c238b03Jack He if (!(args[0] instanceof String) || !(args[1] instanceof Integer)) { 1802f27d360b7ec35eaddee66cac173c51c18c238b03Jack He Log.w(TAG, "processAtXapl() argument types not match"); 1803f27d360b7ec35eaddee66cac173c51c18c238b03Jack He return; 1804f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } 1805f27d360b7ec35eaddee66cac173c51c18c238b03Jack He // feature = 2 indicates that we support battery level reporting only 18060420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseString(device, "+XAPL=iPhone," + String.valueOf(2)); 1807dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu } 1808dd66c701616d77e5bf7f5fd795999f59e5fe28bdZhihai Xu 180969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processUnknownAt(String atString, BluetoothDevice device) { 18103659dee2b21c7f269a2bef051483093fe07e5682Jack He if (device == null) { 181169d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava Log.w(TAG, "processUnknownAt device is null"); 181269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava return; 181369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 18143659dee2b21c7f269a2bef051483093fe07e5682Jack He log("processUnknownAt - atString = " + atString); 1815405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T String atCommand = parseUnknownAt(atString); 1816405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T int commandType = getAtCommandType(atCommand); 1817f27d360b7ec35eaddee66cac173c51c18c238b03Jack He if (atCommand.startsWith("+CSCS")) { 181869d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtCscs(atCommand.substring(5), commandType, device); 1819f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } else if (atCommand.startsWith("+CPBS")) { 182069d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtCpbs(atCommand.substring(5), commandType, device); 1821f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } else if (atCommand.startsWith("+CPBR")) { 182269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava processAtCpbr(atCommand.substring(5), commandType, device); 1823f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } else { 1824f27d360b7ec35eaddee66cac173c51c18c238b03Jack He processVendorSpecificAt(atCommand, device); 1825f27d360b7ec35eaddee66cac173c51c18c238b03Jack He } 18266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 18276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1828a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // HSP +CKPD command 182969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava private void processKeyPressed(BluetoothDevice device) { 1830f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He if (mSystemInterface.isRinging()) { 183150b51beb3bd0885ced514d1bcfda3050f60833ffJack He mSystemInterface.answerCall(device); 1832f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He } else if (mSystemInterface.isInCall()) { 1833f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He if (getAudioState() == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 1834f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He // Should connect audio as well 1835f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He if (!mHeadsetService.setActiveDevice(mDevice)) { 1836f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He Log.w(TAG, "processKeyPressed, failed to set active device to " + mDevice); 183727fca676c2809f992575420cf9fe360ae909699bJack He } 18383659dee2b21c7f269a2bef051483093fe07e5682Jack He } else { 1839a639b81f96c534c2f1066354b4a574c0dda2f713Jack He mSystemInterface.hangupCall(device); 18406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1841f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He } else if (getAudioState() != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 1842f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He if (!mNativeInterface.disconnectAudio(mDevice)) { 1843f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He Log.w(TAG, "processKeyPressed, failed to disconnect audio from " + mDevice); 1844f451ece4cd322f71ba3643c440e6b065e9e93f28Jack He } 18456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else { 1846a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // We have already replied OK to this HSP command, no feedback is needed 1847a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (mHeadsetService.hasDeviceInitiatedDialingOut()) { 1848a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processKeyPressed, already dialling"); 1849a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return; 1850a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 18516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String dialNumber = mPhonebook.getLastDialledNumber(); 18526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (dialNumber == null) { 1853a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processKeyPressed, last dial number null"); 1854a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return; 1855a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 1856a639b81f96c534c2f1066354b4a574c0dda2f713Jack He if (!mHeadsetService.dialOutgoingCall(mDevice, dialNumber)) { 1857a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Log.w(TAG, "processKeyPressed, failed to call in service"); 18586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return; 18596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 18606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 18616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 18626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 18630b319f1df5ba13d6bec5a431cc4f329b43dd37fbJack He /** 18640b319f1df5ba13d6bec5a431cc4f329b43dd37fbJack He * Send HF indicator value changed intent 1865122e077f24750ee0e7fd650cbfa832edeb216d07Jack He * 18660b319f1df5ba13d6bec5a431cc4f329b43dd37fbJack He * @param device Device whose HF indicator value has changed 1867b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He * @param indId Indicator ID [0-65535] 1868b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He * @param indValue Indicator Value [0-65535], -1 means invalid but indId is supported 18690b319f1df5ba13d6bec5a431cc4f329b43dd37fbJack He */ 1870b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He private void sendIndicatorIntent(BluetoothDevice device, int indId, int indValue) { 18712ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth Intent intent = new Intent(BluetoothHeadset.ACTION_HF_INDICATORS_VALUE_CHANGED); 18722ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1873b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He intent.putExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_ID, indId); 1874b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He intent.putExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_VALUE, indValue); 18752ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 1876caa5d6ab09bf61f4379413299ae1ab436c503710Jack He mHeadsetService.sendBroadcast(intent, HeadsetService.BLUETOOTH_PERM); 18772ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 18782ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 1879b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He private void processAtBind(String atString, BluetoothDevice device) { 1880b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He log("processAtBind: " + atString); 18812ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 18822ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth // Parse the AT String to find the Indicator Ids that are supported 18835ef52da260f8b4c1baed22bceb2983a694bb022cJack He int indId = 0; 18842ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth int iter = 0; 18852ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth int iter1 = 0; 18862ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 1887b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He while (iter < atString.length()) { 1888b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He iter1 = findChar(',', atString, iter); 1889b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He String id = atString.substring(iter, iter1); 18902ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 18912ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth try { 18925ef52da260f8b4c1baed22bceb2983a694bb022cJack He indId = Integer.valueOf(id); 18932ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } catch (NumberFormatException e) { 18942ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth Log.e(TAG, Log.getStackTraceString(new Throwable())); 18952ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 18962ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 18975ef52da260f8b4c1baed22bceb2983a694bb022cJack He switch (indId) { 18983659dee2b21c7f269a2bef051483093fe07e5682Jack He case HeadsetHalConstants.HF_INDICATOR_ENHANCED_DRIVER_SAFETY: 1899c6231925ec13a432770a879c49b3c4f008ee96e1Jack He log("Send Broadcast intent for the Enhanced Driver Safety indicator."); 19005ef52da260f8b4c1baed22bceb2983a694bb022cJack He sendIndicatorIntent(device, indId, -1); 19012ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 19023659dee2b21c7f269a2bef051483093fe07e5682Jack He case HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS: 1903c6231925ec13a432770a879c49b3c4f008ee96e1Jack He log("Send Broadcast intent for the Battery Level indicator."); 19045ef52da260f8b4c1baed22bceb2983a694bb022cJack He sendIndicatorIntent(device, indId, -1); 19052ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 19062ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth default: 19072ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth log("Invalid HF Indicator Received"); 19082ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth break; 19092ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 19102ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 19112ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth iter = iter1 + 1; // move past comma 19122ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 19132ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 19142ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 1915c6231925ec13a432770a879c49b3c4f008ee96e1Jack He private void processAtBiev(int indId, int indValue, BluetoothDevice device) { 1916c6231925ec13a432770a879c49b3c4f008ee96e1Jack He log("processAtBiev: ind_id=" + indId + ", ind_value=" + indValue); 1917c6231925ec13a432770a879c49b3c4f008ee96e1Jack He sendIndicatorIntent(device, indId, indValue); 19182ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth } 19192ab50a41dac634a78cef60a419c3bcc848c1aa78Mudumba Ananth 19206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie private void processSendClccResponse(HeadsetClccResponse clcc) { 192167ccceab9600aaeec6dc34658c45c074de39aa38Jack He if (!hasMessages(CLCC_RSP_TIMEOUT)) { 19225d56b57b6fac07125f5462a6ed3dd3b1a546541bSunny Kapdi return; 19235d56b57b6fac07125f5462a6ed3dd3b1a546541bSunny Kapdi } 192469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava if (clcc.mIndex == 0) { 192569d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava removeMessages(CLCC_RSP_TIMEOUT); 192669d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava } 192767ccceab9600aaeec6dc34658c45c074de39aa38Jack He mNativeInterface.clccResponse(mDevice, clcc.mIndex, clcc.mDirection, clcc.mStatus, 19280420b4fe3c7794139218821fab49f7f149d0075eJack He clcc.mMode, clcc.mMpty, clcc.mNumber, clcc.mType); 19296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 19306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1931cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee private void processSendVendorSpecificResultCode(HeadsetVendorSpecificResultCode resultCode) { 1932cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String stringToSend = resultCode.mCommand + ": "; 1933cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (resultCode.mArg != null) { 1934cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee stringToSend += resultCode.mArg; 1935cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 19360420b4fe3c7794139218821fab49f7f149d0075eJack He mNativeInterface.atResponseString(resultCode.mDevice, stringToSend); 1937cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 1938cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 193967ccceab9600aaeec6dc34658c45c074de39aa38Jack He private String getCurrentDeviceName() { 1940caa5d6ab09bf61f4379413299ae1ab436c503710Jack He String deviceName = mAdapterService.getRemoteName(mDevice); 19416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (deviceName == null) { 194267ccceab9600aaeec6dc34658c45c074de39aa38Jack He return "<unknown>"; 19436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 19446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie return deviceName; 19456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 19466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1947448309eada01c130b2fee8977f7fd74875978cbcJack He private void updateAgIndicatorEnableState( 1948448309eada01c130b2fee8977f7fd74875978cbcJack He HeadsetAgIndicatorEnableState agIndicatorEnableState) { 1949448309eada01c130b2fee8977f7fd74875978cbcJack He if (Objects.equals(mAgIndicatorEnableState, agIndicatorEnableState)) { 1950448309eada01c130b2fee8977f7fd74875978cbcJack He Log.i(TAG, "updateAgIndicatorEnableState, no change in indicator state " 1951448309eada01c130b2fee8977f7fd74875978cbcJack He + mAgIndicatorEnableState); 1952448309eada01c130b2fee8977f7fd74875978cbcJack He return; 1953448309eada01c130b2fee8977f7fd74875978cbcJack He } 1954448309eada01c130b2fee8977f7fd74875978cbcJack He mAgIndicatorEnableState = agIndicatorEnableState; 1955448309eada01c130b2fee8977f7fd74875978cbcJack He int events = PhoneStateListener.LISTEN_NONE; 1956448309eada01c130b2fee8977f7fd74875978cbcJack He if (mAgIndicatorEnableState != null && mAgIndicatorEnableState.service) { 1957448309eada01c130b2fee8977f7fd74875978cbcJack He events |= PhoneStateListener.LISTEN_SERVICE_STATE; 1958448309eada01c130b2fee8977f7fd74875978cbcJack He } 1959448309eada01c130b2fee8977f7fd74875978cbcJack He if (mAgIndicatorEnableState != null && mAgIndicatorEnableState.signal) { 1960448309eada01c130b2fee8977f7fd74875978cbcJack He events |= PhoneStateListener.LISTEN_SIGNAL_STRENGTHS; 1961448309eada01c130b2fee8977f7fd74875978cbcJack He } 1962448309eada01c130b2fee8977f7fd74875978cbcJack He mSystemInterface.getHeadsetPhoneState().listenForPhoneState(mDevice, events); 1963448309eada01c130b2fee8977f7fd74875978cbcJack He } 1964448309eada01c130b2fee8977f7fd74875978cbcJack He 1965522d3b2b0a69c0157ca87995d92bb712f6102c1aWink Saville @Override 1966522d3b2b0a69c0157ca87995d92bb712f6102c1aWink Saville protected void log(String msg) { 19676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (DBG) { 1968522d3b2b0a69c0157ca87995d92bb712f6102c1aWink Saville super.log(msg); 19696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 19706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 19716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1972764073b18d2a0a44a021325db841a6b33e26241bJack He @Override 1973764073b18d2a0a44a021325db841a6b33e26241bJack He protected String getLogRecString(Message msg) { 1974764073b18d2a0a44a021325db841a6b33e26241bJack He StringBuilder builder = new StringBuilder(); 1975764073b18d2a0a44a021325db841a6b33e26241bJack He builder.append(getMessageName(msg.what)); 1976764073b18d2a0a44a021325db841a6b33e26241bJack He builder.append(": "); 1977764073b18d2a0a44a021325db841a6b33e26241bJack He builder.append("arg1=") 1978764073b18d2a0a44a021325db841a6b33e26241bJack He .append(msg.arg1) 1979764073b18d2a0a44a021325db841a6b33e26241bJack He .append(", arg2=") 1980764073b18d2a0a44a021325db841a6b33e26241bJack He .append(msg.arg2) 1981764073b18d2a0a44a021325db841a6b33e26241bJack He .append(", obj="); 1982764073b18d2a0a44a021325db841a6b33e26241bJack He if (msg.obj instanceof HeadsetMessageObject) { 1983764073b18d2a0a44a021325db841a6b33e26241bJack He HeadsetMessageObject object = (HeadsetMessageObject) msg.obj; 1984764073b18d2a0a44a021325db841a6b33e26241bJack He object.buildString(builder); 1985764073b18d2a0a44a021325db841a6b33e26241bJack He } else { 1986764073b18d2a0a44a021325db841a6b33e26241bJack He builder.append(msg.obj); 1987764073b18d2a0a44a021325db841a6b33e26241bJack He } 1988764073b18d2a0a44a021325db841a6b33e26241bJack He return builder.toString(); 1989764073b18d2a0a44a021325db841a6b33e26241bJack He } 1990764073b18d2a0a44a021325db841a6b33e26241bJack He 199150b51beb3bd0885ced514d1bcfda3050f60833ffJack He private void handleAccessPermissionResult(Intent intent) { 1992405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T log("handleAccessPermissionResult"); 199369d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 199450b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (!mPhonebook.getCheckingAccessPermission()) { 199550b51beb3bd0885ced514d1bcfda3050f60833ffJack He return; 199650b51beb3bd0885ced514d1bcfda3050f60833ffJack He } 199750b51beb3bd0885ced514d1bcfda3050f60833ffJack He int atCommandResult = 0; 199850b51beb3bd0885ced514d1bcfda3050f60833ffJack He int atCommandErrorCode = 0; 199950b51beb3bd0885ced514d1bcfda3050f60833ffJack He // HeadsetBase headset = mHandsfree.getHeadset(); 200050b51beb3bd0885ced514d1bcfda3050f60833ffJack He // ASSERT: (headset != null) && headSet.isConnected() 200150b51beb3bd0885ced514d1bcfda3050f60833ffJack He // REASON: mCheckingAccessPermission is true, otherwise resetAtState 200250b51beb3bd0885ced514d1bcfda3050f60833ffJack He // has set mCheckingAccessPermission to false 200350b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (intent.getAction().equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { 200450b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 200550b51beb3bd0885ced514d1bcfda3050f60833ffJack He BluetoothDevice.CONNECTION_ACCESS_NO) 200650b51beb3bd0885ced514d1bcfda3050f60833ffJack He == BluetoothDevice.CONNECTION_ACCESS_YES) { 200750b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 200867ccceab9600aaeec6dc34658c45c074de39aa38Jack He mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); 2009405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 201050b51beb3bd0885ced514d1bcfda3050f60833ffJack He atCommandResult = mPhonebook.processCpbrCommand(device); 2011fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee } else { 201250b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 201367ccceab9600aaeec6dc34658c45c074de39aa38Jack He mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED); 201450b51beb3bd0885ced514d1bcfda3050f60833ffJack He } 2015fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee } 201650b51beb3bd0885ced514d1bcfda3050f60833ffJack He } 201750b51beb3bd0885ced514d1bcfda3050f60833ffJack He mPhonebook.setCpbrIndex(-1); 201850b51beb3bd0885ced514d1bcfda3050f60833ffJack He mPhonebook.setCheckingAccessPermission(false); 201950b51beb3bd0885ced514d1bcfda3050f60833ffJack He if (atCommandResult >= 0) { 202050b51beb3bd0885ced514d1bcfda3050f60833ffJack He mNativeInterface.atResponseCode(device, atCommandResult, atCommandErrorCode); 2021fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee } else { 202250b51beb3bd0885ced514d1bcfda3050f60833ffJack He log("handleAccessPermissionResult - RESULT_NONE"); 2023405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 2024405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 2025122e077f24750ee0e7fd650cbfa832edeb216d07Jack He 202667ccceab9600aaeec6dc34658c45c074de39aa38Jack He private static String getMessageName(int what) { 2027122e077f24750ee0e7fd650cbfa832edeb216d07Jack He switch (what) { 2028122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT: 2029122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "CONNECT"; 2030122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT: 2031122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "DISCONNECT"; 2032122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_AUDIO: 2033122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "CONNECT_AUDIO"; 2034122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DISCONNECT_AUDIO: 2035122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "DISCONNECT_AUDIO"; 2036122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case VOICE_RECOGNITION_START: 2037122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "VOICE_RECOGNITION_START"; 2038122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case VOICE_RECOGNITION_STOP: 2039122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "VOICE_RECOGNITION_STOP"; 2040122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case INTENT_SCO_VOLUME_CHANGED: 2041122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "INTENT_SCO_VOLUME_CHANGED"; 204250b51beb3bd0885ced514d1bcfda3050f60833ffJack He case INTENT_CONNECTION_ACCESS_REPLY: 204350b51beb3bd0885ced514d1bcfda3050f60833ffJack He return "INTENT_CONNECTION_ACCESS_REPLY"; 2044122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CALL_STATE_CHANGED: 2045122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "CALL_STATE_CHANGED"; 2046122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case DEVICE_STATE_CHANGED: 2047122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "DEVICE_STATE_CHANGED"; 2048122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case SEND_CCLC_RESPONSE: 2049122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "SEND_CCLC_RESPONSE"; 2050122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case SEND_VENDOR_SPECIFIC_RESULT_CODE: 2051122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "SEND_VENDOR_SPECIFIC_RESULT_CODE"; 2052122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case STACK_EVENT: 2053122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "STACK_EVENT"; 2054ff5993924ef627e8b723d33ccb5514cb15bb134dJack He case VOICE_RECOGNITION_RESULT: 2055ff5993924ef627e8b723d33ccb5514cb15bb134dJack He return "VOICE_RECOGNITION_RESULT"; 2056a639b81f96c534c2f1066354b4a574c0dda2f713Jack He case DIALING_OUT_RESULT: 2057a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return "DIALING_OUT_RESULT"; 2058122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CLCC_RSP_TIMEOUT: 2059122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "CLCC_RSP_TIMEOUT"; 2060122e077f24750ee0e7fd650cbfa832edeb216d07Jack He case CONNECT_TIMEOUT: 2061122e077f24750ee0e7fd650cbfa832edeb216d07Jack He return "CONNECT_TIMEOUT"; 2062122e077f24750ee0e7fd650cbfa832edeb216d07Jack He default: 2063ff5993924ef627e8b723d33ccb5514cb15bb134dJack He return "UNKNOWN(" + what + ")"; 2064122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 2065122e077f24750ee0e7fd650cbfa832edeb216d07Jack He } 20666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie} 2067