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