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