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