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