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