BluetoothInputProfileHandler.java revision 47898dd398ce7758983c7eca8a204cf9a170342a
1/* 2 * Copyright (C) 2011 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 android.server; 18 19import android.bluetooth.BluetoothAdapter; 20import android.bluetooth.BluetoothDevice; 21import android.bluetooth.BluetoothDeviceProfileState; 22import android.bluetooth.BluetoothInputDevice; 23import android.bluetooth.BluetoothProfileState; 24import android.content.Context; 25import android.content.Intent; 26import android.os.Message; 27import android.provider.Settings; 28import android.util.Log; 29 30import java.util.ArrayList; 31import java.util.HashMap; 32import java.util.List; 33 34/** 35 * This handles all the operations on the HID profile. 36 * All functions are called by BluetoothService, as Bluetooth Service 37 * is the Service handler for the HID profile. 38 */ 39final class BluetoothInputProfileHandler { 40 private static final String TAG = "BluetoothInputProfileHandler"; 41 private static final boolean DBG = true; 42 43 public static BluetoothInputProfileHandler sInstance; 44 private Context mContext; 45 private BluetoothService mBluetoothService; 46 private final HashMap<BluetoothDevice, Integer> mInputDevices; 47 private final BluetoothProfileState mHidProfileState; 48 49 private BluetoothInputProfileHandler(Context context, BluetoothService service) { 50 mContext = context; 51 mBluetoothService = service; 52 mInputDevices = new HashMap<BluetoothDevice, Integer>(); 53 mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID); 54 mHidProfileState.start(); 55 } 56 57 static synchronized BluetoothInputProfileHandler getInstance(Context context, 58 BluetoothService service) { 59 if (sInstance == null) sInstance = new BluetoothInputProfileHandler(context, service); 60 return sInstance; 61 } 62 63 synchronized boolean connectInputDevice(BluetoothDevice device, 64 BluetoothDeviceProfileState state) { 65 String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 66 if (objectPath == null || 67 getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED || 68 getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) { 69 return false; 70 } 71 if (state != null) { 72 Message msg = new Message(); 73 msg.arg1 = BluetoothDeviceProfileState.CONNECT_HID_OUTGOING; 74 msg.obj = state; 75 mHidProfileState.sendMessage(msg); 76 return true; 77 } 78 return false; 79 } 80 81 synchronized boolean connectInputDeviceInternal(BluetoothDevice device) { 82 String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 83 handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING); 84 if (!mBluetoothService.connectInputDeviceNative(objectPath)) { 85 handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTED); 86 return false; 87 } 88 return true; 89 } 90 91 synchronized boolean disconnectInputDevice(BluetoothDevice device, 92 BluetoothDeviceProfileState state) { 93 String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 94 if (objectPath == null || 95 getInputDeviceState(device) == BluetoothInputDevice.STATE_DISCONNECTED) { 96 return false; 97 } 98 if (state != null) { 99 Message msg = new Message(); 100 msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HID_OUTGOING; 101 msg.obj = state; 102 mHidProfileState.sendMessage(msg); 103 return true; 104 } 105 return false; 106 } 107 108 synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) { 109 String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 110 handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING); 111 if (!mBluetoothService.disconnectInputDeviceNative(objectPath)) { 112 handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTED); 113 return false; 114 } 115 return true; 116 } 117 118 synchronized int getInputDeviceState(BluetoothDevice device) { 119 if (mInputDevices.get(device) == null) { 120 return BluetoothInputDevice.STATE_DISCONNECTED; 121 } 122 return mInputDevices.get(device); 123 } 124 125 synchronized List<BluetoothDevice> getConnectedInputDevices() { 126 List<BluetoothDevice> devices = lookupInputDevicesMatchingStates( 127 new int[] {BluetoothInputDevice.STATE_CONNECTED}); 128 return devices; 129 } 130 131 synchronized int getInputDevicePriority(BluetoothDevice device) { 132 return Settings.Secure.getInt(mContext.getContentResolver(), 133 Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 134 BluetoothInputDevice.PRIORITY_UNDEFINED); 135 } 136 137 synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) { 138 if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { 139 return false; 140 } 141 return Settings.Secure.putInt(mContext.getContentResolver(), 142 Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 143 priority); 144 } 145 146 synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) { 147 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 148 149 for (BluetoothDevice device: mInputDevices.keySet()) { 150 int inputDeviceState = getInputDeviceState(device); 151 for (int state : states) { 152 if (state == inputDeviceState) { 153 inputDevices.add(device); 154 break; 155 } 156 } 157 } 158 return inputDevices; 159 } 160 161 private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) { 162 int prevState; 163 if (mInputDevices.get(device) == null) { 164 prevState = BluetoothInputDevice.STATE_DISCONNECTED; 165 } else { 166 prevState = mInputDevices.get(device); 167 } 168 if (prevState == state) return; 169 170 mInputDevices.put(device, state); 171 172 if (getInputDevicePriority(device) > 173 BluetoothInputDevice.PRIORITY_OFF && 174 state == BluetoothInputDevice.STATE_CONNECTING || 175 state == BluetoothInputDevice.STATE_CONNECTED) { 176 // We have connected or attempting to connect. 177 // Bump priority 178 setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT); 179 } 180 181 Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED); 182 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 183 intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState); 184 intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state); 185 mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); 186 187 debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state); 188 mBluetoothService.sendConnectionStateChange(device, state, prevState); 189 } 190 191 synchronized void handleInputDevicePropertyChange(String address, boolean connected) { 192 int state = connected ? BluetoothInputDevice.STATE_CONNECTED : 193 BluetoothInputDevice.STATE_DISCONNECTED; 194 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 195 BluetoothDevice device = adapter.getRemoteDevice(address); 196 handleInputDeviceStateChange(device, state); 197 } 198 199 synchronized void setInitialInputDevicePriority(BluetoothDevice device, int state) { 200 switch (state) { 201 case BluetoothDevice.BOND_BONDED: 202 if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) { 203 setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON); 204 } 205 break; 206 case BluetoothDevice.BOND_NONE: 207 setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_UNDEFINED); 208 break; 209 } 210 } 211 212 private static void debugLog(String msg) { 213 if (DBG) Log.d(TAG, msg); 214 } 215 216 private static void errorLog(String msg) { 217 Log.e(TAG, msg); 218 } 219} 220