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