blob: e6513fd3469906b6d086f37d44f1ef503ac80cd8 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDeviceProfileState;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothProfileState;
import android.content.Context;
import android.content.Intent;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* This handles all the operations on the HID profile.
* All functions are called by BluetoothService, as Bluetooth Service
* is the Service handler for the HID profile.
*/
final class BluetoothInputProfileHandler {
private static final String TAG = "BluetoothInputProfileHandler";
private static final boolean DBG = true;
public static BluetoothInputProfileHandler sInstance;
private Context mContext;
private BluetoothService mBluetoothService;
private final HashMap<BluetoothDevice, Integer> mInputDevices;
private final BluetoothProfileState mHidProfileState;
private BluetoothInputProfileHandler(Context context, BluetoothService service) {
mContext = context;
mBluetoothService = service;
mInputDevices = new HashMap<BluetoothDevice, Integer>();
mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID);
mHidProfileState.start();
}
static synchronized BluetoothInputProfileHandler getInstance(Context context,
BluetoothService service) {
if (sInstance == null) sInstance = new BluetoothInputProfileHandler(context, service);
return sInstance;
}
synchronized boolean connectInputDevice(BluetoothDevice device,
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
getInputDeviceConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
return false;
}
if (state != null) {
Message msg = new Message();
msg.arg1 = BluetoothDeviceProfileState.CONNECT_HID_OUTGOING;
msg.obj = state;
mHidProfileState.sendMessage(msg);
return true;
}
return false;
}
synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING);
if (!mBluetoothService.connectInputDeviceNative(objectPath)) {
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTED);
return false;
}
return true;
}
synchronized boolean disconnectInputDevice(BluetoothDevice device,
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
getInputDeviceConnectionState(device) == BluetoothInputDevice.STATE_DISCONNECTED) {
return false;
}
if (state != null) {
Message msg = new Message();
msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HID_OUTGOING;
msg.obj = state;
mHidProfileState.sendMessage(msg);
return true;
}
return false;
}
synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING);
if (!mBluetoothService.disconnectInputDeviceNative(objectPath)) {
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTED);
return false;
}
return true;
}
synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
if (mInputDevices.get(device) == null) {
return BluetoothInputDevice.STATE_DISCONNECTED;
}
return mInputDevices.get(device);
}
synchronized List<BluetoothDevice> getConnectedInputDevices() {
List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(
new int[] {BluetoothInputDevice.STATE_CONNECTED});
return devices;
}
synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(int[] states) {
List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(states);
return devices;
}
synchronized int getInputDevicePriority(BluetoothDevice device) {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
BluetoothInputDevice.PRIORITY_UNDEFINED);
}
synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
return false;
}
return Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
priority);
}
synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mInputDevices.keySet()) {
int inputDeviceState = getInputDeviceConnectionState(device);
for (int state : states) {
if (state == inputDeviceState) {
inputDevices.add(device);
break;
}
}
}
return inputDevices;
}
private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) {
int prevState;
if (mInputDevices.get(device) == null) {
prevState = BluetoothInputDevice.STATE_DISCONNECTED;
} else {
prevState = mInputDevices.get(device);
}
if (prevState == state) return;
mInputDevices.put(device, state);
if (getInputDevicePriority(device) >
BluetoothInputDevice.PRIORITY_OFF &&
state == BluetoothInputDevice.STATE_CONNECTING ||
state == BluetoothInputDevice.STATE_CONNECTED) {
// We have connected or attempting to connect.
// Bump priority
setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT);
}
Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothInputDevice.EXTRA_STATE, state);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
mBluetoothService.sendConnectionStateChange(device, state, prevState);
}
synchronized void handleInputDevicePropertyChange(String address, boolean connected) {
int state = connected ? BluetoothInputDevice.STATE_CONNECTED :
BluetoothInputDevice.STATE_DISCONNECTED;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = adapter.getRemoteDevice(address);
handleInputDeviceStateChange(device, state);
}
synchronized void setInitialInputDevicePriority(BluetoothDevice device, int state) {
switch (state) {
case BluetoothDevice.BOND_BONDED:
if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) {
setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON);
}
break;
case BluetoothDevice.BOND_NONE:
setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_UNDEFINED);
break;
}
}
private static void debugLog(String msg) {
if (DBG) Log.d(TAG, msg);
}
private static void errorLog(String msg) {
Log.e(TAG, msg);
}
}