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