HeadsetClientStateMachine.java revision 05462fe44531f887fe91ac173ec645e91b236025
1/* 2 * Copyright (c) 2014 The Android Open Source Project 3 * Copyright (C) 2012 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18/** 19 * Bluetooth Headset Client StateMachine 20 * (Disconnected) 21 * | ^ ^ 22 * CONNECT | | | DISCONNECTED 23 * V | | 24 * (Connecting) | 25 * | | 26 * CONNECTED | | DISCONNECT 27 * V | 28 * (Connected) 29 * | ^ 30 * CONNECT_AUDIO | | DISCONNECT_AUDIO 31 * V | 32 * (AudioOn) 33 */ 34 35package com.android.bluetooth.hfpclient; 36 37import android.bluetooth.BluetoothAdapter; 38import android.bluetooth.BluetoothDevice; 39import android.bluetooth.BluetoothHeadsetClient; 40import android.bluetooth.BluetoothHeadsetClientCall; 41import android.bluetooth.BluetoothProfile; 42import android.bluetooth.BluetoothUuid; 43import android.content.Context; 44import android.content.Intent; 45import android.media.AudioManager; 46import android.os.Bundle; 47import android.os.Message; 48import android.os.ParcelUuid; 49import android.os.SystemClock; 50import android.util.Log; 51import android.util.Pair; 52import android.telecom.TelecomManager; 53 54import com.android.bluetooth.Utils; 55import com.android.bluetooth.btservice.AdapterService; 56import com.android.bluetooth.btservice.ProfileService; 57import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService; 58import com.android.internal.util.IState; 59import com.android.internal.util.State; 60import com.android.internal.util.StateMachine; 61 62import java.util.ArrayList; 63import java.util.Arrays; 64import java.util.HashSet; 65import java.util.Hashtable; 66import java.util.Iterator; 67import java.util.LinkedList; 68import java.util.List; 69import java.util.Queue; 70import java.util.Set; 71 72import com.android.bluetooth.R; 73 74final class HeadsetClientStateMachine extends StateMachine { 75 private static final String TAG = "HeadsetClientStateMachine"; 76 private static final boolean DBG = false; 77 78 static final int NO_ACTION = 0; 79 80 // external actions 81 static final int CONNECT = 1; 82 static final int DISCONNECT = 2; 83 static final int CONNECT_AUDIO = 3; 84 static final int DISCONNECT_AUDIO = 4; 85 static final int VOICE_RECOGNITION_START = 5; 86 static final int VOICE_RECOGNITION_STOP = 6; 87 static final int SET_MIC_VOLUME = 7; 88 static final int SET_SPEAKER_VOLUME = 8; 89 static final int DIAL_NUMBER = 10; 90 static final int ACCEPT_CALL = 12; 91 static final int REJECT_CALL = 13; 92 static final int HOLD_CALL = 14; 93 static final int TERMINATE_CALL = 15; 94 static final int ENTER_PRIVATE_MODE = 16; 95 static final int SEND_DTMF = 17; 96 static final int EXPLICIT_CALL_TRANSFER = 18; 97 static final int LAST_VTAG_NUMBER = 19; 98 static final int DISABLE_NREC = 20; 99 100 // internal actions 101 static final int QUERY_CURRENT_CALLS = 50; 102 static final int QUERY_OPERATOR_NAME = 51; 103 static final int SUBSCRIBER_INFO = 52; 104 // special action to handle terminating specific call from multiparty call 105 static final int TERMINATE_SPECIFIC_CALL = 53; 106 107 static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec. 108 static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec. 109 110 private static final int STACK_EVENT = 100; 111 112 public static final Integer HF_ORIGINATED_CALL_ID = new Integer(-1); 113 private long OUTGOING_TIMEOUT_MILLI = 10 * 1000; // 10 seconds 114 115 private final Disconnected mDisconnected; 116 private final Connecting mConnecting; 117 private final Connected mConnected; 118 private final AudioOn mAudioOn; 119 120 private final HeadsetClientService mService; 121 122 // Set of calls that represent the accurate state of calls that exists on AG and the calls that 123 // are currently in process of being notified to the AG from HF. 124 private final Hashtable<Integer, BluetoothHeadsetClientCall> mCalls = new Hashtable<>(); 125 // Set of calls received from AG via the AT+CLCC command. We use this map to update the mCalls 126 // which is eventually used to inform the telephony stack of any changes to call on HF. 127 private final Hashtable<Integer, BluetoothHeadsetClientCall> mCallsUpdate = new Hashtable<>(); 128 129 private int mIndicatorNetworkState; 130 private int mIndicatorNetworkType; 131 private int mIndicatorNetworkSignal; 132 private int mIndicatorBatteryLevel; 133 134 private int mIndicatorCall; 135 private int mIndicatorCallSetup; 136 private int mIndicatorCallHeld; 137 private boolean mVgsFromStack = false; 138 private boolean mVgmFromStack = false; 139 140 private String mOperatorName; 141 private String mSubscriberInfo; 142 143 private int mVoiceRecognitionActive; 144 private int mInBandRingtone; 145 146 private int mMaxAmVcVol; 147 private int mMinAmVcVol; 148 149 // queue of send actions (pair action, action_data) 150 private Queue<Pair<Integer, Object>> mQueuedActions; 151 152 // last executed command, before action is complete e.g. waiting for some 153 // indicator 154 private Pair<Integer, Object> mPendingAction; 155 156 private final AudioManager mAudioManager; 157 private int mAudioState; 158 // Indicates whether audio can be routed to the device. 159 private boolean mAudioRouteAllowed; 160 private boolean mAudioWbs; 161 private final BluetoothAdapter mAdapter; 162 private boolean mNativeAvailable; 163 private TelecomManager mTelecomManager; 164 165 // currently connected device 166 private BluetoothDevice mCurrentDevice = null; 167 168 // general peer features and call handling features 169 private int mPeerFeatures; 170 private int mChldFeatures; 171 172 static { 173 classInitNative(); 174 } 175 176 public void dump(StringBuilder sb) { 177 ProfileService.println(sb, "mCurrentDevice: " + mCurrentDevice); 178 ProfileService.println(sb, "mAudioOn: " + mAudioOn); 179 ProfileService.println(sb, "mAudioState: " + mAudioState); 180 ProfileService.println(sb, "mAudioWbs: " + mAudioWbs); 181 ProfileService.println(sb, "mIndicatorNetworkState: " + mIndicatorNetworkState); 182 ProfileService.println(sb, "mIndicatorNetworkType: " + mIndicatorNetworkType); 183 ProfileService.println(sb, "mIndicatorNetworkSignal: " + mIndicatorNetworkSignal); 184 ProfileService.println(sb, "mIndicatorBatteryLevel: " + mIndicatorBatteryLevel); 185 ProfileService.println(sb, "mIndicatorCall: " + mIndicatorCall); 186 ProfileService.println(sb, "mIndicatorCallSetup: " + mIndicatorCallSetup); 187 ProfileService.println(sb, "mIndicatorCallHeld: " + mIndicatorCallHeld); 188 ProfileService.println(sb, "mVgsFromStack: " + mVgsFromStack); 189 ProfileService.println(sb, "mVgmFromStack: " + mVgmFromStack); 190 ProfileService.println(sb, "mOperatorName: " + mOperatorName); 191 ProfileService.println(sb, "mSubscriberInfo: " + mSubscriberInfo); 192 ProfileService.println(sb, "mVoiceRecognitionActive: " + mVoiceRecognitionActive); 193 ProfileService.println(sb, "mInBandRingtone: " + mInBandRingtone); 194 195 ProfileService.println(sb, "mCalls:"); 196 if (mCalls != null) { 197 for (BluetoothHeadsetClientCall call : mCalls.values()) { 198 ProfileService.println(sb, " " + call); 199 } 200 } 201 202 ProfileService.println(sb, "mCallsUpdate:"); 203 if (mCallsUpdate != null) { 204 for (BluetoothHeadsetClientCall call : mCallsUpdate.values()) { 205 ProfileService.println(sb, " " + call); 206 } 207 } 208 } 209 210 private void clearPendingAction() { 211 mPendingAction = new Pair<Integer, Object>(NO_ACTION, 0); 212 } 213 214 private void addQueuedAction(int action) { 215 addQueuedAction(action, 0); 216 } 217 218 private void addQueuedAction(int action, Object data) { 219 mQueuedActions.add(new Pair<Integer, Object>(action, data)); 220 } 221 222 private void addQueuedAction(int action, int data) { 223 mQueuedActions.add(new Pair<Integer, Object>(action, data)); 224 } 225 226 private BluetoothHeadsetClientCall getCall(int... states) { 227 if (DBG) { 228 Log.d(TAG, "getFromCallsWithStates states:" + Arrays.toString(states)); 229 } 230 for (BluetoothHeadsetClientCall c : mCalls.values()) { 231 for (int s : states) { 232 if (c.getState() == s) { 233 return c; 234 } 235 } 236 } 237 return null; 238 } 239 240 private int callsInState(int state) { 241 int i = 0; 242 for (BluetoothHeadsetClientCall c : mCalls.values()) { 243 if (c.getState() == state) { 244 i++; 245 } 246 } 247 248 return i; 249 } 250 251 private void updateCallsMultiParty() { 252 boolean multi = callsInState(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) > 1; 253 254 for (BluetoothHeadsetClientCall c : mCalls.values()) { 255 if (c.getState() == BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) { 256 if (c.isMultiParty() == multi) { 257 continue; 258 } 259 260 c.setMultiParty(multi); 261 sendCallChangedIntent(c); 262 } else { 263 if (c.isMultiParty()) { 264 c.setMultiParty(false); 265 sendCallChangedIntent(c); 266 } 267 } 268 } 269 } 270 271 private void setCallState(BluetoothHeadsetClientCall c, int state) { 272 if (state == c.getState()) { 273 return; 274 } 275 c.setState(state); 276 sendCallChangedIntent(c); 277 } 278 279 private void sendCallChangedIntent(BluetoothHeadsetClientCall c) { 280 if (DBG) { 281 Log.d(TAG, "sendCallChangedIntent " + c); 282 } 283 Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CALL_CHANGED); 284 intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c); 285 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 286 } 287 288 private void updateCallIndicator(int call) { 289 if (DBG) { 290 Log.d(TAG, "updateCallIndicator " + call); 291 } 292 mIndicatorCall = call; 293 sendMessage(QUERY_CURRENT_CALLS); 294 } 295 296 private void updateCallSetupIndicator(int callSetup) { 297 if (DBG) { 298 Log.d(TAG, "updateCallSetupIndicator " + callSetup + " " + mPendingAction.first); 299 } 300 mIndicatorCallSetup = callSetup; 301 sendMessage(QUERY_CURRENT_CALLS); 302 } 303 304 private void updateCallHeldIndicator(int callHeld) { 305 if (DBG) { 306 Log.d(TAG, "updateCallHeld " + callHeld); 307 } 308 mIndicatorCallHeld = callHeld; 309 sendMessage(QUERY_CURRENT_CALLS); 310 } 311 312 private void updateRespAndHold(int resp_and_hold) { 313 if (DBG) { 314 Log.d(TAG, "updatRespAndHold " + resp_and_hold); 315 } 316 sendMessage(QUERY_CURRENT_CALLS); 317 } 318 319 private void updateClip(String number) { 320 if (DBG) { 321 Log.d(TAG, "updateClip " + number); 322 } 323 sendMessage(QUERY_CURRENT_CALLS); 324 } 325 326 private void updateCCWA(String number) { 327 if (DBG) { 328 Log.d(TAG, "updateCCWA " + number); 329 } 330 sendMessage(QUERY_CURRENT_CALLS); 331 } 332 333 private boolean queryCallsStart() { 334 if (DBG) { 335 Log.d(TAG, "queryCallsStart"); 336 } 337 clearPendingAction(); 338 queryCurrentCallsNative(); 339 addQueuedAction(QUERY_CURRENT_CALLS, 0); 340 return true; 341 } 342 343 private void queryCallsDone() { 344 if (DBG) { 345 Log.d(TAG, "queryCallsDone"); 346 } 347 Iterator<Hashtable.Entry<Integer, BluetoothHeadsetClientCall>> it; 348 349 // mCalls has two types of calls: 350 // (a) Calls that are received from AG of a previous iteration of queryCallsStart() 351 // (b) Calls that are outgoing initiated from HF 352 // mCallsUpdate has all calls received from queryCallsUpdate() in current iteration of 353 // queryCallsStart(). 354 // 355 // We use the following steps to make sure that calls are update correctly. 356 // 357 // If there are no calls initiated from HF (i.e. ID = -1) then: 358 // 1. All IDs which are common in mCalls & mCallsUpdate are updated and the upper layers are 359 // informed of the change calls (if any changes). 360 // 2. All IDs that are in mCalls but *not* in mCallsUpdate will be removed from mCalls and 361 // the calls should be terminated 362 // 3. All IDs that are new in mCallsUpdated should be added as new calls to mCalls. 363 // 364 // If there is an outgoing HF call, it is important to associate that call with one of the 365 // mCallsUpdated calls hence, 366 // 1. If from the above procedure we get N extra calls (i.e. {3}): 367 // choose the first call as the one to associate with the HF call. 368 369 // Create set of IDs for added calls, removed calls and consitent calls. 370 // WARN!!! Java Map -> Set has association hence changes to Set are reflected in the Map 371 // itself (i.e. removing an element from Set removes it from the Map hence use copy). 372 Set<Integer> currCallIdSet = new HashSet<Integer>(); 373 currCallIdSet.addAll(mCalls.keySet()); 374 // Remove the entry for unassigned call. 375 currCallIdSet.remove(HF_ORIGINATED_CALL_ID); 376 377 Set<Integer> newCallIdSet = new HashSet<Integer>(); 378 newCallIdSet.addAll(mCallsUpdate.keySet()); 379 380 // Added. 381 Set<Integer> callAddedIds = new HashSet<Integer>(); 382 callAddedIds.addAll(newCallIdSet); 383 callAddedIds.removeAll(currCallIdSet); 384 385 // Removed. 386 Set<Integer> callRemovedIds = new HashSet<Integer>(); 387 callRemovedIds.addAll(currCallIdSet); 388 callRemovedIds.removeAll(newCallIdSet); 389 390 // Retained. 391 Set<Integer> callRetainedIds = new HashSet<Integer>(); 392 callRetainedIds.addAll(currCallIdSet); 393 callRetainedIds.retainAll(newCallIdSet); 394 395 if (DBG) { 396 Log.d(TAG, "currCallIdSet " + mCalls.keySet() + " newCallIdSet " + newCallIdSet + 397 " callAddedIds " + callAddedIds + " callRemovedIds " + callRemovedIds + 398 " callRetainedIds " + callRetainedIds); 399 } 400 401 // First thing is to try to associate the outgoing HF with a valid call. 402 Integer hfOriginatedAssoc = -1; 403 if (mCalls.containsKey(HF_ORIGINATED_CALL_ID)) { 404 BluetoothHeadsetClientCall c = mCalls.get(HF_ORIGINATED_CALL_ID); 405 long cCreationElapsed = c.getCreationElapsedMilli(); 406 if (callAddedIds.size() > 0) { 407 if (DBG) { 408 Log.d(TAG, "Associating the first call with HF originated call"); 409 } 410 hfOriginatedAssoc = (Integer) callAddedIds.toArray()[0]; 411 mCalls.put(hfOriginatedAssoc, mCalls.get(HF_ORIGINATED_CALL_ID)); 412 mCalls.remove(HF_ORIGINATED_CALL_ID); 413 414 // Adjust this call in above sets. 415 callAddedIds.remove(hfOriginatedAssoc); 416 callRetainedIds.add(hfOriginatedAssoc); 417 } else if (SystemClock.elapsedRealtime() - cCreationElapsed > OUTGOING_TIMEOUT_MILLI) { 418 Log.w(TAG, "Outgoing call did not see a response, clear the calls and send CHUP"); 419 terminateCall(); 420 421 // Clean out the state. 422 for (Integer idx : mCalls.keySet()) { 423 BluetoothHeadsetClientCall c1 = mCalls.get(idx); 424 c1.setState(BluetoothHeadsetClientCall.CALL_STATE_TERMINATED); 425 sendCallChangedIntent(c); 426 } 427 mCalls.clear(); 428 } 429 } 430 431 if (DBG) { 432 Log.d(TAG, "ADJUST: currCallIdSet " + mCalls.keySet() + " newCallIdSet " + 433 newCallIdSet + " callAddedIds " + callAddedIds + " callRemovedIds " + 434 callRemovedIds + " callRetainedIds " + callRetainedIds); 435 } 436 437 // Terminate & remove the calls that are done. 438 for (Integer idx : callRemovedIds) { 439 BluetoothHeadsetClientCall c = mCalls.remove(idx); 440 c.setState(BluetoothHeadsetClientCall.CALL_STATE_TERMINATED); 441 sendCallChangedIntent(c); 442 } 443 444 // Add the new calls. 445 for (Integer idx : callAddedIds) { 446 BluetoothHeadsetClientCall c = mCallsUpdate.get(idx); 447 mCalls.put(idx, c); 448 sendCallChangedIntent(c); 449 } 450 451 // Update the existing calls. 452 for (Integer idx : callRetainedIds) { 453 BluetoothHeadsetClientCall cOrig = mCalls.get(idx); 454 BluetoothHeadsetClientCall cUpdate = mCallsUpdate.get(idx); 455 456 // Update the necessary fields. 457 cOrig.setNumber(cUpdate.getNumber()); 458 cOrig.setState(cUpdate.getState()); 459 cOrig.setMultiParty(cUpdate.isMultiParty()); 460 461 // Send update with original object (UUID, idx). 462 sendCallChangedIntent(cOrig); 463 } 464 465 if (loopQueryCalls()) { 466 sendMessageDelayed(QUERY_CURRENT_CALLS, 1523); 467 } 468 469 mCallsUpdate.clear(); 470 } 471 472 private void queryCallsUpdate(int id, int state, String number, boolean multiParty, 473 boolean outgoing) { 474 if (DBG) { 475 Log.d(TAG, "queryCallsUpdate: " + id); 476 } 477 mCallsUpdate.put(id, new BluetoothHeadsetClientCall(mCurrentDevice, id, state, number, 478 multiParty, outgoing)); 479 } 480 481 // helper function for determining if query calls should be looped 482 private boolean loopQueryCalls() { 483 if (DBG) { 484 Log.d(TAG, "loopQueryCalls, starting call query loop"); 485 } 486 if (mCalls.size() > 0) { 487 return true; 488 } 489 490 // Workaround for Windows Phone 7.8 not sending callsetup=0 after 491 // rejecting incoming call in 3WC use case (when no active calls present). 492 // Fixes both, AG and HF rejecting the call. 493 BluetoothHeadsetClientCall c = getCall(BluetoothHeadsetClientCall.CALL_STATE_INCOMING); 494 if (c != null && mIndicatorCallSetup == HeadsetClientHalConstants.CALLSETUP_NONE) 495 return true; 496 497 return false; 498 } 499 500 private void acceptCall(int flag, boolean retry) { 501 int action; 502 503 if (DBG) { 504 Log.d(TAG, "acceptCall: (" + flag + ")"); 505 } 506 507 BluetoothHeadsetClientCall c = getCall(BluetoothHeadsetClientCall.CALL_STATE_INCOMING, 508 BluetoothHeadsetClientCall.CALL_STATE_WAITING); 509 if (c == null) { 510 c = getCall(BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD, 511 BluetoothHeadsetClientCall.CALL_STATE_HELD); 512 513 if (c == null) { 514 return; 515 } 516 } 517 518 switch (c.getState()) { 519 case BluetoothHeadsetClientCall.CALL_STATE_INCOMING: 520 if (flag != BluetoothHeadsetClient.CALL_ACCEPT_NONE) { 521 return; 522 } 523 524 // Some NOKIA phones with Windows Phone 7.8 and MeeGo requires CHLD=1 525 // for accepting incoming call if it is the only call present after 526 // second active remote has disconnected (3WC scenario - call state 527 // changes from waiting to incoming). On the other hand some Android 528 // phones and iPhone requires ATA. Try to handle those gently by 529 // first issuing ATA. Failing means that AG is probably one of those 530 // phones that requires CHLD=1. Handle this case when we are retrying. 531 // Accepting incoming calls when there is held one and 532 // no active should also be handled by ATA. 533 action = HeadsetClientHalConstants.CALL_ACTION_ATA; 534 535 if (mCalls.size() == 1 && retry) { 536 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1; 537 } 538 break; 539 case BluetoothHeadsetClientCall.CALL_STATE_WAITING: 540 if (callsInState(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) == 0) { 541 // if no active calls present only plain accept is allowed 542 if (flag != BluetoothHeadsetClient.CALL_ACCEPT_NONE) { 543 return; 544 } 545 546 // Some phones (WP7) require ATA instead of CHLD=2 547 // to accept waiting call if no active calls are present. 548 if (retry) { 549 action = HeadsetClientHalConstants.CALL_ACTION_ATA; 550 } else { 551 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; 552 } 553 break; 554 } 555 556 // if active calls are present action must be selected 557 if (flag == BluetoothHeadsetClient.CALL_ACCEPT_HOLD) { 558 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; 559 } else if (flag == BluetoothHeadsetClient.CALL_ACCEPT_TERMINATE) { 560 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1; 561 } else { 562 return; 563 } 564 break; 565 case BluetoothHeadsetClientCall.CALL_STATE_HELD: 566 if (flag == BluetoothHeadsetClient.CALL_ACCEPT_HOLD) { 567 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; 568 } else if (flag == BluetoothHeadsetClient.CALL_ACCEPT_TERMINATE) { 569 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1; 570 } else if (getCall(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) != null) { 571 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_3; 572 } else { 573 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; 574 } 575 break; 576 case BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: 577 action = HeadsetClientHalConstants.CALL_ACTION_BTRH_1; 578 break; 579 case BluetoothHeadsetClientCall.CALL_STATE_ALERTING: 580 case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: 581 case BluetoothHeadsetClientCall.CALL_STATE_DIALING: 582 default: 583 return; 584 } 585 586 if (handleCallActionNative(action, 0)) { 587 addQueuedAction(ACCEPT_CALL, action); 588 } else { 589 Log.e(TAG, "ERROR: Couldn't accept a call, action:" + action); 590 } 591 } 592 593 private void rejectCall() { 594 int action; 595 596 if (DBG) { 597 Log.d(TAG, "rejectCall"); 598 } 599 600 BluetoothHeadsetClientCall c = 601 getCall(BluetoothHeadsetClientCall.CALL_STATE_INCOMING, 602 BluetoothHeadsetClientCall.CALL_STATE_WAITING, 603 BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD, 604 BluetoothHeadsetClientCall.CALL_STATE_HELD); 605 if (c == null) { 606 return; 607 } 608 609 switch (c.getState()) { 610 case BluetoothHeadsetClientCall.CALL_STATE_INCOMING: 611 action = HeadsetClientHalConstants.CALL_ACTION_CHUP; 612 break; 613 case BluetoothHeadsetClientCall.CALL_STATE_WAITING: 614 case BluetoothHeadsetClientCall.CALL_STATE_HELD: 615 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_0; 616 break; 617 case BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: 618 action = HeadsetClientHalConstants.CALL_ACTION_BTRH_2; 619 break; 620 case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: 621 case BluetoothHeadsetClientCall.CALL_STATE_DIALING: 622 case BluetoothHeadsetClientCall.CALL_STATE_ALERTING: 623 default: 624 return; 625 } 626 627 if (handleCallActionNative(action, 0)) { 628 addQueuedAction(REJECT_CALL, action); 629 } else { 630 Log.e(TAG, "ERROR: Couldn't reject a call, action:" + action); 631 } 632 } 633 634 private void holdCall() { 635 int action; 636 637 if (DBG) { 638 Log.d(TAG, "holdCall"); 639 } 640 641 BluetoothHeadsetClientCall c = getCall(BluetoothHeadsetClientCall.CALL_STATE_INCOMING); 642 if (c != null) { 643 action = HeadsetClientHalConstants.CALL_ACTION_BTRH_0; 644 } else { 645 c = getCall(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE); 646 if (c == null) { 647 return; 648 } 649 650 action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; 651 } 652 653 if (handleCallActionNative(action, 0)) { 654 addQueuedAction(HOLD_CALL, action); 655 } else { 656 Log.e(TAG, "ERROR: Couldn't hold a call, action:" + action); 657 } 658 } 659 660 private void terminateCall() { 661 if (DBG) { 662 Log.d(TAG, "terminateCall"); 663 } 664 665 int action = HeadsetClientHalConstants.CALL_ACTION_CHUP; 666 667 BluetoothHeadsetClientCall c = getCall( 668 BluetoothHeadsetClientCall.CALL_STATE_DIALING, 669 BluetoothHeadsetClientCall.CALL_STATE_ALERTING, 670 BluetoothHeadsetClientCall.CALL_STATE_ACTIVE); 671 if (c != null) { 672 if (handleCallActionNative(action, 0)) { 673 addQueuedAction(TERMINATE_CALL, action); 674 } else { 675 Log.e(TAG, "ERROR: Couldn't terminate outgoing call"); 676 } 677 } 678 } 679 680 private void enterPrivateMode(int idx) { 681 if (DBG) { 682 Log.d(TAG, "enterPrivateMode: " + idx); 683 } 684 685 BluetoothHeadsetClientCall c = mCalls.get(idx); 686 687 if (c == null) { 688 return; 689 } 690 691 if (c.getState() != BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) { 692 return; 693 } 694 695 if (!c.isMultiParty()) { 696 return; 697 } 698 699 if (handleCallActionNative(HeadsetClientHalConstants.CALL_ACTION_CHLD_2x, idx)) { 700 addQueuedAction(ENTER_PRIVATE_MODE, c); 701 } else { 702 Log.e(TAG, "ERROR: Couldn't enter private " + " id:" + idx); 703 } 704 } 705 706 private void explicitCallTransfer() { 707 if (DBG) { 708 Log.d(TAG, "explicitCallTransfer"); 709 } 710 711 // can't transfer call if there is not enough call parties 712 if (mCalls.size() < 2) { 713 return; 714 } 715 716 if (handleCallActionNative(HeadsetClientHalConstants.CALL_ACTION_CHLD_4, -1)) { 717 addQueuedAction(EXPLICIT_CALL_TRANSFER); 718 } else { 719 Log.e(TAG, "ERROR: Couldn't transfer call"); 720 } 721 } 722 723 public Bundle getCurrentAgFeatures() 724 { 725 Bundle b = new Bundle(); 726 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_3WAY) == 727 HeadsetClientHalConstants.PEER_FEAT_3WAY) { 728 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_3WAY_CALLING, true); 729 } 730 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_VREC) == 731 HeadsetClientHalConstants.PEER_FEAT_VREC) { 732 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_VOICE_RECOGNITION, true); 733 } 734 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_VTAG) == 735 HeadsetClientHalConstants.PEER_FEAT_VTAG) { 736 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT, true); 737 } 738 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_REJECT) == 739 HeadsetClientHalConstants.PEER_FEAT_REJECT) { 740 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_REJECT_CALL, true); 741 } 742 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECC) == 743 HeadsetClientHalConstants.PEER_FEAT_ECC) { 744 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ECC, true); 745 } 746 747 // add individual CHLD support extras 748 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC) == 749 HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC) { 750 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL, true); 751 } 752 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_REL) == 753 HeadsetClientHalConstants.CHLD_FEAT_REL) { 754 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL, true); 755 } 756 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_REL_ACC) == 757 HeadsetClientHalConstants.CHLD_FEAT_REL_ACC) { 758 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT, true); 759 } 760 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_MERGE) == 761 HeadsetClientHalConstants.CHLD_FEAT_MERGE) { 762 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE, true); 763 } 764 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) == 765 HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) { 766 b.putBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH, true); 767 } 768 769 return b; 770 } 771 772 private HeadsetClientStateMachine(HeadsetClientService context) { 773 super(TAG); 774 mService = context; 775 776 mAdapter = BluetoothAdapter.getDefaultAdapter(); 777 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 778 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 779 mAudioWbs = false; 780 781 mAudioRouteAllowed = context.getResources().getBoolean( 782 R.bool.headset_client_initial_audio_route_allowed); 783 784 mTelecomManager = (TelecomManager) context.getSystemService(context.TELECOM_SERVICE); 785 786 mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE; 787 mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME; 788 mIndicatorNetworkSignal = 0; 789 mIndicatorBatteryLevel = 0; 790 791 // all will be set on connected 792 mIndicatorCall = -1; 793 mIndicatorCallSetup = -1; 794 mIndicatorCallHeld = -1; 795 796 mMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL); 797 mMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL); 798 799 mOperatorName = null; 800 mSubscriberInfo = null; 801 802 mVoiceRecognitionActive = HeadsetClientHalConstants.VR_STATE_STOPPED; 803 mInBandRingtone = HeadsetClientHalConstants.IN_BAND_RING_NOT_PROVIDED; 804 805 mQueuedActions = new LinkedList<Pair<Integer, Object>>(); 806 clearPendingAction(); 807 808 mCalls.clear(); 809 mCallsUpdate.clear(); 810 811 initializeNative(); 812 mNativeAvailable = true; 813 814 mDisconnected = new Disconnected(); 815 mConnecting = new Connecting(); 816 mConnected = new Connected(); 817 mAudioOn = new AudioOn(); 818 819 addState(mDisconnected); 820 addState(mConnecting); 821 addState(mConnected); 822 addState(mAudioOn, mConnected); 823 824 setInitialState(mDisconnected); 825 } 826 827 static HeadsetClientStateMachine make(HeadsetClientService context) { 828 if (DBG) { 829 Log.d(TAG, "make"); 830 } 831 HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context); 832 hfcsm.start(); 833 return hfcsm; 834 } 835 836 public void doQuit() { 837 quitNow(); 838 } 839 840 public void cleanup() { 841 if (mNativeAvailable) { 842 cleanupNative(); 843 mNativeAvailable = false; 844 } 845 } 846 847 private int hfToAmVol(int hfVol) { 848 int amRange = mMaxAmVcVol - mMinAmVcVol; 849 int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; 850 int amOffset = 851 (amRange * (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME)) / hfRange; 852 int amVol = mMinAmVcVol + amOffset; 853 Log.d(TAG, "HF -> AM " + hfVol + " " + amVol); 854 return amVol; 855 } 856 857 private int amToHfVol(int amVol) { 858 int amRange = mMaxAmVcVol - mMinAmVcVol; 859 int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; 860 int hfOffset = (hfRange * (amVol - mMinAmVcVol)) / amRange; 861 int hfVol = MIN_HFP_SCO_VOICE_CALL_VOLUME + hfOffset; 862 Log.d(TAG, "AM -> HF " + amVol + " " + hfVol); 863 return hfVol; 864 } 865 866 private class Disconnected extends State { 867 @Override 868 public void enter() { 869 Log.d(TAG, "Enter Disconnected: " + getCurrentMessage().what); 870 871 // cleanup 872 mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE; 873 mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME; 874 mIndicatorNetworkSignal = 0; 875 mIndicatorBatteryLevel = 0; 876 877 mAudioWbs = false; 878 879 // will be set on connect 880 mIndicatorCall = -1; 881 mIndicatorCallSetup = -1; 882 mIndicatorCallHeld = -1; 883 884 mOperatorName = null; 885 mSubscriberInfo = null; 886 887 mQueuedActions = new LinkedList<Pair<Integer, Object>>(); 888 clearPendingAction(); 889 890 mVoiceRecognitionActive = HeadsetClientHalConstants.VR_STATE_STOPPED; 891 mInBandRingtone = HeadsetClientHalConstants.IN_BAND_RING_NOT_PROVIDED; 892 893 mCalls.clear(); 894 mCallsUpdate.clear(); 895 896 mPeerFeatures = 0; 897 mChldFeatures = 0; 898 899 removeMessages(QUERY_CURRENT_CALLS); 900 } 901 902 @Override 903 public synchronized boolean processMessage(Message message) { 904 Log.d(TAG, "Disconnected process message: " + message.what); 905 906 if (mCurrentDevice != null) { 907 Log.e(TAG, "ERROR: current device not null in Disconnected"); 908 return NOT_HANDLED; 909 } 910 911 switch (message.what) { 912 case CONNECT: 913 BluetoothDevice device = (BluetoothDevice) message.obj; 914 915 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 916 BluetoothProfile.STATE_DISCONNECTED); 917 918 if (!connectNative(getByteAddress(device))) { 919 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 920 BluetoothProfile.STATE_CONNECTING); 921 break; 922 } 923 924 mCurrentDevice = device; 925 transitionTo(mConnecting); 926 break; 927 case DISCONNECT: 928 // ignore 929 break; 930 case STACK_EVENT: 931 StackEvent event = (StackEvent) message.obj; 932 if (DBG) { 933 Log.d(TAG, "Stack event type: " + event.type); 934 } 935 switch (event.type) { 936 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 937 if (DBG) { 938 Log.d(TAG, "Disconnected: Connection " + event.device 939 + " state changed:" + event.valueInt); 940 } 941 processConnectionEvent(event.valueInt, event.device); 942 break; 943 default: 944 Log.e(TAG, "Disconnected: Unexpected stack event: " + event.type); 945 break; 946 } 947 break; 948 default: 949 return NOT_HANDLED; 950 } 951 return HANDLED; 952 } 953 954 // in Disconnected state 955 private void processConnectionEvent(int state, BluetoothDevice device) 956 { 957 switch (state) { 958 case HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED: 959 Log.w(TAG, "HFPClient Connecting from Disconnected state"); 960 if (okToConnect(device)) { 961 Log.i(TAG, "Incoming AG accepted"); 962 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 963 BluetoothProfile.STATE_DISCONNECTED); 964 mCurrentDevice = device; 965 transitionTo(mConnecting); 966 } else { 967 Log.i(TAG, "Incoming AG rejected. priority=" + mService.getPriority(device) 968 + 969 " bondState=" + device.getBondState()); 970 // reject the connection and stay in Disconnected state 971 // itself 972 disconnectNative(getByteAddress(device)); 973 // the other profile connection should be initiated 974 AdapterService adapterService = AdapterService.getAdapterService(); 975 if (adapterService != null) { 976 adapterService.connectOtherProfile(device, 977 AdapterService.PROFILE_CONN_REJECTED); 978 } 979 } 980 break; 981 case HeadsetClientHalConstants.CONNECTION_STATE_CONNECTING: 982 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED: 983 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTING: 984 default: 985 Log.i(TAG, "ignoring state: " + state); 986 break; 987 } 988 } 989 990 @Override 991 public void exit() { 992 if (DBG) { 993 Log.d(TAG, "Exit Disconnected: " + getCurrentMessage().what); 994 } 995 } 996 } 997 998 private class Connecting extends State { 999 @Override 1000 public void enter() { 1001 if (DBG) { 1002 Log.d(TAG, "Enter Connecting: " + getCurrentMessage().what); 1003 } 1004 } 1005 1006 @Override 1007 public synchronized boolean processMessage(Message message) { 1008 if (DBG) { 1009 Log.d(TAG, "Connecting process message: " + message.what); 1010 } 1011 1012 boolean retValue = HANDLED; 1013 switch (message.what) { 1014 case CONNECT: 1015 case CONNECT_AUDIO: 1016 case DISCONNECT: 1017 deferMessage(message); 1018 break; 1019 case STACK_EVENT: 1020 StackEvent event = (StackEvent) message.obj; 1021 if (DBG) { 1022 Log.d(TAG, "Connecting: event type: " + event.type); 1023 } 1024 switch (event.type) { 1025 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 1026 if (DBG) { 1027 Log.d(TAG, "Connecting: Connection " + event.device + " state changed:" 1028 + event.valueInt); 1029 } 1030 processConnectionEvent(event.valueInt, event.valueInt2, 1031 event.valueInt3, event.device); 1032 break; 1033 case EVENT_TYPE_AUDIO_STATE_CHANGED: 1034 case EVENT_TYPE_VR_STATE_CHANGED: 1035 case EVENT_TYPE_NETWORK_STATE: 1036 case EVENT_TYPE_ROAMING_STATE: 1037 case EVENT_TYPE_NETWORK_SIGNAL: 1038 case EVENT_TYPE_BATTERY_LEVEL: 1039 case EVENT_TYPE_CALL: 1040 case EVENT_TYPE_CALLSETUP: 1041 case EVENT_TYPE_CALLHELD: 1042 case EVENT_TYPE_RESP_AND_HOLD: 1043 case EVENT_TYPE_CLIP: 1044 case EVENT_TYPE_CALL_WAITING: 1045 case EVENT_TYPE_VOLUME_CHANGED: 1046 case EVENT_TYPE_IN_BAND_RING: 1047 deferMessage(message); 1048 break; 1049 case EVENT_TYPE_CMD_RESULT: 1050 case EVENT_TYPE_SUBSCRIBER_INFO: 1051 case EVENT_TYPE_CURRENT_CALLS: 1052 case EVENT_TYPE_OPERATOR_NAME: 1053 default: 1054 Log.e(TAG, "Connecting: ignoring stack event: " + event.type); 1055 break; 1056 } 1057 break; 1058 default: 1059 return NOT_HANDLED; 1060 } 1061 return retValue; 1062 } 1063 1064 // in Connecting state 1065 private void processConnectionEvent( 1066 int state, int peer_feat, int chld_feat, BluetoothDevice device) { 1067 switch (state) { 1068 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED: 1069 broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_DISCONNECTED, 1070 BluetoothProfile.STATE_CONNECTING); 1071 mCurrentDevice = null; 1072 transitionTo(mDisconnected); 1073 break; 1074 1075 case HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED: 1076 Log.w(TAG, "HFPClient Connected from Connecting state"); 1077 1078 mPeerFeatures = peer_feat; 1079 mChldFeatures = chld_feat; 1080 1081 // We do not support devices which do not support enhanced call status (ECS). 1082 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECS) == 0) { 1083 disconnectNative(getByteAddress(device)); 1084 return; 1085 } 1086 1087 broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, 1088 BluetoothProfile.STATE_CONNECTING); 1089 1090 // Send AT+NREC to remote if supported by audio 1091 if (HeadsetClientHalConstants.HANDSFREECLIENT_NREC_SUPPORTED && 1092 ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECNR) == 1093 HeadsetClientHalConstants.PEER_FEAT_ECNR)) { 1094 if (sendATCmdNative(HeadsetClientHalConstants.HANDSFREECLIENT_AT_CMD_NREC, 1095 1 , 0, null)) { 1096 addQueuedAction(DISABLE_NREC); 1097 } else { 1098 Log.e(TAG, "Failed to send NREC"); 1099 } 1100 } 1101 transitionTo(mConnected); 1102 1103 int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); 1104 sendMessage( 1105 obtainMessage(HeadsetClientStateMachine.SET_SPEAKER_VOLUME, amVol, 0)); 1106 // Mic is either in ON state (full volume) or OFF state. There is no way in 1107 // Android to change the MIC volume. 1108 sendMessage(obtainMessage(HeadsetClientStateMachine.SET_MIC_VOLUME, 1109 mAudioManager.isMicrophoneMute() ? 0 : 15, 0)); 1110 1111 // query subscriber info 1112 sendMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO); 1113 break; 1114 1115 case HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED: 1116 if (!mCurrentDevice.equals(device)) { 1117 Log.w(TAG, "incoming connection event, device: " + device); 1118 1119 broadcastConnectionState(mCurrentDevice, 1120 BluetoothProfile.STATE_DISCONNECTED, 1121 BluetoothProfile.STATE_CONNECTING); 1122 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 1123 BluetoothProfile.STATE_DISCONNECTED); 1124 1125 mCurrentDevice = device; 1126 } 1127 break; 1128 case HeadsetClientHalConstants.CONNECTION_STATE_CONNECTING: 1129 /* outgoing connecting started */ 1130 if (DBG) { 1131 Log.d(TAG, "outgoing connection started, ignore"); 1132 } 1133 break; 1134 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTING: 1135 default: 1136 Log.e(TAG, "Incorrect state: " + state); 1137 break; 1138 } 1139 } 1140 1141 @Override 1142 public void exit() { 1143 if (DBG) { 1144 Log.d(TAG, "Exit Connecting: " + getCurrentMessage().what); 1145 } 1146 } 1147 } 1148 1149 private class Connected extends State { 1150 @Override 1151 public void enter() { 1152 if (DBG) { 1153 Log.d(TAG, "Enter Connected: " + getCurrentMessage().what); 1154 } 1155 1156 mAudioWbs = false; 1157 } 1158 1159 @Override 1160 public synchronized boolean processMessage(Message message) { 1161 if (DBG) { 1162 Log.d(TAG, "Connected process message: " + message.what); 1163 } 1164 if (DBG) { 1165 if (mCurrentDevice == null) { 1166 Log.e(TAG, "ERROR: mCurrentDevice is null in Connected"); 1167 return NOT_HANDLED; 1168 } 1169 } 1170 1171 switch (message.what) { 1172 case CONNECT: 1173 BluetoothDevice device = (BluetoothDevice) message.obj; 1174 if (mCurrentDevice.equals(device)) { 1175 // already connected to this device, do nothing 1176 break; 1177 } 1178 1179 if (!disconnectNative(getByteAddress(mCurrentDevice))) { 1180 // if succeed this will be handled from disconnected 1181 // state 1182 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 1183 BluetoothProfile.STATE_DISCONNECTED); 1184 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 1185 BluetoothProfile.STATE_CONNECTING); 1186 break; 1187 } 1188 1189 // will be handled when entered disconnected 1190 deferMessage(message); 1191 break; 1192 case DISCONNECT: 1193 BluetoothDevice dev = (BluetoothDevice) message.obj; 1194 if (!mCurrentDevice.equals(dev)) { 1195 break; 1196 } 1197 broadcastConnectionState(dev, BluetoothProfile.STATE_DISCONNECTING, 1198 BluetoothProfile.STATE_CONNECTED); 1199 if (!disconnectNative(getByteAddress(dev))) { 1200 // disconnecting failed 1201 broadcastConnectionState(dev, BluetoothProfile.STATE_CONNECTED, 1202 BluetoothProfile.STATE_DISCONNECTED); 1203 break; 1204 } 1205 break; 1206 case CONNECT_AUDIO: 1207 // TODO: handle audio connection failure 1208 if (!connectAudioNative(getByteAddress(mCurrentDevice))) { 1209 Log.e(TAG, "ERROR: Couldn't connect Audio."); 1210 } 1211 break; 1212 case DISCONNECT_AUDIO: 1213 // TODO: handle audio disconnection failure 1214 if (!disconnectAudioNative(getByteAddress(mCurrentDevice))) { 1215 Log.e(TAG, "ERROR: Couldn't connect Audio."); 1216 } 1217 break; 1218 case VOICE_RECOGNITION_START: 1219 if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STOPPED) { 1220 if (startVoiceRecognitionNative()) { 1221 addQueuedAction(VOICE_RECOGNITION_START); 1222 } else { 1223 Log.e(TAG, "ERROR: Couldn't start voice recognition"); 1224 } 1225 } 1226 break; 1227 case VOICE_RECOGNITION_STOP: 1228 if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STARTED) { 1229 if (stopVoiceRecognitionNative()) { 1230 addQueuedAction(VOICE_RECOGNITION_STOP); 1231 } else { 1232 Log.e(TAG, "ERROR: Couldn't stop voice recognition"); 1233 } 1234 } 1235 break; 1236 // Called only for Mute/Un-mute - Mic volume change is not allowed. 1237 case SET_MIC_VOLUME: 1238 if (mVgmFromStack) { 1239 mVgmFromStack = false; 1240 break; 1241 } 1242 if (setVolumeNative(HeadsetClientHalConstants.VOLUME_TYPE_MIC, message.arg1)) { 1243 addQueuedAction(SET_MIC_VOLUME); 1244 } 1245 break; 1246 case SET_SPEAKER_VOLUME: 1247 // This message should always contain the volume in AudioManager max normalized. 1248 int amVol = message.arg1; 1249 int hfVol = amToHfVol(amVol); 1250 Log.d(TAG,"HF volume is set to " + hfVol); 1251 mAudioManager.setParameters("hfp_volume=" + hfVol); 1252 if (mVgsFromStack) { 1253 mVgsFromStack = false; 1254 break; 1255 } 1256 if (setVolumeNative(HeadsetClientHalConstants.VOLUME_TYPE_SPK, hfVol)) { 1257 addQueuedAction(SET_SPEAKER_VOLUME); 1258 } 1259 break; 1260 case DIAL_NUMBER: 1261 // Add the call as an outgoing call. 1262 BluetoothHeadsetClientCall c = (BluetoothHeadsetClientCall) message.obj; 1263 mCalls.put(HF_ORIGINATED_CALL_ID, c); 1264 1265 if (dialNative(c.getNumber())) { 1266 addQueuedAction(DIAL_NUMBER, c.getNumber()); 1267 // Start looping on calling current calls. 1268 sendMessage(QUERY_CURRENT_CALLS); 1269 } else { 1270 Log.e(TAG, "ERROR: Cannot dial with a given number:" + (String) message.obj); 1271 // Set the call to terminated remove. 1272 c.setState(BluetoothHeadsetClientCall.CALL_STATE_TERMINATED); 1273 sendCallChangedIntent(c); 1274 mCalls.remove(HF_ORIGINATED_CALL_ID); 1275 } 1276 break; 1277 case ACCEPT_CALL: 1278 acceptCall(message.arg1, false); 1279 break; 1280 case REJECT_CALL: 1281 rejectCall(); 1282 break; 1283 case HOLD_CALL: 1284 holdCall(); 1285 break; 1286 case TERMINATE_CALL: 1287 terminateCall(); 1288 break; 1289 case ENTER_PRIVATE_MODE: 1290 enterPrivateMode(message.arg1); 1291 break; 1292 case EXPLICIT_CALL_TRANSFER: 1293 explicitCallTransfer(); 1294 break; 1295 case SEND_DTMF: 1296 if (sendDtmfNative((byte) message.arg1)) { 1297 addQueuedAction(SEND_DTMF); 1298 } else { 1299 Log.e(TAG, "ERROR: Couldn't send DTMF"); 1300 } 1301 break; 1302 case SUBSCRIBER_INFO: 1303 if (retrieveSubscriberInfoNative()) { 1304 addQueuedAction(SUBSCRIBER_INFO); 1305 } else { 1306 Log.e(TAG, "ERROR: Couldn't retrieve subscriber info"); 1307 } 1308 break; 1309 case LAST_VTAG_NUMBER: 1310 if (requestLastVoiceTagNumberNative()) { 1311 addQueuedAction(LAST_VTAG_NUMBER); 1312 } else { 1313 Log.e(TAG, "ERROR: Couldn't get last VTAG number"); 1314 } 1315 break; 1316 case QUERY_CURRENT_CALLS: 1317 queryCallsStart(); 1318 break; 1319 case STACK_EVENT: 1320 Intent intent = null; 1321 StackEvent event = (StackEvent) message.obj; 1322 if (DBG) { 1323 Log.d(TAG, "Connected: event type: " + event.type); 1324 } 1325 1326 switch (event.type) { 1327 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 1328 if (DBG) { 1329 Log.d(TAG, "Connected: Connection state changed: " + event.device 1330 + ": " + event.valueInt); 1331 } 1332 processConnectionEvent(event.valueInt, event.device); 1333 break; 1334 case EVENT_TYPE_AUDIO_STATE_CHANGED: 1335 if (DBG) { 1336 Log.d(TAG, "Connected: Audio state changed: " + event.device + ": " 1337 + event.valueInt); 1338 } 1339 processAudioEvent(event.valueInt, event.device); 1340 break; 1341 case EVENT_TYPE_NETWORK_STATE: 1342 if (DBG) { 1343 Log.d(TAG, "Connected: Network state: " + event.valueInt); 1344 } 1345 mIndicatorNetworkState = event.valueInt; 1346 1347 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1348 intent.putExtra(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS, 1349 event.valueInt); 1350 1351 if (mIndicatorNetworkState == 1352 HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE) { 1353 mOperatorName = null; 1354 intent.putExtra(BluetoothHeadsetClient.EXTRA_OPERATOR_NAME, 1355 mOperatorName); 1356 } 1357 1358 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1359 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1360 1361 if (mIndicatorNetworkState == 1362 HeadsetClientHalConstants.NETWORK_STATE_AVAILABLE) { 1363 if (queryCurrentOperatorNameNative()) { 1364 addQueuedAction(QUERY_OPERATOR_NAME); 1365 } else { 1366 Log.e(TAG, "ERROR: Couldn't querry operator name"); 1367 } 1368 } 1369 break; 1370 case EVENT_TYPE_ROAMING_STATE: 1371 mIndicatorNetworkType = event.valueInt; 1372 1373 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1374 intent.putExtra(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING, 1375 event.valueInt); 1376 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1377 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1378 break; 1379 case EVENT_TYPE_NETWORK_SIGNAL: 1380 mIndicatorNetworkSignal = event.valueInt; 1381 1382 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1383 intent.putExtra(BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, 1384 event.valueInt); 1385 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1386 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1387 break; 1388 case EVENT_TYPE_BATTERY_LEVEL: 1389 mIndicatorBatteryLevel = event.valueInt; 1390 1391 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1392 intent.putExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL, 1393 event.valueInt); 1394 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1395 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1396 break; 1397 case EVENT_TYPE_OPERATOR_NAME: 1398 mOperatorName = event.valueString; 1399 1400 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1401 intent.putExtra(BluetoothHeadsetClient.EXTRA_OPERATOR_NAME, 1402 event.valueString); 1403 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1404 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1405 break; 1406 case EVENT_TYPE_VR_STATE_CHANGED: 1407 if (mVoiceRecognitionActive != event.valueInt) { 1408 mVoiceRecognitionActive = event.valueInt; 1409 1410 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1411 intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, 1412 mVoiceRecognitionActive); 1413 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1414 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1415 } 1416 break; 1417 case EVENT_TYPE_CALL: 1418 updateCallIndicator(event.valueInt); 1419 break; 1420 case EVENT_TYPE_CALLSETUP: 1421 updateCallSetupIndicator(event.valueInt); 1422 break; 1423 case EVENT_TYPE_CALLHELD: 1424 updateCallHeldIndicator(event.valueInt); 1425 break; 1426 case EVENT_TYPE_RESP_AND_HOLD: 1427 updateRespAndHold(event.valueInt); 1428 break; 1429 case EVENT_TYPE_CLIP: 1430 updateClip(event.valueString); 1431 break; 1432 case EVENT_TYPE_CALL_WAITING: 1433 updateCCWA(event.valueString); 1434 break; 1435 case EVENT_TYPE_IN_BAND_RING: 1436 if (mInBandRingtone != event.valueInt) { 1437 mInBandRingtone = event.valueInt; 1438 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1439 intent.putExtra(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, 1440 mInBandRingtone); 1441 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1442 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1443 } 1444 break; 1445 case EVENT_TYPE_CURRENT_CALLS: 1446 queryCallsUpdate( 1447 event.valueInt, 1448 event.valueInt3, 1449 event.valueString, 1450 event.valueInt4 == 1451 HeadsetClientHalConstants.CALL_MPTY_TYPE_MULTI, 1452 event.valueInt2 == 1453 HeadsetClientHalConstants.CALL_DIRECTION_OUTGOING); 1454 break; 1455 case EVENT_TYPE_VOLUME_CHANGED: 1456 if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) { 1457 Log.d(TAG, "AM volume set to " + 1458 hfToAmVol(event.valueInt2)); 1459 mAudioManager.setStreamVolume( 1460 AudioManager.STREAM_VOICE_CALL, 1461 hfToAmVol(event.valueInt2), 1462 AudioManager.FLAG_SHOW_UI); 1463 mVgsFromStack = true; 1464 } else if (event.valueInt == 1465 HeadsetClientHalConstants.VOLUME_TYPE_MIC) { 1466 mAudioManager.setMicrophoneMute(event.valueInt2 == 0); 1467 1468 mVgmFromStack = true; 1469 } 1470 break; 1471 case EVENT_TYPE_CMD_RESULT: 1472 Pair<Integer, Object> queuedAction = mQueuedActions.poll(); 1473 1474 // should not happen but... 1475 if (queuedAction == null || queuedAction.first == NO_ACTION) { 1476 clearPendingAction(); 1477 break; 1478 } 1479 1480 if (DBG) { 1481 Log.d(TAG, "Connected: command result: " + event.valueInt 1482 + " queuedAction: " + queuedAction.first); 1483 } 1484 1485 switch (queuedAction.first) { 1486 case VOICE_RECOGNITION_STOP: 1487 case VOICE_RECOGNITION_START: 1488 if (event.valueInt == HeadsetClientHalConstants.CMD_COMPLETE_OK) { 1489 if (queuedAction.first == VOICE_RECOGNITION_STOP) { 1490 mVoiceRecognitionActive = 1491 HeadsetClientHalConstants.VR_STATE_STOPPED; 1492 } else { 1493 mVoiceRecognitionActive = 1494 HeadsetClientHalConstants.VR_STATE_STARTED; 1495 } 1496 } 1497 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1498 intent.putExtra( 1499 BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, 1500 mVoiceRecognitionActive); 1501 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1502 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1503 break; 1504 case QUERY_CURRENT_CALLS: 1505 queryCallsDone(); 1506 break; 1507 case ACCEPT_CALL: 1508 if (event.valueInt == BluetoothHeadsetClient.ACTION_RESULT_OK) { 1509 mPendingAction = queuedAction; 1510 } else { 1511 if (callsInState(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) == 0) { 1512 if(getCall(BluetoothHeadsetClientCall.CALL_STATE_INCOMING) != null && 1513 (Integer) mPendingAction.second == HeadsetClientHalConstants.CALL_ACTION_ATA) { 1514 acceptCall(BluetoothHeadsetClient.CALL_ACCEPT_NONE, true); 1515 break; 1516 } else if(getCall(BluetoothHeadsetClientCall.CALL_STATE_WAITING) != null && 1517 (Integer) mPendingAction.second == HeadsetClientHalConstants.CALL_ACTION_CHLD_2) { 1518 acceptCall(BluetoothHeadsetClient.CALL_ACCEPT_NONE, true); 1519 break; 1520 } 1521 } 1522 sendActionResultIntent(event); 1523 } 1524 break; 1525 case DIAL_NUMBER: 1526 case REJECT_CALL: 1527 case HOLD_CALL: 1528 case TERMINATE_CALL: 1529 case ENTER_PRIVATE_MODE: 1530 case TERMINATE_SPECIFIC_CALL: 1531 // if terminating specific succeed no other 1532 // event is send 1533 if (event.valueInt == BluetoothHeadsetClient.ACTION_RESULT_OK) { 1534 BluetoothHeadsetClientCall sc = 1535 (BluetoothHeadsetClientCall) queuedAction.second; 1536 setCallState(sc, 1537 BluetoothHeadsetClientCall.CALL_STATE_TERMINATED); 1538 mCalls.remove(sc.getId()); 1539 } else { 1540 sendActionResultIntent(event); 1541 } 1542 break; 1543 case LAST_VTAG_NUMBER: 1544 if (event.valueInt != BluetoothHeadsetClient.ACTION_RESULT_OK) { 1545 sendActionResultIntent(event); 1546 } 1547 break; 1548 case DISABLE_NREC: 1549 if (event.valueInt != HeadsetClientHalConstants.CMD_COMPLETE_OK) { 1550 Log.w(TAG, "Failed to disable AG's EC and NR"); 1551 } 1552 break; 1553 case SET_MIC_VOLUME: 1554 case SET_SPEAKER_VOLUME: 1555 case SUBSCRIBER_INFO: 1556 case QUERY_OPERATOR_NAME: 1557 break; 1558 default: 1559 sendActionResultIntent(event); 1560 break; 1561 } 1562 1563 break; 1564 case EVENT_TYPE_SUBSCRIBER_INFO: 1565 /* TODO should we handle type as well? */ 1566 mSubscriberInfo = event.valueString; 1567 intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); 1568 intent.putExtra(BluetoothHeadsetClient.EXTRA_SUBSCRIBER_INFO, 1569 mSubscriberInfo); 1570 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1571 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1572 break; 1573 case EVENT_TYPE_LAST_VOICE_TAG_NUMBER: 1574 intent = new Intent(BluetoothHeadsetClient.ACTION_LAST_VTAG); 1575 intent.putExtra(BluetoothHeadsetClient.EXTRA_NUMBER, 1576 event.valueString); 1577 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1578 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1579 break; 1580 case EVENT_TYPE_RING_INDICATION: 1581 // Ringing is not handled at this indication and rather should be 1582 // implemented (by the client of this service). Use the 1583 // CALL_STATE_INCOMING (and similar) handle ringing. 1584 break; 1585 default: 1586 Log.e(TAG, "Unknown stack event: " + event.type); 1587 break; 1588 } 1589 1590 break; 1591 default: 1592 return NOT_HANDLED; 1593 } 1594 return HANDLED; 1595 } 1596 1597 private void sendActionResultIntent(StackEvent event) { 1598 Intent intent = new Intent(BluetoothHeadsetClient.ACTION_RESULT); 1599 intent.putExtra(BluetoothHeadsetClient.EXTRA_RESULT_CODE, event.valueInt); 1600 if (event.valueInt == BluetoothHeadsetClient.ACTION_RESULT_ERROR_CME) { 1601 intent.putExtra(BluetoothHeadsetClient.EXTRA_CME_CODE, event.valueInt2); 1602 } 1603 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, event.device); 1604 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1605 } 1606 1607 // in Connected state 1608 private void processConnectionEvent(int state, BluetoothDevice device) { 1609 switch (state) { 1610 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED: 1611 if (DBG) { 1612 Log.d(TAG, "Connected disconnects."); 1613 } 1614 // AG disconnects 1615 if (mCurrentDevice.equals(device)) { 1616 broadcastConnectionState(mCurrentDevice, 1617 BluetoothProfile.STATE_DISCONNECTED, 1618 BluetoothProfile.STATE_CONNECTED); 1619 mCurrentDevice = null; 1620 transitionTo(mDisconnected); 1621 } else { 1622 Log.e(TAG, "Disconnected from unknown device: " + device); 1623 } 1624 break; 1625 default: 1626 Log.e(TAG, "Connection State Device: " + device + " bad state: " + state); 1627 break; 1628 } 1629 } 1630 1631 // in Connected state 1632 private void processAudioEvent(int state, BluetoothDevice device) { 1633 // message from old device 1634 if (!mCurrentDevice.equals(device)) { 1635 Log.e(TAG, "Audio changed on disconnected device: " + device); 1636 return; 1637 } 1638 1639 switch (state) { 1640 case HeadsetClientHalConstants.AUDIO_STATE_CONNECTED_MSBC: 1641 mAudioWbs = true; 1642 // fall through 1643 case HeadsetClientHalConstants.AUDIO_STATE_CONNECTED: 1644 if (!mAudioRouteAllowed) { 1645 sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 1646 break; 1647 } 1648 1649 // Audio state is split in two parts, the audio focus is maintained by the 1650 // entity exercising this service (typically the Telecom stack) and audio 1651 // routing is handled by the bluetooth stack itself. The only reason to do so is 1652 // because Bluetooth SCO connection from the HF role is not entirely supported 1653 // for routing and volume purposes. 1654 // NOTE: All calls here are routed via the setParameters which changes the 1655 // routing at the Audio HAL level. 1656 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_CONNECTED; 1657 1658 // We need to set the volume after switching into HFP mode as some Audio HALs 1659 // reset the volume to a known-default on mode switch. 1660 final int amVol = 1661 mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); 1662 final int hfVol = amToHfVol(amVol); 1663 1664 if (DBG) { 1665 Log.d(TAG,"hfp_enable=true mAudioWbs is " + mAudioWbs); 1666 } 1667 if (mAudioWbs) { 1668 if (DBG) { 1669 Log.d(TAG,"Setting sampling rate as 16000"); 1670 } 1671 mAudioManager.setParameters("hfp_set_sampling_rate=16000"); 1672 } 1673 else { 1674 if (DBG) { 1675 Log.d(TAG,"Setting sampling rate as 8000"); 1676 } 1677 mAudioManager.setParameters("hfp_set_sampling_rate=8000"); 1678 } 1679 if (DBG) { 1680 Log.d(TAG, "hf_volume " + hfVol); 1681 } 1682 mAudioManager.setParameters("hfp_enable=true"); 1683 mAudioManager.setParameters("hfp_volume=" + hfVol); 1684 transitionTo(mAudioOn); 1685 break; 1686 case HeadsetClientHalConstants.AUDIO_STATE_CONNECTING: 1687 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_CONNECTING; 1688 broadcastAudioState(device, BluetoothHeadsetClient.STATE_AUDIO_CONNECTING, 1689 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED); 1690 break; 1691 case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED: 1692 if (mAudioState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTING) { 1693 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 1694 broadcastAudioState(device, 1695 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED, 1696 BluetoothHeadsetClient.STATE_AUDIO_CONNECTING); 1697 } 1698 break; 1699 default: 1700 Log.e(TAG, "Audio State Device: " + device + " bad state: " + state); 1701 break; 1702 } 1703 } 1704 1705 @Override 1706 public void exit() { 1707 if (DBG) { 1708 Log.d(TAG, "Exit Connected: " + getCurrentMessage().what); 1709 } 1710 } 1711 } 1712 1713 private class AudioOn extends State { 1714 @Override 1715 public void enter() { 1716 if (DBG) { 1717 Log.d(TAG, "Enter AudioOn: " + getCurrentMessage().what); 1718 } 1719 broadcastAudioState(mCurrentDevice, BluetoothHeadsetClient.STATE_AUDIO_CONNECTED, 1720 BluetoothHeadsetClient.STATE_AUDIO_CONNECTING); 1721 } 1722 1723 @Override 1724 public synchronized boolean processMessage(Message message) { 1725 if (DBG) { 1726 Log.d(TAG, "AudioOn process message: " + message.what); 1727 } 1728 if (DBG) { 1729 if (mCurrentDevice == null) { 1730 Log.e(TAG, "ERROR: mCurrentDevice is null in Connected"); 1731 return NOT_HANDLED; 1732 } 1733 } 1734 1735 switch (message.what) { 1736 case DISCONNECT: 1737 BluetoothDevice device = (BluetoothDevice) message.obj; 1738 if (!mCurrentDevice.equals(device)) { 1739 break; 1740 } 1741 deferMessage(message); 1742 /* 1743 * fall through - disconnect audio first then expect 1744 * deferred DISCONNECT message in Connected state 1745 */ 1746 case DISCONNECT_AUDIO: 1747 /* 1748 * just disconnect audio and wait for 1749 * EVENT_TYPE_AUDIO_STATE_CHANGED, that triggers State 1750 * Machines state changing 1751 */ 1752 if (disconnectAudioNative(getByteAddress(mCurrentDevice))) { 1753 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 1754 if (DBG) { 1755 Log.d(TAG,"hfp_enable=false"); 1756 } 1757 mAudioManager.setParameters("hfp_enable=false"); 1758 broadcastAudioState(mCurrentDevice, 1759 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED, 1760 BluetoothHeadsetClient.STATE_AUDIO_CONNECTED); 1761 } 1762 break; 1763 case STACK_EVENT: 1764 StackEvent event = (StackEvent) message.obj; 1765 if (DBG) { 1766 Log.d(TAG, "AudioOn: event type: " + event.type); 1767 } 1768 switch (event.type) { 1769 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 1770 if (DBG) { 1771 Log.d(TAG, "AudioOn connection state changed" + event.device + ": " 1772 + event.valueInt); 1773 } 1774 processConnectionEvent(event.valueInt, event.device); 1775 break; 1776 case EVENT_TYPE_AUDIO_STATE_CHANGED: 1777 if (DBG) { 1778 Log.d(TAG, "AudioOn audio state changed" + event.device + ": " 1779 + event.valueInt); 1780 } 1781 processAudioEvent(event.valueInt, event.device); 1782 break; 1783 default: 1784 return NOT_HANDLED; 1785 } 1786 break; 1787 default: 1788 return NOT_HANDLED; 1789 } 1790 return HANDLED; 1791 } 1792 1793 // in AudioOn state. Can AG disconnect RFCOMM prior to SCO? Handle this 1794 private void processConnectionEvent(int state, BluetoothDevice device) { 1795 switch (state) { 1796 case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED: 1797 if (mCurrentDevice.equals(device)) { 1798 processAudioEvent(HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED, 1799 device); 1800 broadcastConnectionState(mCurrentDevice, 1801 BluetoothProfile.STATE_DISCONNECTED, 1802 BluetoothProfile.STATE_CONNECTED); 1803 mCurrentDevice = null; 1804 transitionTo(mDisconnected); 1805 } else { 1806 Log.e(TAG, "Disconnected from unknown device: " + device); 1807 } 1808 break; 1809 default: 1810 Log.e(TAG, "Connection State Device: " + device + " bad state: " + state); 1811 break; 1812 } 1813 } 1814 1815 // in AudioOn state 1816 private void processAudioEvent(int state, BluetoothDevice device) { 1817 if (!mCurrentDevice.equals(device)) { 1818 Log.e(TAG, "Audio changed on disconnected device: " + device); 1819 return; 1820 } 1821 1822 switch (state) { 1823 case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED: 1824 if (mAudioState != BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED) { 1825 mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 1826 // Audio focus may still be held by the entity controlling the actual call 1827 // (such as Telecom) and hence this will still keep the call around, there 1828 // is not much we can do here since dropping the call without user consent 1829 // even if the audio connection snapped may not be a good idea. 1830 if (DBG) { 1831 Log.d(TAG,"hfp_enable=false"); 1832 } 1833 mAudioManager.setParameters("hfp_enable=false"); 1834 broadcastAudioState(device, 1835 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED, 1836 BluetoothHeadsetClient.STATE_AUDIO_CONNECTED); 1837 } 1838 1839 transitionTo(mConnected); 1840 break; 1841 default: 1842 Log.e(TAG, "Audio State Device: " + device + " bad state: " + state); 1843 break; 1844 } 1845 } 1846 1847 @Override 1848 public void exit() { 1849 if (DBG) { 1850 Log.d(TAG, "Exit AudioOn: " + getCurrentMessage().what); 1851 } 1852 } 1853 } 1854 1855 /** 1856 * @hide 1857 */ 1858 public synchronized int getConnectionState(BluetoothDevice device) { 1859 if (mCurrentDevice == null) { 1860 return BluetoothProfile.STATE_DISCONNECTED; 1861 } 1862 1863 if (!mCurrentDevice.equals(device)) { 1864 return BluetoothProfile.STATE_DISCONNECTED; 1865 } 1866 1867 IState currentState = getCurrentState(); 1868 if (currentState == mConnecting) { 1869 return BluetoothProfile.STATE_CONNECTING; 1870 } 1871 1872 if (currentState == mConnected || currentState == mAudioOn) { 1873 return BluetoothProfile.STATE_CONNECTED; 1874 } 1875 1876 Log.e(TAG, "Bad currentState: " + currentState); 1877 return BluetoothProfile.STATE_DISCONNECTED; 1878 } 1879 1880 private void broadcastAudioState(BluetoothDevice device, int newState, int prevState) { 1881 Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED); 1882 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 1883 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 1884 1885 if (newState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTED) { 1886 intent.putExtra(BluetoothHeadsetClient.EXTRA_AUDIO_WBS, mAudioWbs); 1887 } 1888 1889 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1890 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1891 if (DBG) { 1892 Log.d(TAG, "Audio state " + device + ": " + prevState + "->" + newState); 1893 } 1894 } 1895 1896 // This method does not check for error condition (newState == prevState) 1897 private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) { 1898 if (DBG) { 1899 Log.d(TAG, "Connection state " + device + ": " + prevState + "->" + newState); 1900 } 1901 /* 1902 * Notifying the connection state change of the profile before sending 1903 * the intent for connection state change, as it was causing a race 1904 * condition, with the UI not being updated with the correct connection 1905 * state. 1906 */ 1907 mService.notifyProfileConnectionStateChanged(device, BluetoothProfile.HEADSET_CLIENT, 1908 newState, prevState); 1909 Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); 1910 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 1911 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 1912 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1913 1914 // add feature extras when connected 1915 if (newState == BluetoothProfile.STATE_CONNECTED) { 1916 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_3WAY) == 1917 HeadsetClientHalConstants.PEER_FEAT_3WAY) { 1918 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_3WAY_CALLING, true); 1919 } 1920 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_VREC) == 1921 HeadsetClientHalConstants.PEER_FEAT_VREC) { 1922 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_VOICE_RECOGNITION, true); 1923 } 1924 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_VTAG) == 1925 HeadsetClientHalConstants.PEER_FEAT_VTAG) { 1926 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT, true); 1927 } 1928 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_REJECT) == 1929 HeadsetClientHalConstants.PEER_FEAT_REJECT) { 1930 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_REJECT_CALL, true); 1931 } 1932 if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECC) == 1933 HeadsetClientHalConstants.PEER_FEAT_ECC) { 1934 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ECC, true); 1935 } 1936 1937 // add individual CHLD support extras 1938 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC) == 1939 HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC) { 1940 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL, true); 1941 } 1942 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_REL) == 1943 HeadsetClientHalConstants.CHLD_FEAT_REL) { 1944 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL, true); 1945 } 1946 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_REL_ACC) == 1947 HeadsetClientHalConstants.CHLD_FEAT_REL_ACC) { 1948 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT, true); 1949 } 1950 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_MERGE) == 1951 HeadsetClientHalConstants.CHLD_FEAT_MERGE) { 1952 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE, true); 1953 } 1954 if ((mChldFeatures & HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) == 1955 HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) { 1956 intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH, true); 1957 } 1958 } 1959 mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 1960 } 1961 1962 boolean isConnected() { 1963 IState currentState = getCurrentState(); 1964 return (currentState == mConnected || currentState == mAudioOn); 1965 } 1966 1967 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 1968 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 1969 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 1970 int connectionState; 1971 synchronized (this) { 1972 for (BluetoothDevice device : bondedDevices) { 1973 ParcelUuid[] featureUuids = device.getUuids(); 1974 if (!BluetoothUuid.isUuidPresent(featureUuids, BluetoothUuid.Handsfree_AG)) { 1975 continue; 1976 } 1977 connectionState = getConnectionState(device); 1978 for (int state : states) { 1979 if (connectionState == state) { 1980 deviceList.add(device); 1981 } 1982 } 1983 } 1984 } 1985 return deviceList; 1986 } 1987 1988 boolean okToConnect(BluetoothDevice device) { 1989 int priority = mService.getPriority(device); 1990 boolean ret = false; 1991 // check priority and accept or reject the connection. if priority is 1992 // undefined 1993 // it is likely that our SDP has not completed and peer is initiating 1994 // the 1995 // connection. Allow this connection, provided the device is bonded 1996 if ((BluetoothProfile.PRIORITY_OFF < priority) || 1997 ((BluetoothProfile.PRIORITY_UNDEFINED == priority) && 1998 (device.getBondState() != BluetoothDevice.BOND_NONE))) { 1999 ret = true; 2000 } 2001 return ret; 2002 } 2003 2004 boolean isAudioOn() { 2005 return (getCurrentState() == mAudioOn); 2006 } 2007 2008 public void setAudioRouteAllowed(boolean allowed) { 2009 mAudioRouteAllowed = allowed; 2010 } 2011 2012 public boolean getAudioRouteAllowed() { 2013 return mAudioRouteAllowed; 2014 } 2015 2016 synchronized int getAudioState(BluetoothDevice device) { 2017 if (mCurrentDevice == null || !mCurrentDevice.equals(device)) { 2018 return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 2019 } 2020 return mAudioState; 2021 } 2022 2023 /** 2024 * @hide 2025 */ 2026 List<BluetoothDevice> getConnectedDevices() { 2027 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 2028 synchronized (this) { 2029 if (isConnected()) { 2030 devices.add(mCurrentDevice); 2031 } 2032 } 2033 return devices; 2034 } 2035 2036 private BluetoothDevice getDevice(byte[] address) { 2037 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 2038 } 2039 2040 private void onConnectionStateChanged(int state, int peer_feat, int chld_feat, byte[] address) { 2041 StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED); 2042 event.valueInt = state; 2043 event.valueInt2 = peer_feat; 2044 event.valueInt3 = chld_feat; 2045 event.device = getDevice(address); 2046 if (DBG) { 2047 Log.d(TAG, "incoming" + event); 2048 } 2049 sendMessage(STACK_EVENT, event); 2050 } 2051 2052 private void onAudioStateChanged(int state, byte[] address) { 2053 StackEvent event = new StackEvent(EVENT_TYPE_AUDIO_STATE_CHANGED); 2054 event.valueInt = state; 2055 event.device = getDevice(address); 2056 if (DBG) { 2057 Log.d(TAG, "incoming" + event); 2058 } 2059 sendMessage(STACK_EVENT, event); 2060 } 2061 2062 private void onVrStateChanged(int state) { 2063 StackEvent event = new StackEvent(EVENT_TYPE_VR_STATE_CHANGED); 2064 event.valueInt = state; 2065 if (DBG) { 2066 Log.d(TAG, "incoming" + event); 2067 } 2068 sendMessage(STACK_EVENT, event); 2069 } 2070 2071 private void onNetworkState(int state) { 2072 StackEvent event = new StackEvent(EVENT_TYPE_NETWORK_STATE); 2073 event.valueInt = state; 2074 if (DBG) { 2075 Log.d(TAG, "incoming" + event); 2076 } 2077 sendMessage(STACK_EVENT, event); 2078 } 2079 2080 private void onNetworkRoaming(int state) { 2081 StackEvent event = new StackEvent(EVENT_TYPE_ROAMING_STATE); 2082 event.valueInt = state; 2083 if (DBG) { 2084 Log.d(TAG, "incoming" + event); 2085 } 2086 sendMessage(STACK_EVENT, event); 2087 } 2088 2089 private void onNetworkSignal(int signal) { 2090 StackEvent event = new StackEvent(EVENT_TYPE_NETWORK_SIGNAL); 2091 event.valueInt = signal; 2092 if (DBG) { 2093 Log.d(TAG, "incoming" + event); 2094 } 2095 sendMessage(STACK_EVENT, event); 2096 } 2097 2098 private void onBatteryLevel(int level) { 2099 StackEvent event = new StackEvent(EVENT_TYPE_BATTERY_LEVEL); 2100 event.valueInt = level; 2101 if (DBG) { 2102 Log.d(TAG, "incoming" + event); 2103 } 2104 sendMessage(STACK_EVENT, event); 2105 } 2106 2107 private void onCurrentOperator(String name) { 2108 StackEvent event = new StackEvent(EVENT_TYPE_OPERATOR_NAME); 2109 event.valueString = name; 2110 if (DBG) { 2111 Log.d(TAG, "incoming" + event); 2112 } 2113 sendMessage(STACK_EVENT, event); 2114 } 2115 2116 /** 2117 * CIEV (Call indicators) notifying if a call is in progress. 2118 * 2119 * Values Include: 2120 * 0 - No call in progress 2121 * 1 - Atleast 1 call is in progress 2122 */ 2123 private void onCall(int call) { 2124 StackEvent event = new StackEvent(EVENT_TYPE_CALL); 2125 event.valueInt = call; 2126 if (DBG) { 2127 Log.d(TAG, "incoming" + event); 2128 } 2129 sendMessage(STACK_EVENT, event); 2130 } 2131 2132 /** 2133 * CIEV (Call indicators) notifying if call(s) are getting set up. 2134 * 2135 * Values incldue: 2136 * 0 - No current call is in setup 2137 * 1 - Incoming call process ongoing 2138 * 2 - Outgoing call process ongoing 2139 * 3 - Remote party being alerted for outgoing call 2140 */ 2141 private void onCallSetup(int callsetup) { 2142 StackEvent event = new StackEvent(EVENT_TYPE_CALLSETUP); 2143 event.valueInt = callsetup; 2144 if (DBG) { 2145 Log.d(TAG, "incoming" + event); 2146 } 2147 sendMessage(STACK_EVENT, event); 2148 } 2149 2150 /** 2151 * CIEV (Call indicators) notifying call held states. 2152 * 2153 * Values include: 2154 * 0 - No calls held 2155 * 1 - Call is placed on hold or active/held calls wapped (The AG has both an ACTIVE and HELD 2156 * call) 2157 * 2 - Call on hold, no active call 2158 */ 2159 private void onCallHeld(int callheld) { 2160 StackEvent event = new StackEvent(EVENT_TYPE_CALLHELD); 2161 event.valueInt = callheld; 2162 if (DBG) { 2163 Log.d(TAG, "incoming" + event); 2164 } 2165 sendMessage(STACK_EVENT, event); 2166 } 2167 2168 private void onRespAndHold(int resp_and_hold) { 2169 StackEvent event = new StackEvent(EVENT_TYPE_RESP_AND_HOLD); 2170 event.valueInt = resp_and_hold; 2171 if (DBG) { 2172 Log.d(TAG, "incoming" + event); 2173 } 2174 sendMessage(STACK_EVENT, event); 2175 } 2176 2177 private void onClip(String number) { 2178 StackEvent event = new StackEvent(EVENT_TYPE_CLIP); 2179 event.valueString = number; 2180 if (DBG) { 2181 Log.d(TAG, "incoming" + event); 2182 } 2183 sendMessage(STACK_EVENT, event); 2184 } 2185 2186 private void onCallWaiting(String number) { 2187 StackEvent event = new StackEvent(EVENT_TYPE_CALL_WAITING); 2188 event.valueString = number; 2189 if (DBG) { 2190 Log.d(TAG, "incoming" + event); 2191 } 2192 sendMessage(STACK_EVENT, event); 2193 } 2194 2195 private void onCurrentCalls(int index, int dir, int state, int mparty, String number) { 2196 StackEvent event = new StackEvent(EVENT_TYPE_CURRENT_CALLS); 2197 event.valueInt = index; 2198 event.valueInt2 = dir; 2199 event.valueInt3 = state; 2200 event.valueInt4 = mparty; 2201 event.valueString = number; 2202 if (DBG) { 2203 Log.d(TAG, "incoming" + event); 2204 } 2205 sendMessage(STACK_EVENT, event); 2206 } 2207 2208 private void onVolumeChange(int type, int volume) { 2209 StackEvent event = new StackEvent(EVENT_TYPE_VOLUME_CHANGED); 2210 event.valueInt = type; 2211 event.valueInt2 = volume; 2212 if (DBG) { 2213 Log.d(TAG, "incoming" + event); 2214 } 2215 sendMessage(STACK_EVENT, event); 2216 } 2217 2218 private void onCmdResult(int type, int cme) { 2219 StackEvent event = new StackEvent(EVENT_TYPE_CMD_RESULT); 2220 event.valueInt = type; 2221 event.valueInt2 = cme; 2222 if (DBG) { 2223 Log.d(TAG, "incoming" + event); 2224 } 2225 sendMessage(STACK_EVENT, event); 2226 } 2227 2228 private void onSubscriberInfo(String number, int type) { 2229 StackEvent event = new StackEvent(EVENT_TYPE_SUBSCRIBER_INFO); 2230 event.valueInt = type; 2231 event.valueString = number; 2232 if (DBG) { 2233 Log.d(TAG, "incoming" + event); 2234 } 2235 sendMessage(STACK_EVENT, event); 2236 } 2237 2238 private void onInBandRing(int in_band) { 2239 StackEvent event = new StackEvent(EVENT_TYPE_IN_BAND_RING); 2240 event.valueInt = in_band; 2241 if (DBG) { 2242 Log.d(TAG, "incoming" + event); 2243 } 2244 sendMessage(STACK_EVENT, event); 2245 } 2246 2247 private void onLastVoiceTagNumber(String number) { 2248 StackEvent event = new StackEvent(EVENT_TYPE_LAST_VOICE_TAG_NUMBER); 2249 event.valueString = number; 2250 if (DBG) { 2251 Log.d(TAG, "incoming" + event); 2252 } 2253 sendMessage(STACK_EVENT, event); 2254 } 2255 2256 private void onRingIndication() { 2257 StackEvent event = new StackEvent(EVENT_TYPE_RING_INDICATION); 2258 if (DBG) { 2259 Log.d(TAG, "incoming" + event); 2260 } 2261 sendMessage(STACK_EVENT, event); 2262 } 2263 2264 private String getCurrentDeviceName() { 2265 String defaultName = "<unknown>"; 2266 if (mCurrentDevice == null) { 2267 return defaultName; 2268 } 2269 String deviceName = mCurrentDevice.getName(); 2270 if (deviceName == null) { 2271 return defaultName; 2272 } 2273 return deviceName; 2274 } 2275 2276 private byte[] getByteAddress(BluetoothDevice device) { 2277 return Utils.getBytesFromAddress(device.getAddress()); 2278 } 2279 2280 // Event types for STACK_EVENT message 2281 final private static int EVENT_TYPE_NONE = 0; 2282 final private static int EVENT_TYPE_CONNECTION_STATE_CHANGED = 1; 2283 final private static int EVENT_TYPE_AUDIO_STATE_CHANGED = 2; 2284 final private static int EVENT_TYPE_VR_STATE_CHANGED = 3; 2285 final private static int EVENT_TYPE_NETWORK_STATE = 4; 2286 final private static int EVENT_TYPE_ROAMING_STATE = 5; 2287 final private static int EVENT_TYPE_NETWORK_SIGNAL = 6; 2288 final private static int EVENT_TYPE_BATTERY_LEVEL = 7; 2289 final private static int EVENT_TYPE_OPERATOR_NAME = 8; 2290 final private static int EVENT_TYPE_CALL = 9; 2291 final private static int EVENT_TYPE_CALLSETUP = 10; 2292 final private static int EVENT_TYPE_CALLHELD = 11; 2293 final private static int EVENT_TYPE_CLIP = 12; 2294 final private static int EVENT_TYPE_CALL_WAITING = 13; 2295 final private static int EVENT_TYPE_CURRENT_CALLS = 14; 2296 final private static int EVENT_TYPE_VOLUME_CHANGED = 15; 2297 final private static int EVENT_TYPE_CMD_RESULT = 16; 2298 final private static int EVENT_TYPE_SUBSCRIBER_INFO = 17; 2299 final private static int EVENT_TYPE_RESP_AND_HOLD = 18; 2300 final private static int EVENT_TYPE_IN_BAND_RING = 19; 2301 final private static int EVENT_TYPE_LAST_VOICE_TAG_NUMBER = 20; 2302 final private static int EVENT_TYPE_RING_INDICATION= 21; 2303 2304 // for debugging only 2305 private final String EVENT_TYPE_NAMES[] = 2306 { 2307 "EVENT_TYPE_NONE", 2308 "EVENT_TYPE_CONNECTION_STATE_CHANGED", 2309 "EVENT_TYPE_AUDIO_STATE_CHANGED", 2310 "EVENT_TYPE_VR_STATE_CHANGED", 2311 "EVENT_TYPE_NETWORK_STATE", 2312 "EVENT_TYPE_ROAMING_STATE", 2313 "EVENT_TYPE_NETWORK_SIGNAL", 2314 "EVENT_TYPE_BATTERY_LEVEL", 2315 "EVENT_TYPE_OPERATOR_NAME", 2316 "EVENT_TYPE_CALL", 2317 "EVENT_TYPE_CALLSETUP", 2318 "EVENT_TYPE_CALLHELD", 2319 "EVENT_TYPE_CLIP", 2320 "EVENT_TYPE_CALL_WAITING", 2321 "EVENT_TYPE_CURRENT_CALLS", 2322 "EVENT_TYPE_VOLUME_CHANGED", 2323 "EVENT_TYPE_CMD_RESULT", 2324 "EVENT_TYPE_SUBSCRIBER_INFO", 2325 "EVENT_TYPE_RESP_AND_HOLD", 2326 "EVENT_TYPE_IN_BAND_RING", 2327 "EVENT_TYPE_LAST_VOICE_TAG_NUMBER", 2328 "EVENT_TYPE_RING_INDICATION", 2329 }; 2330 2331 private class StackEvent { 2332 int type = EVENT_TYPE_NONE; 2333 int valueInt = 0; 2334 int valueInt2 = 0; 2335 int valueInt3 = 0; 2336 int valueInt4 = 0; 2337 String valueString = null; 2338 BluetoothDevice device = null; 2339 2340 private StackEvent(int type) { 2341 this.type = type; 2342 } 2343 2344 @Override 2345 public String toString() { 2346 // event dump 2347 StringBuilder result = new StringBuilder(); 2348 result.append("StackEvent {type:" + EVENT_TYPE_NAMES[type]); 2349 result.append(", value1:" + valueInt); 2350 result.append(", value2:" + valueInt2); 2351 result.append(", value3:" + valueInt3); 2352 result.append(", value4:" + valueInt4); 2353 result.append(", string: \"" + valueString + "\""); 2354 result.append(", device:" + device + "}"); 2355 return result.toString(); 2356 } 2357 } 2358 2359 private native static void classInitNative(); 2360 2361 private native void initializeNative(); 2362 2363 private native void cleanupNative(); 2364 2365 private native boolean connectNative(byte[] address); 2366 2367 private native boolean disconnectNative(byte[] address); 2368 2369 private native boolean connectAudioNative(byte[] address); 2370 2371 private native boolean disconnectAudioNative(byte[] address); 2372 2373 private native boolean startVoiceRecognitionNative(); 2374 2375 private native boolean stopVoiceRecognitionNative(); 2376 2377 private native boolean setVolumeNative(int volumeType, int volume); 2378 2379 private native boolean dialNative(String number); 2380 2381 private native boolean dialMemoryNative(int location); 2382 2383 private native boolean handleCallActionNative(int action, int index); 2384 2385 private native boolean queryCurrentCallsNative(); 2386 2387 private native boolean queryCurrentOperatorNameNative(); 2388 2389 private native boolean retrieveSubscriberInfoNative(); 2390 2391 private native boolean sendDtmfNative(byte code); 2392 2393 private native boolean requestLastVoiceTagNumberNative(); 2394 2395 private native boolean sendATCmdNative(int ATCmd, int val1, 2396 int val2, String arg); 2397 2398 public List<BluetoothHeadsetClientCall> getCurrentCalls() { 2399 return new ArrayList<BluetoothHeadsetClientCall>(mCalls.values()); 2400 } 2401 2402 public Bundle getCurrentAgEvents() { 2403 Bundle b = new Bundle(); 2404 b.putInt(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS, mIndicatorNetworkState); 2405 b.putInt(BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, mIndicatorNetworkSignal); 2406 b.putInt(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING, mIndicatorNetworkType); 2407 b.putInt(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL, mIndicatorBatteryLevel); 2408 b.putString(BluetoothHeadsetClient.EXTRA_OPERATOR_NAME, mOperatorName); 2409 b.putInt(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, mVoiceRecognitionActive); 2410 b.putInt(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, mInBandRingtone); 2411 b.putString(BluetoothHeadsetClient.EXTRA_SUBSCRIBER_INFO, mSubscriberInfo); 2412 return b; 2413 } 2414} 2415