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