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