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