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