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