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