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