1436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby/* 2b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie * Copyright (C) 2012 The Android Open Source Project 3436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 4436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Licensed under the Apache License, Version 2.0 (the "License"); 5436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * you may not use this file except in compliance with the License. 6436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * You may obtain a copy of the License at 7436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 8436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * http://www.apache.org/licenses/LICENSE-2.0 9436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 10436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Unless required by applicable law or agreed to in writing, software 11436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * distributed under the License is distributed on an "AS IS" BASIS, 12436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * See the License for the specific language governing permissions and 14436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * limitations under the License. 15436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 16436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 17436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambypackage com.android.settings.bluetooth; 18436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 19654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredcimport android.bluetooth.BluetoothAdapter; 20436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothClass; 21436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothDevice; 22436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothInputDevice; 23436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothProfile; 24436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Context; 25654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredcimport android.util.Log; 26436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 27436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport com.android.settings.R; 28436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 29436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.List; 30436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 31436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby/** 32436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * HidProfile handles Bluetooth HID profile. 33436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 34436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class HidProfile implements LocalBluetoothProfile { 35654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private static final String TAG = "HidProfile"; 36654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private static boolean V = true; 37654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 38436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private BluetoothInputDevice mService; 39654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private boolean mIsProfileReady; 40436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 4118c4317b93fce47109017efdab089dec4b01f790Jake Hamby private final LocalBluetoothAdapter mLocalAdapter; 4218c4317b93fce47109017efdab089dec4b01f790Jake Hamby private final CachedBluetoothDeviceManager mDeviceManager; 4318c4317b93fce47109017efdab089dec4b01f790Jake Hamby private final LocalBluetoothProfileManager mProfileManager; 4418c4317b93fce47109017efdab089dec4b01f790Jake Hamby 45436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static final String NAME = "HID"; 46436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 47436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Order of this profile in device profiles list 48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static final int ORDINAL = 3; 49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 50436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // These callbacks run on the main thread. 51436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final class InputDeviceServiceListener 52436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby implements BluetoothProfile.ServiceListener { 53436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceConnected(int profile, BluetoothProfile proxy) { 55654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG,"Bluetooth service connected"); 56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService = (BluetoothInputDevice) proxy; 5718c4317b93fce47109017efdab089dec4b01f790Jake Hamby // We just bound to the service, so refresh the UI for any connected HID devices. 5818c4317b93fce47109017efdab089dec4b01f790Jake Hamby List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 5918c4317b93fce47109017efdab089dec4b01f790Jake Hamby while (!deviceList.isEmpty()) { 6018c4317b93fce47109017efdab089dec4b01f790Jake Hamby BluetoothDevice nextDevice = deviceList.remove(0); 6118c4317b93fce47109017efdab089dec4b01f790Jake Hamby CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 6218c4317b93fce47109017efdab089dec4b01f790Jake Hamby // we may add a new device here, but generally this should not happen 6318c4317b93fce47109017efdab089dec4b01f790Jake Hamby if (device == null) { 6418c4317b93fce47109017efdab089dec4b01f790Jake Hamby Log.w(TAG, "HidProfile found new device: " + nextDevice); 6518c4317b93fce47109017efdab089dec4b01f790Jake Hamby device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); 6618c4317b93fce47109017efdab089dec4b01f790Jake Hamby } 6718c4317b93fce47109017efdab089dec4b01f790Jake Hamby device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED); 6818c4317b93fce47109017efdab089dec4b01f790Jake Hamby device.refresh(); 6918c4317b93fce47109017efdab089dec4b01f790Jake Hamby } 70654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=true; 71436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 72436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceDisconnected(int profile) { 74654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG,"Bluetooth service disconnected"); 75654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=false; 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 79654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc public boolean isProfileReady() { 80654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc return mIsProfileReady; 81654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 82654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 8318c4317b93fce47109017efdab089dec4b01f790Jake Hamby HidProfile(Context context, LocalBluetoothAdapter adapter, 8418c4317b93fce47109017efdab089dec4b01f790Jake Hamby CachedBluetoothDeviceManager deviceManager, 8518c4317b93fce47109017efdab089dec4b01f790Jake Hamby LocalBluetoothProfileManager profileManager) { 8618c4317b93fce47109017efdab089dec4b01f790Jake Hamby mLocalAdapter = adapter; 8718c4317b93fce47109017efdab089dec4b01f790Jake Hamby mDeviceManager = deviceManager; 8818c4317b93fce47109017efdab089dec4b01f790Jake Hamby mProfileManager = profileManager; 89436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby adapter.getProfileProxy(context, new InputDeviceServiceListener(), 90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.INPUT_DEVICE); 91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 92436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isConnectable() { 94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isAutoConnectable() { 98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean connect(BluetoothDevice device) { 102afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.connect(device); 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 105436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 106436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean disconnect(BluetoothDevice device) { 107afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.disconnect(device); 109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 111436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getConnectionStatus(BluetoothDevice device) { 112afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) { 113afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc return BluetoothProfile.STATE_DISCONNECTED; 114afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc } 115436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return !deviceList.isEmpty() && deviceList.get(0).equals(device) 118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ? mService.getConnectionState(device) 119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby : BluetoothProfile.STATE_DISCONNECTED; 120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 122436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isPreferred(BluetoothDevice device) { 123afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getPreferred(BluetoothDevice device) { 128afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return BluetoothProfile.PRIORITY_OFF; 129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device); 130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void setPreferred(BluetoothDevice device, boolean preferred) { 133afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return; 134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (preferred) { 135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else { 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public String toString() { 144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return NAME; 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getOrdinal() { 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return ORDINAL; 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 15179be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby public int getNameResource(BluetoothDevice device) { 15279be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby // TODO: distinguish between keyboard and mouse? 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_profile_hid; 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getSummaryResourceForDevice(BluetoothDevice device) { 157afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc int state = getConnectionStatus(device); 158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby switch (state) { 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_DISCONNECTED: 160436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_hid_profile_summary_use_for; 161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 162436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_CONNECTED: 163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_hid_profile_summary_connected; 164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 165436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby default: 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return Utils.getConnectionStateSummary(state); 167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getDrawableResource(BluetoothClass btClass) { 171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (btClass == null) { 172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_keyboard_hid; 173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 174436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return getHidClassDrawable(btClass); 175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static int getHidClassDrawable(BluetoothClass btClass) { 178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby switch (btClass.getDeviceClass()) { 179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothClass.Device.PERIPHERAL_KEYBOARD: 180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING: 181436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_keyboard_hid; 182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothClass.Device.PERIPHERAL_POINTING: 183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_pointing_hid; 184436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby default: 185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_misc_hid; 186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 188654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 189654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc protected void finalize() { 190654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG, "finalize()"); 191654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (mService != null) { 192654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc try { 193b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE, 194b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie mService); 195654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mService = null; 196654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc }catch (Throwable t) { 197654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc Log.w(TAG, "Error cleaning up HID proxy", t); 198654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 199654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 200654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 201436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby} 202