17ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/* 27ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Copyright (C) 2012 The Android Open Source Project 37ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * 47ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 57ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * you may not use this file except in compliance with the License. 67ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * You may obtain a copy of the License at 77ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * 87ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 97ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * 107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Unless required by applicable law or agreed to in writing, software 117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * distributed under the License is distributed on an "AS IS" BASIS, 127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * See the License for the specific language governing permissions and 147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * limitations under the License. 157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */ 167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpackage com.android.settingslib.bluetooth; 187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothAdapter; 207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothClass; 217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothDevice; 227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothInputDevice; 237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothProfile; 247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.Context; 257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.util.Log; 267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport com.android.settingslib.R; 287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.List; 307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/** 327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * HidProfile handles Bluetooth HID profile. 337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */ 347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpublic final class HidProfile implements LocalBluetoothProfile { 357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private static final String TAG = "HidProfile"; 367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private static boolean V = true; 377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private BluetoothInputDevice mService; 397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private boolean mIsProfileReady; 407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private final LocalBluetoothAdapter mLocalAdapter; 427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private final CachedBluetoothDeviceManager mDeviceManager; 437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private final LocalBluetoothProfileManager mProfileManager; 447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk static final String NAME = "HID"; 467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk // Order of this profile in device profiles list 487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private static final int ORDINAL = 3; 497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk // These callbacks run on the main thread. 517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk private final class InputDeviceServiceListener 527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk implements BluetoothProfile.ServiceListener { 537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public void onServiceConnected(int profile, BluetoothProfile proxy) { 557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (V) Log.d(TAG,"Bluetooth service connected"); 567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mService = (BluetoothInputDevice) proxy; 577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk // We just bound to the service, so refresh the UI for any connected HID devices. 587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk while (!deviceList.isEmpty()) { 607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk BluetoothDevice nextDevice = deviceList.remove(0); 617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk // we may add a new device here, but generally this should not happen 637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (device == null) { 647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk Log.w(TAG, "HidProfile found new device: " + nextDevice); 657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); 667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED); 687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk device.refresh(); 697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mIsProfileReady=true; 717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public void onServiceDisconnected(int profile) { 747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (V) Log.d(TAG,"Bluetooth service disconnected"); 757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mIsProfileReady=false; 767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean isProfileReady() { 807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return mIsProfileReady; 817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk HidProfile(Context context, LocalBluetoothAdapter adapter, 847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk CachedBluetoothDeviceManager deviceManager, 857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk LocalBluetoothProfileManager profileManager) { 867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mLocalAdapter = adapter; 877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mDeviceManager = deviceManager; 887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mProfileManager = profileManager; 897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk adapter.getProfileProxy(context, new InputDeviceServiceListener(), 907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk BluetoothProfile.INPUT_DEVICE); 917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean isConnectable() { 947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return true; 957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean isAutoConnectable() { 987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return true; 997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean connect(BluetoothDevice device) { 1027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) return false; 1037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return mService.connect(device); 1047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean disconnect(BluetoothDevice device) { 1077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) return false; 1087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return mService.disconnect(device); 1097ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getConnectionStatus(BluetoothDevice device) { 1127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) { 1137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return BluetoothProfile.STATE_DISCONNECTED; 1147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 1167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return !deviceList.isEmpty() && deviceList.get(0).equals(device) 1187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk ? mService.getConnectionState(device) 1197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk : BluetoothProfile.STATE_DISCONNECTED; 1207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public boolean isPreferred(BluetoothDevice device) { 1237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) return false; 1247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 1257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getPreferred(BluetoothDevice device) { 1287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) return BluetoothProfile.PRIORITY_OFF; 1297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return mService.getPriority(device); 1307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public void setPreferred(BluetoothDevice device, boolean preferred) { 1337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService == null) return; 1347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (preferred) { 1357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 1367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 1377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } else { 1397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 1407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public String toString() { 1447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return NAME; 1457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getOrdinal() { 1487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return ORDINAL; 1497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getNameResource(BluetoothDevice device) { 1527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk // TODO: distinguish between keyboard and mouse? 1537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.string.bluetooth_profile_hid; 1547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getSummaryResourceForDevice(BluetoothDevice device) { 1577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk int state = getConnectionStatus(device); 1587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk switch (state) { 1597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk case BluetoothProfile.STATE_DISCONNECTED: 1607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.string.bluetooth_hid_profile_summary_use_for; 1617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk case BluetoothProfile.STATE_CONNECTED: 1637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.string.bluetooth_hid_profile_summary_connected; 1647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk default: 1667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return Utils.getConnectionStateSummary(state); 1677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public int getDrawableResource(BluetoothClass btClass) { 1717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (btClass == null) { 1727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.drawable.ic_lockscreen_ime; 1737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return getHidClassDrawable(btClass); 1757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk public static int getHidClassDrawable(BluetoothClass btClass) { 1787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk switch (btClass.getDeviceClass()) { 1797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk case BluetoothClass.Device.PERIPHERAL_KEYBOARD: 1807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING: 1817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.drawable.ic_lockscreen_ime; 1827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk case BluetoothClass.Device.PERIPHERAL_POINTING: 1837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.drawable.ic_bt_pointing_hid; 1847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk default: 1857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk return R.drawable.ic_bt_misc_hid; 1867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk 1897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk protected void finalize() { 1907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (V) Log.d(TAG, "finalize()"); 1917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk if (mService != null) { 1927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk try { 1937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE, 1947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mService); 1957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk mService = null; 1967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk }catch (Throwable t) { 1977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk Log.w(TAG, "Error cleaning up HID proxy", t); 1987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 1997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 2007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk } 2017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk} 202