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