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