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