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