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