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