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 static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
21 
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothClass;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothHidHost;
26 import android.bluetooth.BluetoothProfile;
27 import android.content.Context;
28 import android.util.Log;
29 
30 import com.android.settingslib.R;
31 
32 import java.util.List;
33 
34 /**
35  * HidProfile handles Bluetooth HID Host role.
36  */
37 public class HidProfile implements LocalBluetoothProfile {
38     private static final String TAG = "HidProfile";
39 
40     private BluetoothHidHost mService;
41     private boolean mIsProfileReady;
42 
43     private final CachedBluetoothDeviceManager mDeviceManager;
44     private final LocalBluetoothProfileManager mProfileManager;
45 
46     static final String NAME = "HID";
47 
48     // Order of this profile in device profiles list
49     private static final int ORDINAL = 3;
50 
51     // These callbacks run on the main thread.
52     private final class HidHostServiceListener
53             implements BluetoothProfile.ServiceListener {
54 
onServiceConnected(int profile, BluetoothProfile proxy)55         public void onServiceConnected(int profile, BluetoothProfile proxy) {
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(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             mIsProfileReady=false;
75         }
76     }
77 
isProfileReady()78     public boolean isProfileReady() {
79         return mIsProfileReady;
80     }
81 
82     @Override
getProfileId()83     public int getProfileId() {
84         return BluetoothProfile.HID_HOST;
85     }
86 
HidProfile(Context context, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)87     HidProfile(Context context,
88         CachedBluetoothDeviceManager deviceManager,
89         LocalBluetoothProfileManager profileManager) {
90         mDeviceManager = deviceManager;
91         mProfileManager = profileManager;
92         BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HidHostServiceListener(),
93                 BluetoothProfile.HID_HOST);
94     }
95 
accessProfileEnabled()96     public boolean accessProfileEnabled() {
97         return true;
98     }
99 
isAutoConnectable()100     public boolean isAutoConnectable() {
101         return true;
102     }
103 
getConnectionStatus(BluetoothDevice device)104     public int getConnectionStatus(BluetoothDevice device) {
105         if (mService == null) {
106             return BluetoothProfile.STATE_DISCONNECTED;
107         }
108         return mService.getConnectionState(device);
109     }
110 
111     @Override
isEnabled(BluetoothDevice device)112     public boolean isEnabled(BluetoothDevice device) {
113         if (mService == null) {
114             return false;
115         }
116         return mService.getConnectionPolicy(device) != CONNECTION_POLICY_FORBIDDEN;
117     }
118 
119     @Override
getConnectionPolicy(BluetoothDevice device)120     public int getConnectionPolicy(BluetoothDevice device) {
121         if (mService == null) {
122             return CONNECTION_POLICY_FORBIDDEN;
123         }
124         return mService.getConnectionPolicy(device);
125     }
126 
127     @Override
setEnabled(BluetoothDevice device, boolean enabled)128     public boolean setEnabled(BluetoothDevice device, boolean enabled) {
129         boolean isEnabled = false;
130         if (mService == null) {
131             return false;
132         }
133         if (enabled) {
134             if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
135                 isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
136             }
137         } else {
138             isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
139         }
140 
141         return isEnabled;
142     }
143 
toString()144     public String toString() {
145         return NAME;
146     }
147 
getOrdinal()148     public int getOrdinal() {
149         return ORDINAL;
150     }
151 
getNameResource(BluetoothDevice device)152     public int getNameResource(BluetoothDevice device) {
153         // TODO: distinguish between keyboard and mouse?
154         return R.string.bluetooth_profile_hid;
155     }
156 
getSummaryResourceForDevice(BluetoothDevice device)157     public int getSummaryResourceForDevice(BluetoothDevice device) {
158         int state = getConnectionStatus(device);
159         switch (state) {
160             case BluetoothProfile.STATE_DISCONNECTED:
161                 return R.string.bluetooth_hid_profile_summary_use_for;
162 
163             case BluetoothProfile.STATE_CONNECTED:
164                 return R.string.bluetooth_hid_profile_summary_connected;
165 
166             default:
167                 return BluetoothUtils.getConnectionStateSummary(state);
168         }
169     }
170 
getDrawableResource(BluetoothClass btClass)171     public int getDrawableResource(BluetoothClass btClass) {
172         if (btClass == null) {
173             return com.android.internal.R.drawable.ic_lockscreen_ime;
174         }
175         return getHidClassDrawable(btClass);
176     }
177 
getHidClassDrawable(BluetoothClass btClass)178     public static int getHidClassDrawable(BluetoothClass btClass) {
179         switch (btClass.getDeviceClass()) {
180             case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
181             case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
182                 return com.android.internal.R.drawable.ic_lockscreen_ime;
183             case BluetoothClass.Device.PERIPHERAL_POINTING:
184                 return com.android.internal.R.drawable.ic_bt_pointing_hid;
185             default:
186                 return com.android.internal.R.drawable.ic_bt_misc_hid;
187         }
188     }
189 
finalize()190     protected void finalize() {
191         Log.d(TAG, "finalize()");
192         if (mService != null) {
193             try {
194                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_HOST,
195                                                                        mService);
196                 mService = null;
197             }catch (Throwable t) {
198                 Log.w(TAG, "Error cleaning up HID proxy", t);
199             }
200         }
201     }
202 }
203