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