LocalBluetoothProfileManager.java revision 498d12bac0df509a4f74a4df8a8c69ec22583a1a
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.bluetooth;
18
19import com.android.settings.R;
20
21import android.bluetooth.BluetoothA2dp;
22import android.bluetooth.BluetoothAdapter;
23import android.bluetooth.BluetoothDevice;
24import android.bluetooth.BluetoothHeadset;
25import android.bluetooth.BluetoothInputDevice;
26import android.bluetooth.BluetoothPan;
27import android.bluetooth.BluetoothProfile;
28import android.bluetooth.BluetoothUuid;
29import android.os.Handler;
30import android.os.ParcelUuid;
31import android.util.Log;
32
33import java.util.HashMap;
34import java.util.Iterator;
35import java.util.LinkedList;
36import java.util.List;
37import java.util.Map;
38
39/**
40 * LocalBluetoothProfileManager is an abstract class defining the basic
41 * functionality related to a profile.
42 */
43public abstract class LocalBluetoothProfileManager {
44    private static final String TAG = "LocalBluetoothProfileManager";
45
46    /* package */ static final ParcelUuid[] HEADSET_PROFILE_UUIDS = new ParcelUuid[] {
47        BluetoothUuid.HSP,
48        BluetoothUuid.Handsfree,
49    };
50
51    /* package */ static final ParcelUuid[] A2DP_SINK_PROFILE_UUIDS = new ParcelUuid[] {
52        BluetoothUuid.AudioSink,
53        BluetoothUuid.AdvAudioDist,
54    };
55
56    /* package */ static final ParcelUuid[] A2DP_SRC_PROFILE_UUIDS = new ParcelUuid[] {
57        BluetoothUuid.AudioSource
58    };
59
60    /* package */ static final ParcelUuid[] OPP_PROFILE_UUIDS = new ParcelUuid[] {
61        BluetoothUuid.ObexObjectPush
62    };
63
64    /* package */ static final ParcelUuid[] HID_PROFILE_UUIDS = new ParcelUuid[] {
65        BluetoothUuid.Hid
66    };
67
68    /* package */ static final ParcelUuid[] PANU_PROFILE_UUIDS = new ParcelUuid[] {
69        BluetoothUuid.PANU
70    };
71
72    /* package */ static final ParcelUuid[] NAP_PROFILE_UUIDS = new ParcelUuid[] {
73        BluetoothUuid.NAP
74    };
75
76    /**
77     * An interface for notifying BluetoothHeadset IPC clients when they have
78     * been connected to the BluetoothHeadset service.
79     */
80    public interface ServiceListener {
81        /**
82         * Called to notify the client when this proxy object has been
83         * connected to the BluetoothHeadset service. Clients must wait for
84         * this callback before making IPC calls on the BluetoothHeadset
85         * service.
86         */
87        public void onServiceConnected();
88
89        /**
90         * Called to notify the client that this proxy object has been
91         * disconnected from the BluetoothHeadset service. Clients must not
92         * make IPC calls on the BluetoothHeadset service after this callback.
93         * This callback will currently only occur if the application hosting
94         * the BluetoothHeadset service, but may be called more often in future.
95         */
96        public void onServiceDisconnected();
97    }
98
99    // TODO: close profiles when we're shutting down
100    private static Map<Profile, LocalBluetoothProfileManager> sProfileMap =
101            new HashMap<Profile, LocalBluetoothProfileManager>();
102
103    protected LocalBluetoothManager mLocalManager;
104
105    public static void init(LocalBluetoothManager localManager) {
106        synchronized (sProfileMap) {
107            if (sProfileMap.size() == 0) {
108                LocalBluetoothProfileManager profileManager;
109
110                profileManager = new A2dpProfileManager(localManager);
111                sProfileMap.put(Profile.A2DP, profileManager);
112
113                profileManager = new HeadsetProfileManager(localManager);
114                sProfileMap.put(Profile.HEADSET, profileManager);
115
116                profileManager = new OppProfileManager(localManager);
117                sProfileMap.put(Profile.OPP, profileManager);
118
119                profileManager = new HidProfileManager(localManager);
120                sProfileMap.put(Profile.HID, profileManager);
121
122                profileManager = new PanProfileManager(localManager);
123                sProfileMap.put(Profile.PAN, profileManager);
124            }
125        }
126    }
127
128    // TODO(): Combine the init and updateLocalProfiles codes.
129    // init can get called from various paths, it makes no sense to add and then delete.
130    public static void updateLocalProfiles(LocalBluetoothManager localManager, ParcelUuid[] uuids) {
131        if (!BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
132            !BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
133            sProfileMap.remove(Profile.HEADSET);
134        }
135
136        if (!BluetoothUuid.containsAnyUuid(uuids, A2DP_SRC_PROFILE_UUIDS)) {
137            sProfileMap.remove(Profile.A2DP);
138        }
139
140        if (!BluetoothUuid.containsAnyUuid(uuids, OPP_PROFILE_UUIDS)) {
141            sProfileMap.remove(Profile.OPP);
142        }
143
144        if (!BluetoothUuid.containsAnyUuid(uuids, PANU_PROFILE_UUIDS)) {
145            sProfileMap.remove(Profile.PAN);
146        }
147
148        // There is no local SDP record for HID and Settings app doesn't control PBAP
149    }
150
151    private static LinkedList<ServiceListener> mServiceListeners =
152            new LinkedList<ServiceListener>();
153
154    public static void addServiceListener(ServiceListener l) {
155        mServiceListeners.add(l);
156    }
157
158    public static void removeServiceListener(ServiceListener l) {
159        mServiceListeners.remove(l);
160    }
161
162    public static boolean isManagerReady() {
163        // Getting just the headset profile is fine for now. Will need to deal with A2DP
164        // and others if they aren't always in a ready state.
165        LocalBluetoothProfileManager profileManager = sProfileMap.get(Profile.HEADSET);
166        if (profileManager == null) {
167            return sProfileMap.size() > 0;
168        }
169        return profileManager.isProfileReady();
170    }
171
172    public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager,
173            Profile profile) {
174        // Note: This code assumes that "localManager" is same as the
175        // LocalBluetoothManager that was used to initialize the sProfileMap.
176        // If that every changes, we can't just keep one copy of sProfileMap.
177        synchronized (sProfileMap) {
178            LocalBluetoothProfileManager profileManager = sProfileMap.get(profile);
179            if (profileManager == null) {
180                Log.e(TAG, "profileManager can't be found for " + profile.toString());
181            }
182            return profileManager;
183        }
184    }
185
186    /**
187     * Temporary method to fill profiles based on a device's class.
188     *
189     * NOTE: This list happens to define the connection order. We should put this logic in a more
190     * well known place when this method is no longer temporary.
191     * @param uuids of the remote device
192     * @param localUuids UUIDs of the local device
193     * @param profiles The list of profiles to fill
194     */
195    public static void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
196        List<Profile> profiles) {
197        profiles.clear();
198
199        if (uuids == null) {
200            return;
201        }
202
203        if (sProfileMap.containsKey(Profile.HEADSET)) {
204            if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
205                BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
206                (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
207                BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
208                    profiles.add(Profile.HEADSET);
209            }
210        }
211
212
213        if (BluetoothUuid.containsAnyUuid(uuids, A2DP_SINK_PROFILE_UUIDS) &&
214            sProfileMap.containsKey(Profile.A2DP)) {
215            profiles.add(Profile.A2DP);
216        }
217
218        if (BluetoothUuid.containsAnyUuid(uuids, OPP_PROFILE_UUIDS) &&
219            sProfileMap.containsKey(Profile.OPP)) {
220            profiles.add(Profile.OPP);
221        }
222
223        if (BluetoothUuid.containsAnyUuid(uuids, HID_PROFILE_UUIDS) &&
224            sProfileMap.containsKey(Profile.HID)) {
225            profiles.add(Profile.HID);
226        }
227
228        if (BluetoothUuid.containsAnyUuid(uuids, PANU_PROFILE_UUIDS) &&
229            sProfileMap.containsKey(Profile.PAN)) {
230            profiles.add(Profile.PAN);
231        }
232    }
233
234    protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) {
235        mLocalManager = localManager;
236    }
237
238    public abstract List<BluetoothDevice> getConnectedDevices();
239
240    public abstract boolean connect(BluetoothDevice device);
241
242    public abstract boolean disconnect(BluetoothDevice device);
243
244    public abstract int getConnectionStatus(BluetoothDevice device);
245
246    public abstract int getSummary(BluetoothDevice device);
247
248    public abstract int convertState(int a2dpState);
249
250    public abstract boolean isPreferred(BluetoothDevice device);
251
252    public abstract int getPreferred(BluetoothDevice device);
253
254    public abstract void setPreferred(BluetoothDevice device, boolean preferred);
255
256    public boolean isConnected(BluetoothDevice device) {
257        return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device));
258    }
259
260    public abstract boolean isProfileReady();
261
262    public int getDrawableResource() {
263        return R.drawable.ic_bt_headphones_a2dp;
264    }
265
266    public static enum Profile {
267        HEADSET(R.string.bluetooth_profile_headset),
268        A2DP(R.string.bluetooth_profile_a2dp),
269        OPP(R.string.bluetooth_profile_opp),
270        HID(R.string.bluetooth_profile_hid),
271        PAN(R.string.bluetooth_profile_pan);
272
273        public final int localizedString;
274
275        private Profile(int localizedString) {
276            this.localizedString = localizedString;
277        }
278    }
279
280    /**
281     * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
282     */
283    private static class A2dpProfileManager extends LocalBluetoothProfileManager
284          implements BluetoothProfile.ServiceListener {
285        private BluetoothA2dp mService;
286
287        // TODO(): The calls must wait for mService. Its not null just
288        // because it runs in the system server.
289        public A2dpProfileManager(LocalBluetoothManager localManager) {
290            super(localManager);
291            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
292            adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.A2DP);
293
294        }
295
296        public void onServiceConnected(int profile, BluetoothProfile proxy) {
297            mService = (BluetoothA2dp) proxy;
298        }
299
300        public void onServiceDisconnected(int profile) {
301            mService = null;
302        }
303
304        @Override
305        public List<BluetoothDevice> getConnectedDevices() {
306            return mService.getDevicesMatchingConnectionStates(
307                  new int[] {BluetoothProfile.STATE_CONNECTED,
308                             BluetoothProfile.STATE_CONNECTING,
309                             BluetoothProfile.STATE_DISCONNECTING});
310        }
311
312        @Override
313        public boolean connect(BluetoothDevice device) {
314            List<BluetoothDevice> sinks = getConnectedDevices();
315            if (sinks != null) {
316                for (BluetoothDevice sink : sinks) {
317                    mService.disconnect(sink);
318                }
319            }
320            return mService.connect(device);
321        }
322
323        @Override
324        public boolean disconnect(BluetoothDevice device) {
325            // Downgrade priority as user is disconnecting the sink.
326            if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
327                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
328            }
329            return mService.disconnect(device);
330        }
331
332        @Override
333        public int getConnectionStatus(BluetoothDevice device) {
334            return convertState(mService.getConnectionState(device));
335        }
336
337        @Override
338        public int getSummary(BluetoothDevice device) {
339            int connectionStatus = getConnectionStatus(device);
340
341            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
342                return R.string.bluetooth_a2dp_profile_summary_connected;
343            } else {
344                return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
345            }
346        }
347
348        @Override
349        public boolean isPreferred(BluetoothDevice device) {
350            return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
351        }
352
353        @Override
354        public int getPreferred(BluetoothDevice device) {
355            return mService.getPriority(device);
356        }
357
358        @Override
359        public void setPreferred(BluetoothDevice device, boolean preferred) {
360            if (preferred) {
361                if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
362                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
363                }
364            } else {
365                mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
366            }
367        }
368
369        @Override
370        public int convertState(int a2dpState) {
371            switch (a2dpState) {
372            case BluetoothProfile.STATE_CONNECTED:
373                return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
374            case BluetoothProfile.STATE_CONNECTING:
375                return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
376            case BluetoothProfile.STATE_DISCONNECTED:
377                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
378            case BluetoothProfile.STATE_DISCONNECTING:
379                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
380            case BluetoothA2dp.STATE_PLAYING:
381                return SettingsBtStatus.CONNECTION_STATUS_ACTIVE;
382            default:
383                return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
384            }
385        }
386
387        @Override
388        public boolean isProfileReady() {
389            return true;
390        }
391
392        @Override
393        public int getDrawableResource() {
394            return R.drawable.ic_bt_headphones_a2dp;
395        }
396    }
397
398    /**
399     * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
400     */
401    private static class HeadsetProfileManager extends LocalBluetoothProfileManager
402            implements BluetoothProfile.ServiceListener {
403        private BluetoothHeadset mService;
404        private Handler mUiHandler = new Handler();
405        private boolean profileReady = false;
406
407        // TODO(): The calls must get queued if mService becomes null.
408        // It can happen  when phone app crashes for some reason.
409        // All callers should have service listeners. Dock Service is the only
410        // one right now.
411        public HeadsetProfileManager(LocalBluetoothManager localManager) {
412            super(localManager);
413            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
414            adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.HEADSET);
415        }
416
417        public void onServiceConnected(int profile, BluetoothProfile proxy) {
418            mService = (BluetoothHeadset) proxy;
419            profileReady = true;
420            // This could be called on a non-UI thread, funnel to UI thread.
421            mUiHandler.post(new Runnable() {
422                public void run() {
423                    /*
424                     * We just bound to the service, so refresh the UI of the
425                     * headset device.
426                     */
427                    List<BluetoothDevice> deviceList = mService.getConnectedDevices();
428                    if (deviceList.size() == 0) return;
429
430                    mLocalManager.getCachedDeviceManager()
431                            .onProfileStateChanged(deviceList.get(0), Profile.HEADSET,
432                                                   BluetoothProfile.STATE_CONNECTED);
433                }
434            });
435
436            if (mServiceListeners.size() > 0) {
437                Iterator<ServiceListener> it = mServiceListeners.iterator();
438                while(it.hasNext()) {
439                    it.next().onServiceConnected();
440                }
441            }
442        }
443
444        public void onServiceDisconnected(int profile) {
445            mService = null;
446            profileReady = false;
447            if (mServiceListeners.size() > 0) {
448                Iterator<ServiceListener> it = mServiceListeners.iterator();
449                while(it.hasNext()) {
450                    it.next().onServiceDisconnected();
451                }
452            }
453        }
454
455        @Override
456        public boolean isProfileReady() {
457            return profileReady;
458        }
459
460        @Override
461        public List<BluetoothDevice> getConnectedDevices() {
462            return mService.getConnectedDevices();
463        }
464
465        @Override
466        public boolean connect(BluetoothDevice device) {
467            return mService.connect(device);
468        }
469
470        @Override
471        public boolean disconnect(BluetoothDevice device) {
472            List<BluetoothDevice> deviceList = getConnectedDevices();
473            if (deviceList.size() != 0 && deviceList.get(0).equals(device)) {
474                // Downgrade priority as user is disconnecting the headset.
475                if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
476                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
477                }
478                return mService.disconnect(device);
479            } else {
480                return false;
481            }
482        }
483
484        @Override
485        public int getConnectionStatus(BluetoothDevice device) {
486            List<BluetoothDevice> deviceList = getConnectedDevices();
487
488            return deviceList.size() > 0 && deviceList.get(0).equals(device)
489                    ? convertState(mService.getConnectionState(device))
490                    : SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
491        }
492
493        @Override
494        public int getSummary(BluetoothDevice device) {
495            int connectionStatus = getConnectionStatus(device);
496
497            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
498                return R.string.bluetooth_headset_profile_summary_connected;
499            } else {
500                return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
501            }
502        }
503
504        @Override
505        public boolean isPreferred(BluetoothDevice device) {
506            return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
507        }
508
509        @Override
510        public int getPreferred(BluetoothDevice device) {
511            return mService.getPriority(device);
512        }
513
514        @Override
515        public void setPreferred(BluetoothDevice device, boolean preferred) {
516            if (preferred) {
517                if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
518                    mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
519                }
520            } else {
521                mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
522            }
523        }
524
525        @Override
526        public int convertState(int headsetState) {
527            switch (headsetState) {
528            case BluetoothProfile.STATE_CONNECTED:
529                return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
530            case BluetoothProfile.STATE_CONNECTING:
531                return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
532            case BluetoothProfile.STATE_DISCONNECTED:
533                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
534            default:
535                return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
536            }
537        }
538
539        @Override
540        public int getDrawableResource() {
541            return R.drawable.ic_bt_headset_hfp;
542        }
543    }
544
545    /**
546     * OppProfileManager
547     */
548    private static class OppProfileManager extends LocalBluetoothProfileManager {
549
550        public OppProfileManager(LocalBluetoothManager localManager) {
551            super(localManager);
552        }
553
554        @Override
555        public List<BluetoothDevice> getConnectedDevices() {
556            return null;
557        }
558
559        @Override
560        public boolean connect(BluetoothDevice device) {
561            return false;
562        }
563
564        @Override
565        public boolean disconnect(BluetoothDevice device) {
566            return false;
567        }
568
569        @Override
570        public int getConnectionStatus(BluetoothDevice device) {
571            return -1;
572        }
573
574        @Override
575        public int getSummary(BluetoothDevice device) {
576            int connectionStatus = getConnectionStatus(device);
577
578            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
579                return R.string.bluetooth_opp_profile_summary_connected;
580            } else {
581                return R.string.bluetooth_opp_profile_summary_not_connected;
582            }
583        }
584
585        @Override
586        public boolean isPreferred(BluetoothDevice device) {
587            return false;
588        }
589
590        @Override
591        public int getPreferred(BluetoothDevice device) {
592            return -1;
593        }
594
595        @Override
596        public void setPreferred(BluetoothDevice device, boolean preferred) {
597        }
598
599        @Override
600        public boolean isProfileReady() {
601            return true;
602        }
603
604        @Override
605        public int convertState(int oppState) {
606            switch (oppState) {
607            case 0:
608                return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
609            case 1:
610                return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
611            case 2:
612                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
613            default:
614                return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
615            }
616        }
617
618        @Override
619        public int getDrawableResource() {
620            // TODO:
621            return 0;
622        }
623    }
624
625    private static class HidProfileManager extends LocalBluetoothProfileManager {
626        private BluetoothInputDevice mService;
627
628        public HidProfileManager(LocalBluetoothManager localManager) {
629            super(localManager);
630            mService = new BluetoothInputDevice(localManager.getContext());
631        }
632
633        @Override
634        public boolean connect(BluetoothDevice device) {
635            return mService.connectInputDevice(device);
636        }
637
638        @Override
639        public int convertState(int hidState) {
640            switch (hidState) {
641            case BluetoothInputDevice.STATE_CONNECTED:
642                return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
643            case BluetoothInputDevice.STATE_CONNECTING:
644                return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
645            case BluetoothInputDevice.STATE_DISCONNECTED:
646                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
647            case BluetoothInputDevice.STATE_DISCONNECTING:
648                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
649            default:
650                return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
651            }
652        }
653
654        @Override
655        public boolean disconnect(BluetoothDevice device) {
656            return mService.disconnectInputDevice(device);
657        }
658
659        @Override
660        public List<BluetoothDevice> getConnectedDevices() {
661            return mService.getConnectedInputDevices();
662        }
663
664        @Override
665        public int getConnectionStatus(BluetoothDevice device) {
666            return convertState(mService.getInputDeviceState(device));
667        }
668
669        @Override
670        public int getPreferred(BluetoothDevice device) {
671            return mService.getInputDevicePriority(device);
672        }
673
674        @Override
675        public int getSummary(BluetoothDevice device) {
676            final int connectionStatus = getConnectionStatus(device);
677
678            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
679                return R.string.bluetooth_hid_profile_summary_connected;
680            } else {
681                return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
682            }
683        }
684
685        @Override
686        public boolean isPreferred(BluetoothDevice device) {
687            return mService.getInputDevicePriority(device) > BluetoothInputDevice.PRIORITY_OFF;
688        }
689
690        @Override
691        public boolean isProfileReady() {
692            return true;
693        }
694
695        @Override
696        public void setPreferred(BluetoothDevice device, boolean preferred) {
697            if (preferred) {
698                if (mService.getInputDevicePriority(device) < BluetoothInputDevice.PRIORITY_ON) {
699                    mService.setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON);
700                }
701            } else {
702                mService.setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_OFF);
703            }
704        }
705
706        @Override
707        public int getDrawableResource() {
708            // TODO:
709            return 0;
710        }
711    }
712
713    private static class PanProfileManager extends LocalBluetoothProfileManager {
714        private BluetoothPan mService;
715
716        public PanProfileManager(LocalBluetoothManager localManager) {
717            super(localManager);
718            mService = new BluetoothPan(localManager.getContext());
719        }
720
721        @Override
722        public boolean connect(BluetoothDevice device) {
723            return mService.connect(device);
724        }
725
726        @Override
727        public int convertState(int panState) {
728            switch (panState) {
729            case BluetoothPan.STATE_CONNECTED:
730                return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
731            case BluetoothPan.STATE_CONNECTING:
732                return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
733            case BluetoothPan.STATE_DISCONNECTED:
734                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
735            case BluetoothPan.STATE_DISCONNECTING:
736                return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
737            default:
738                return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
739            }
740        }
741
742        @Override
743        public boolean disconnect(BluetoothDevice device) {
744            return mService.disconnect(device);
745        }
746
747        @Override
748        public int getSummary(BluetoothDevice device) {
749            final int connectionStatus = getConnectionStatus(device);
750
751            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
752                return R.string.bluetooth_pan_profile_summary_connected;
753            } else {
754                return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
755            }
756        }
757
758        @Override
759        public boolean isProfileReady() {
760            return true;
761        }
762
763        @Override
764        public List<BluetoothDevice> getConnectedDevices() {
765            return mService.getConnectedDevices();
766        }
767
768        @Override
769        public int getConnectionStatus(BluetoothDevice device) {
770            return convertState(mService.getPanDeviceState(device));
771        }
772
773        @Override
774        public int getPreferred(BluetoothDevice device) {
775            return -1;
776        }
777
778        @Override
779        public boolean isPreferred(BluetoothDevice device) {
780            return false;
781        }
782
783        @Override
784        public void setPreferred(BluetoothDevice device, boolean preferred) {
785            return;
786        }
787
788        @Override
789        public int getDrawableResource() {
790            // TODO:
791            return 0;
792        }
793    }
794}
795