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