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 package com.android.bluetooth.hfpclient;
     19 
     20 import android.bluetooth.BluetoothDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.bluetooth.BluetoothHeadsetClient;
     23 import android.bluetooth.BluetoothHeadsetClientCall;
     24 import android.bluetooth.IBluetoothHeadsetClient;
     25 import android.content.BroadcastReceiver;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.media.AudioManager;
     30 import android.os.Bundle;
     31 import android.os.Message;
     32 import android.provider.Settings;
     33 import android.util.Log;
     34 import com.android.bluetooth.btservice.ProfileService;
     35 import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService;
     36 import com.android.bluetooth.Utils;
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 
     41 /**
     42  * Provides Bluetooth Headset Client (HF Role) profile, as a service in the
     43  * Bluetooth application.
     44  *
     45  * @hide
     46  */
     47 public class HeadsetClientService extends ProfileService {
     48     private static final boolean DBG = false;
     49     private static final String TAG = "HeadsetClientService";
     50 
     51     private HeadsetClientStateMachine mStateMachine;
     52     private static HeadsetClientService sHeadsetClientService;
     53 
     54     public static String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag";
     55 
     56     @Override
     57     protected String getName() {
     58         return TAG;
     59     }
     60 
     61     @Override
     62     public IProfileServiceBinder initBinder() {
     63         return new BluetoothHeadsetClientBinder(this);
     64     }
     65 
     66     @Override
     67     protected boolean start() {
     68         mStateMachine = HeadsetClientStateMachine.make(this);
     69         IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
     70         filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
     71         try {
     72             registerReceiver(mBroadcastReceiver, filter);
     73         } catch (Exception e) {
     74             Log.w(TAG, "Unable to register broadcat receiver", e);
     75         }
     76         setHeadsetClientService(this);
     77 
     78         // Start the HfpClientConnectionService to create connection with telecom when HFP
     79         // connection is available.
     80         Intent startIntent = new Intent(this, HfpClientConnectionService.class);
     81         startService(startIntent);
     82 
     83         return true;
     84     }
     85 
     86     @Override
     87     protected boolean stop() {
     88         try {
     89             unregisterReceiver(mBroadcastReceiver);
     90         } catch (Exception e) {
     91             Log.w(TAG, "Unable to unregister broadcast receiver", e);
     92         }
     93         mStateMachine.doQuit();
     94 
     95         // Stop the HfpClientConnectionService.
     96         Intent stopIntent = new Intent(this, HfpClientConnectionService.class);
     97         stopIntent.putExtra(HFP_CLIENT_STOP_TAG, true);
     98         startService(stopIntent);
     99 
    100         return true;
    101     }
    102 
    103     @Override
    104     protected boolean cleanup() {
    105         if (mStateMachine != null) {
    106             mStateMachine.cleanup();
    107         }
    108         clearHeadsetClientService();
    109         return true;
    110     }
    111 
    112     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    113         @Override
    114         public void onReceive(Context context, Intent intent) {
    115             String action = intent.getAction();
    116 
    117             // We handle the volume changes for Voice calls here since HFP audio volume control does
    118             // not go through audio manager (audio mixer). We check if the voice call volume has
    119             // changed and subsequently change the SCO volume see
    120             // ({@link HeadsetClientStateMachine#SET_SPEAKER_VOLUME} in
    121             // {@link HeadsetClientStateMachine} for details.
    122             if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
    123                 Log.d(TAG, "Volume changed for stream: " +
    124                     intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE));
    125                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
    126                 if (streamType == AudioManager.STREAM_VOICE_CALL) {
    127                     int streamValue = intent
    128                             .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
    129                     int streamPrevValue = intent.getIntExtra(
    130                             AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
    131 
    132                     if (streamValue != -1 && streamValue != streamPrevValue) {
    133                         mStateMachine.sendMessage(mStateMachine.obtainMessage(
    134                                 HeadsetClientStateMachine.SET_SPEAKER_VOLUME, streamValue, 0));
    135                     }
    136                 }
    137             }
    138         }
    139     };
    140 
    141     /**
    142      * Handlers for incoming service calls
    143      */
    144     private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub
    145             implements IProfileServiceBinder {
    146         private HeadsetClientService mService;
    147 
    148         public BluetoothHeadsetClientBinder(HeadsetClientService svc) {
    149             mService = svc;
    150         }
    151 
    152         @Override
    153         public boolean cleanup() {
    154             mService = null;
    155             return true;
    156         }
    157 
    158         private HeadsetClientService getService() {
    159             if (!Utils.checkCaller()) {
    160                 Log.w(TAG, "HeadsetClient call not allowed for non-active user");
    161                 return null;
    162             }
    163 
    164             if (mService != null && mService.isAvailable()) {
    165                 return mService;
    166             }
    167             return null;
    168         }
    169 
    170         @Override
    171         public boolean connect(BluetoothDevice device) {
    172             HeadsetClientService service = getService();
    173             if (service == null) {
    174                 return false;
    175             }
    176             return service.connect(device);
    177         }
    178 
    179         @Override
    180         public boolean disconnect(BluetoothDevice device) {
    181             HeadsetClientService service = getService();
    182             if (service == null) {
    183                 return false;
    184             }
    185             return service.disconnect(device);
    186         }
    187 
    188         @Override
    189         public List<BluetoothDevice> getConnectedDevices() {
    190             HeadsetClientService service = getService();
    191             if (service == null) {
    192                 return new ArrayList<BluetoothDevice>(0);
    193             }
    194             return service.getConnectedDevices();
    195         }
    196 
    197         @Override
    198         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    199             HeadsetClientService service = getService();
    200             if (service == null) {
    201                 return new ArrayList<BluetoothDevice>(0);
    202             }
    203             return service.getDevicesMatchingConnectionStates(states);
    204         }
    205 
    206         @Override
    207         public int getConnectionState(BluetoothDevice device) {
    208             HeadsetClientService service = getService();
    209             if (service == null) {
    210                 return BluetoothProfile.STATE_DISCONNECTED;
    211             }
    212             return service.getConnectionState(device);
    213         }
    214 
    215         @Override
    216         public boolean setPriority(BluetoothDevice device, int priority) {
    217             HeadsetClientService service = getService();
    218             if (service == null) {
    219                 return false;
    220             }
    221             return service.setPriority(device, priority);
    222         }
    223 
    224         @Override
    225         public int getPriority(BluetoothDevice device) {
    226             HeadsetClientService service = getService();
    227             if (service == null) {
    228                 return BluetoothProfile.PRIORITY_UNDEFINED;
    229             }
    230             return service.getPriority(device);
    231         }
    232 
    233         @Override
    234         public boolean startVoiceRecognition(BluetoothDevice device) {
    235             HeadsetClientService service = getService();
    236             if (service == null) {
    237                 return false;
    238             }
    239             return service.startVoiceRecognition(device);
    240         }
    241 
    242         @Override
    243         public boolean stopVoiceRecognition(BluetoothDevice device) {
    244             HeadsetClientService service = getService();
    245             if (service == null) {
    246                 return false;
    247             }
    248             return service.stopVoiceRecognition(device);
    249         }
    250 
    251         @Override
    252         public boolean acceptIncomingConnect(BluetoothDevice device) {
    253             HeadsetClientService service = getService();
    254             if (service == null) {
    255                 return false;
    256             }
    257             return service.acceptIncomingConnect(device);
    258         }
    259 
    260         @Override
    261         public boolean rejectIncomingConnect(BluetoothDevice device) {
    262             HeadsetClientService service = getService();
    263             if (service == null) {
    264                 return false;
    265             }
    266             return service.rejectIncomingConnect(device);
    267         }
    268 
    269         @Override
    270         public int getAudioState(BluetoothDevice device) {
    271             HeadsetClientService service = getService();
    272             if (service == null) {
    273                 return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
    274             }
    275             return service.getAudioState(device);
    276         }
    277 
    278         @Override
    279         public void setAudioRouteAllowed(boolean allowed) {
    280             HeadsetClientService service = getService();
    281             if (service != null) {
    282                 service.setAudioRouteAllowed(allowed);
    283             }
    284         }
    285 
    286         @Override
    287         public boolean getAudioRouteAllowed() {
    288             HeadsetClientService service = getService();
    289             if (service != null) {
    290                 return service.getAudioRouteAllowed();
    291             }
    292 
    293             return false;
    294         }
    295 
    296         @Override
    297         public boolean connectAudio() {
    298             HeadsetClientService service = getService();
    299             if (service == null) {
    300                 return false;
    301             }
    302             return service.connectAudio();
    303         }
    304 
    305         @Override
    306         public boolean disconnectAudio() {
    307             HeadsetClientService service = getService();
    308             if (service == null) {
    309                 return false;
    310             }
    311             return service.disconnectAudio();
    312         }
    313 
    314         @Override
    315         public boolean acceptCall(BluetoothDevice device, int flag) {
    316             HeadsetClientService service = getService();
    317             if (service == null) {
    318                 return false;
    319             }
    320             return service.acceptCall(device, flag);
    321         }
    322 
    323         @Override
    324         public boolean rejectCall(BluetoothDevice device) {
    325             HeadsetClientService service = getService();
    326             if (service == null) {
    327                 return false;
    328             }
    329             return service.rejectCall(device);
    330         }
    331 
    332         @Override
    333         public boolean holdCall(BluetoothDevice device) {
    334             HeadsetClientService service = getService();
    335             if (service == null) {
    336                 return false;
    337             }
    338             return service.holdCall(device);
    339         }
    340 
    341         @Override
    342         public boolean terminateCall(BluetoothDevice device, int index) {
    343             HeadsetClientService service = getService();
    344             if (service == null) {
    345                 return false;
    346             }
    347             return service.terminateCall(device, index);
    348         }
    349 
    350         @Override
    351         public boolean explicitCallTransfer(BluetoothDevice device) {
    352             HeadsetClientService service = getService();
    353             if (service == null) {
    354                 return false;
    355             }
    356             return service.explicitCallTransfer(device);
    357         }
    358 
    359         @Override
    360         public boolean enterPrivateMode(BluetoothDevice device, int index) {
    361             HeadsetClientService service = getService();
    362             if (service == null) {
    363                 return false;
    364             }
    365             return service.enterPrivateMode(device, index);
    366         }
    367 
    368         @Override
    369         public boolean redial(BluetoothDevice device) {
    370             HeadsetClientService service = getService();
    371             if (service == null) {
    372                 return false;
    373             }
    374             return service.redial(device);
    375         }
    376 
    377         @Override
    378         public boolean dial(BluetoothDevice device, String number) {
    379             HeadsetClientService service = getService();
    380             if (service == null) {
    381                 return false;
    382             }
    383             return service.dial(device, number);
    384         }
    385 
    386         @Override
    387         public boolean dialMemory(BluetoothDevice device, int location) {
    388             HeadsetClientService service = getService();
    389             if (service == null) {
    390                 return false;
    391             }
    392             return service.dialMemory(device, location);
    393         }
    394 
    395         @Override
    396         public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
    397             HeadsetClientService service = getService();
    398             if (service == null) {
    399                 return null;
    400             }
    401             return service.getCurrentCalls(device);
    402         }
    403 
    404         @Override
    405         public boolean sendDTMF(BluetoothDevice device, byte code) {
    406             HeadsetClientService service = getService();
    407             if (service == null) {
    408                 return false;
    409             }
    410             return service.sendDTMF(device, code);
    411         }
    412 
    413         @Override
    414         public boolean getLastVoiceTagNumber(BluetoothDevice device) {
    415             HeadsetClientService service = getService();
    416             if (service == null) {
    417                 return false;
    418             }
    419             return service.getLastVoiceTagNumber(device);
    420         }
    421 
    422         @Override
    423         public Bundle getCurrentAgEvents(BluetoothDevice device) {
    424             HeadsetClientService service = getService();
    425             if (service == null) {
    426                 return null;
    427             }
    428             return service.getCurrentAgEvents(device);
    429         }
    430 
    431         @Override
    432         public Bundle getCurrentAgFeatures(BluetoothDevice device) {
    433             HeadsetClientService service = getService();
    434             if (service == null) {
    435                 return null;
    436             }
    437             return service.getCurrentAgFeatures(device);
    438         }
    439     };
    440 
    441     // API methods
    442     public static synchronized HeadsetClientService getHeadsetClientService() {
    443         if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) {
    444             if (DBG) {
    445                 Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService);
    446             }
    447             return sHeadsetClientService;
    448         }
    449         if (DBG) {
    450             if (sHeadsetClientService == null) {
    451                 Log.d(TAG, "getHeadsetClientService(): service is NULL");
    452             } else if (!(sHeadsetClientService.isAvailable())) {
    453                 Log.d(TAG, "getHeadsetClientService(): service is not available");
    454             }
    455         }
    456         return null;
    457     }
    458 
    459     private static synchronized void setHeadsetClientService(HeadsetClientService instance) {
    460         if (instance != null && instance.isAvailable()) {
    461             if (DBG) {
    462                 Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService);
    463             }
    464             sHeadsetClientService = instance;
    465         } else {
    466             if (DBG) {
    467                 if (sHeadsetClientService == null) {
    468                     Log.d(TAG, "setHeadsetClientService(): service not available");
    469                 } else if (!sHeadsetClientService.isAvailable()) {
    470                     Log.d(TAG, "setHeadsetClientService(): service is cleaning up");
    471                 }
    472             }
    473         }
    474     }
    475 
    476     private static synchronized void clearHeadsetClientService() {
    477         sHeadsetClientService = null;
    478     }
    479 
    480     public boolean connect(BluetoothDevice device) {
    481         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    482                 "Need BLUETOOTH ADMIN permission");
    483 
    484         if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
    485             return false;
    486         }
    487 
    488         int connectionState = mStateMachine.getConnectionState(device);
    489         if (connectionState == BluetoothProfile.STATE_CONNECTED ||
    490                 connectionState == BluetoothProfile.STATE_CONNECTING) {
    491             return false;
    492         }
    493 
    494         mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT, device);
    495         return true;
    496     }
    497 
    498     boolean disconnect(BluetoothDevice device) {
    499         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    500                 "Need BLUETOOTH ADMIN permission");
    501         int connectionState = mStateMachine.getConnectionState(device);
    502         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    503                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    504             return false;
    505         }
    506 
    507         mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, device);
    508         return true;
    509     }
    510 
    511     public List<BluetoothDevice> getConnectedDevices() {
    512         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    513         return mStateMachine.getConnectedDevices();
    514     }
    515 
    516     private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
    517         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    518         return mStateMachine.getDevicesMatchingConnectionStates(states);
    519     }
    520 
    521     int getConnectionState(BluetoothDevice device) {
    522         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    523         return mStateMachine.getConnectionState(device);
    524     }
    525 
    526     // TODO Should new setting for HeadsetClient priority be created?
    527     public boolean setPriority(BluetoothDevice device, int priority) {
    528         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    529                 "Need BLUETOOTH_ADMIN permission");
    530         Settings.Global.putInt(getContentResolver(),
    531                 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()),
    532                 priority);
    533         if (DBG) {
    534             Log.d(TAG, "Saved priority " + device + " = " + priority);
    535         }
    536         return true;
    537     }
    538 
    539     public int getPriority(BluetoothDevice device) {
    540         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    541                 "Need BLUETOOTH_ADMIN permission");
    542         int priority = Settings.Global.getInt(getContentResolver(),
    543                 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()),
    544                 BluetoothProfile.PRIORITY_UNDEFINED);
    545         return priority;
    546     }
    547 
    548     boolean startVoiceRecognition(BluetoothDevice device) {
    549         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    550         int connectionState = mStateMachine.getConnectionState(device);
    551         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    552                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    553             return false;
    554         }
    555         mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START);
    556         return true;
    557     }
    558 
    559     boolean stopVoiceRecognition(BluetoothDevice device) {
    560         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    561         // It seem that we really need to check the AudioOn state.
    562         // But since we allow startVoiceRecognition in STATE_CONNECTED and
    563         // STATE_CONNECTING state, we do these 2 in this method
    564         int connectionState = mStateMachine.getConnectionState(device);
    565         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    566                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    567             return false;
    568         }
    569         mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_STOP);
    570         return true;
    571     }
    572 
    573     boolean acceptIncomingConnect(BluetoothDevice device) {
    574         // TODO(BT) remove it if stack does access control
    575         return false;
    576     }
    577 
    578     boolean rejectIncomingConnect(BluetoothDevice device) {
    579         // TODO(BT) remove it if stack does access control
    580         return false;
    581     }
    582 
    583     int getAudioState(BluetoothDevice device) {
    584         return mStateMachine.getAudioState(device);
    585     }
    586 
    587     public void setAudioRouteAllowed(boolean allowed) {
    588         mStateMachine.setAudioRouteAllowed(allowed);
    589     }
    590 
    591     public boolean getAudioRouteAllowed() {
    592         return mStateMachine.getAudioRouteAllowed();
    593     }
    594 
    595     boolean connectAudio() {
    596         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
    597         if (!mStateMachine.isConnected()) {
    598             return false;
    599         }
    600         if (mStateMachine.isAudioOn()) {
    601             return false;
    602         }
    603         mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
    604         return true;
    605     }
    606 
    607     boolean disconnectAudio() {
    608         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
    609         if (!mStateMachine.isAudioOn()) {
    610             return false;
    611         }
    612         mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
    613         return true;
    614     }
    615 
    616     boolean holdCall(BluetoothDevice device) {
    617         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    618         int connectionState = mStateMachine.getConnectionState(device);
    619         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    620                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    621             return false;
    622         }
    623         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.HOLD_CALL);
    624         mStateMachine.sendMessage(msg);
    625         return true;
    626     }
    627 
    628     boolean acceptCall(BluetoothDevice device, int flag) {
    629         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    630         int connectionState = mStateMachine.getConnectionState(device);
    631         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    632                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    633             return false;
    634         }
    635         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL);
    636         msg.arg1 = flag;
    637         mStateMachine.sendMessage(msg);
    638         return true;
    639     }
    640 
    641     boolean rejectCall(BluetoothDevice device) {
    642         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    643         int connectionState = mStateMachine.getConnectionState(device);
    644         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    645                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    646             return false;
    647         }
    648 
    649         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REJECT_CALL);
    650         mStateMachine.sendMessage(msg);
    651         return true;
    652     }
    653 
    654     boolean terminateCall(BluetoothDevice device, int index) {
    655         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    656         int connectionState = mStateMachine.getConnectionState(device);
    657         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    658                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    659             return false;
    660         }
    661 
    662         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL);
    663         msg.arg1 = index;
    664         mStateMachine.sendMessage(msg);
    665         return true;
    666     }
    667 
    668     boolean enterPrivateMode(BluetoothDevice device, int index) {
    669         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    670         int connectionState = mStateMachine.getConnectionState(device);
    671         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    672                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    673             return false;
    674         }
    675 
    676         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE);
    677         msg.arg1 = index;
    678         mStateMachine.sendMessage(msg);
    679         return true;
    680     }
    681 
    682     boolean redial(BluetoothDevice device) {
    683         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    684         int connectionState = mStateMachine.getConnectionState(device);
    685         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    686                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    687             return false;
    688         }
    689 
    690         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REDIAL);
    691         mStateMachine.sendMessage(msg);
    692         return true;
    693     }
    694 
    695     boolean dial(BluetoothDevice device, String number) {
    696         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    697         int connectionState = mStateMachine.getConnectionState(device);
    698         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    699                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    700             return false;
    701         }
    702 
    703         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
    704         msg.obj = number;
    705         mStateMachine.sendMessage(msg);
    706         return true;
    707     }
    708 
    709     boolean dialMemory(BluetoothDevice device, int location) {
    710         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    711         int connectionState = mStateMachine.getConnectionState(device);
    712         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    713                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    714             return false;
    715         }
    716         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_MEMORY);
    717         msg.arg1 = location;
    718         mStateMachine.sendMessage(msg);
    719         return true;
    720     }
    721 
    722     public boolean sendDTMF(BluetoothDevice device, byte code) {
    723         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    724         int connectionState = mStateMachine.getConnectionState(device);
    725         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    726                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    727             return false;
    728         }
    729         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.SEND_DTMF);
    730         msg.arg1 = code;
    731         mStateMachine.sendMessage(msg);
    732         return true;
    733     }
    734 
    735     public boolean getLastVoiceTagNumber(BluetoothDevice device) {
    736         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    737         int connectionState = mStateMachine.getConnectionState(device);
    738         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    739                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    740             return false;
    741         }
    742         Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.LAST_VTAG_NUMBER);
    743         mStateMachine.sendMessage(msg);
    744         return true;
    745     }
    746 
    747     public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
    748         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    749         int connectionState = mStateMachine.getConnectionState(device);
    750         if (connectionState != BluetoothProfile.STATE_CONNECTED) {
    751             return null;
    752         }
    753         return mStateMachine.getCurrentCalls();
    754     }
    755 
    756     public boolean explicitCallTransfer(BluetoothDevice device) {
    757         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    758         int connectionState = mStateMachine.getConnectionState(device);
    759         if (connectionState != BluetoothProfile.STATE_CONNECTED &&
    760                 connectionState != BluetoothProfile.STATE_CONNECTING) {
    761             return false;
    762         }
    763         Message msg = mStateMachine
    764                 .obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER);
    765         mStateMachine.sendMessage(msg);
    766         return true;
    767     }
    768 
    769     public Bundle getCurrentAgEvents(BluetoothDevice device) {
    770         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    771         int connectionState = mStateMachine.getConnectionState(device);
    772         if (connectionState != BluetoothProfile.STATE_CONNECTED) {
    773             return null;
    774         }
    775         return mStateMachine.getCurrentAgEvents();
    776     }
    777 
    778     public Bundle getCurrentAgFeatures(BluetoothDevice device) {
    779         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    780         int connectionState = mStateMachine.getConnectionState(device);
    781         if (connectionState != BluetoothProfile.STATE_CONNECTED) {
    782             return null;
    783         }
    784         return mStateMachine.getCurrentAgFeatures();
    785     }
    786 
    787     @Override
    788     public void dump(StringBuilder sb) {
    789         super.dump(sb);
    790         if (mStateMachine != null) {
    791             mStateMachine.dump(sb);
    792         }
    793     }
    794 }
    795