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