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