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