1 /*
2  * Copyright (C) 2012 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 com.android.settingslib.bluetooth;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothClass;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothHidHost;
23 import android.bluetooth.BluetoothProfile;
24 import android.content.Context;
25 import android.util.Log;
26 
27 import com.android.settingslib.R;
28 
29 import java.util.List;
30 
31 /**
32  * HidProfile handles Bluetooth HID profile.
33  */
34 public class HidProfile implements LocalBluetoothProfile {
35     private static final String TAG = "HidProfile";
36     private static boolean V = true;
37 
38     private BluetoothHidHost mService;
39     private boolean mIsProfileReady;
40 
41     private final LocalBluetoothAdapter mLocalAdapter;
42     private final CachedBluetoothDeviceManager mDeviceManager;
43     private final LocalBluetoothProfileManager mProfileManager;
44 
45     static final String NAME = "HID";
46 
47     // Order of this profile in device profiles list
48     private static final int ORDINAL = 3;
49 
50     // These callbacks run on the main thread.
51     private final class HidHostServiceListener
52             implements BluetoothProfile.ServiceListener {
53 
onServiceConnected(int profile, BluetoothProfile proxy)54         public void onServiceConnected(int profile, BluetoothProfile proxy) {
55             if (V) Log.d(TAG,"Bluetooth service connected");
56             mService = (BluetoothHidHost) proxy;
57             // We just bound to the service, so refresh the UI for any connected HID devices.
58             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
59             while (!deviceList.isEmpty()) {
60                 BluetoothDevice nextDevice = deviceList.remove(0);
61                 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
62                 // we may add a new device here, but generally this should not happen
63                 if (device == null) {
64                     Log.w(TAG, "HidProfile found new device: " + nextDevice);
65                     device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
66                 }
67                 device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED);
68                 device.refresh();
69             }
70             mIsProfileReady=true;
71         }
72 
onServiceDisconnected(int profile)73         public void onServiceDisconnected(int profile) {
74             if (V) Log.d(TAG,"Bluetooth service disconnected");
75             mIsProfileReady=false;
76         }
77     }
78 
isProfileReady()79     public boolean isProfileReady() {
80         return mIsProfileReady;
81     }
82 
83     @Override
getProfileId()84     public int getProfileId() {
85         return BluetoothProfile.HID_HOST;
86     }
87 
HidProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)88     HidProfile(Context context, LocalBluetoothAdapter adapter,
89         CachedBluetoothDeviceManager deviceManager,
90         LocalBluetoothProfileManager profileManager) {
91         mLocalAdapter = adapter;
92         mDeviceManager = deviceManager;
93         mProfileManager = profileManager;
94         adapter.getProfileProxy(context, new HidHostServiceListener(),
95                 BluetoothProfile.HID_HOST);
96     }
97 
isConnectable()98     public boolean isConnectable() {
99         return true;
100     }
101 
isAutoConnectable()102     public boolean isAutoConnectable() {
103         return true;
104     }
105 
connect(BluetoothDevice device)106     public boolean connect(BluetoothDevice device) {
107         if (mService == null) return false;
108         return mService.connect(device);
109     }
110 
disconnect(BluetoothDevice device)111     public boolean disconnect(BluetoothDevice device) {
112         if (mService == null) return false;
113         return mService.disconnect(device);
114     }
115 
getConnectionStatus(BluetoothDevice device)116     public int getConnectionStatus(BluetoothDevice device) {
117         if (mService == null) {
118             return BluetoothProfile.STATE_DISCONNECTED;
119         }
120         List<BluetoothDevice> deviceList = mService.getConnectedDevices();
121 
122         return !deviceList.isEmpty() && deviceList.get(0).equals(device)
123                 ? mService.getConnectionState(device)
124                 : BluetoothProfile.STATE_DISCONNECTED;
125     }
126 
isPreferred(BluetoothDevice device)127     public boolean isPreferred(BluetoothDevice device) {
128         if (mService == null) return false;
129         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
130     }
131 
getPreferred(BluetoothDevice device)132     public int getPreferred(BluetoothDevice device) {
133         if (mService == null) return BluetoothProfile.PRIORITY_OFF;
134         return mService.getPriority(device);
135     }
136 
setPreferred(BluetoothDevice device, boolean preferred)137     public void setPreferred(BluetoothDevice device, boolean preferred) {
138         if (mService == null) return;
139         if (preferred) {
140             if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
141                 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
142             }
143         } else {
144             mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
145         }
146     }
147 
toString()148     public String toString() {
149         return NAME;
150     }
151 
getOrdinal()152     public int getOrdinal() {
153         return ORDINAL;
154     }
155 
getNameResource(BluetoothDevice device)156     public int getNameResource(BluetoothDevice device) {
157         // TODO: distinguish between keyboard and mouse?
158         return R.string.bluetooth_profile_hid;
159     }
160 
getSummaryResourceForDevice(BluetoothDevice device)161     public int getSummaryResourceForDevice(BluetoothDevice device) {
162         int state = getConnectionStatus(device);
163         switch (state) {
164             case BluetoothProfile.STATE_DISCONNECTED:
165                 return R.string.bluetooth_hid_profile_summary_use_for;
166 
167             case BluetoothProfile.STATE_CONNECTED:
168                 return R.string.bluetooth_hid_profile_summary_connected;
169 
170             default:
171                 return Utils.getConnectionStateSummary(state);
172         }
173     }
174 
getDrawableResource(BluetoothClass btClass)175     public int getDrawableResource(BluetoothClass btClass) {
176         if (btClass == null) {
177             return R.drawable.ic_lockscreen_ime;
178         }
179         return getHidClassDrawable(btClass);
180     }
181 
getHidClassDrawable(BluetoothClass btClass)182     public static int getHidClassDrawable(BluetoothClass btClass) {
183         switch (btClass.getDeviceClass()) {
184             case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
185             case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
186                 return R.drawable.ic_lockscreen_ime;
187             case BluetoothClass.Device.PERIPHERAL_POINTING:
188                 return R.drawable.ic_bt_pointing_hid;
189             default:
190                 return R.drawable.ic_bt_misc_hid;
191         }
192     }
193 
finalize()194     protected void finalize() {
195         if (V) Log.d(TAG, "finalize()");
196         if (mService != null) {
197             try {
198                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_HOST,
199                                                                        mService);
200                 mService = null;
201             }catch (Throwable t) {
202                 Log.w(TAG, "Error cleaning up HID proxy", t);
203             }
204         }
205     }
206 }
207