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