• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 /*
18  * Defines the native inteface that is used by HID Device service to
19  * send or receive messages from the native stack. This file is registered
20  * for the native methods in the corresponding JNI C++ file.
21  */
22 
23 package com.android.bluetooth.hid;
24 
25 import android.bluetooth.BluetoothAdapter;
26 import android.bluetooth.BluetoothDevice;
27 import android.util.Log;
28 
29 import com.android.bluetooth.btservice.AdapterService;
30 import com.android.internal.annotations.GuardedBy;
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.util.Objects;
34 
35 /**
36  * HID Device Native Interface to/from JNI.
37  */
38 public class HidDeviceNativeInterface {
39     private static final String TAG = "HidDeviceNativeInterface";
40     private BluetoothAdapter mAdapter;
41     private AdapterService mAdapterService;
42 
43     @GuardedBy("INSTANCE_LOCK")
44     private static HidDeviceNativeInterface sInstance;
45     private static final Object INSTANCE_LOCK = new Object();
46 
47     static {
classInitNative()48         classInitNative();
49     }
50 
51     @VisibleForTesting
HidDeviceNativeInterface()52     private HidDeviceNativeInterface() {
53         mAdapter = BluetoothAdapter.getDefaultAdapter();
54         if (mAdapter == null) {
55             Log.wtf(TAG, "No Bluetooth Adapter Available");
56         }
57         mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
58                 "AdapterService cannot be null when HidDeviceNativeInterface init");
59     }
60 
61     /**
62      * Get the singleton instance.
63      */
getInstance()64     public static HidDeviceNativeInterface getInstance() {
65         synchronized (INSTANCE_LOCK) {
66             if (sInstance == null) {
67                 setInstance(new HidDeviceNativeInterface());
68             }
69             return sInstance;
70         }
71     }
72 
73     /**
74      * Set the singleton instance.
75      *
76      * @param nativeInterface native interface
77      */
setInstance(HidDeviceNativeInterface nativeInterface)78     private static void setInstance(HidDeviceNativeInterface nativeInterface) {
79         sInstance = nativeInterface;
80     }
81 
82     /**
83      * Initializes the native interface.
84      */
init()85     public void init() {
86         initNative();
87     }
88 
89     /**
90      * Cleanup the native interface.
91      */
cleanup()92     public void cleanup() {
93         cleanupNative();
94     }
95 
96     /**
97      * Registers the application
98      *
99      * @param name name of the HID Device application
100      * @param description description of the HID Device application
101      * @param provider provider of the HID Device application
102      * @param subclass subclass of the HID Device application
103      * @param descriptors HID descriptors
104      * @param inQos incoming QoS settings
105      * @param outQos outgoing QoS settings
106      * @return the result of the native call
107      */
registerApp(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos)108     public boolean registerApp(String name, String description, String provider,
109             byte subclass, byte[] descriptors, int[] inQos, int[] outQos) {
110         return registerAppNative(name, description, provider, subclass, descriptors, inQos, outQos);
111     }
112 
113     /**
114      * Unregisters the application
115      *
116      * @return the result of the native call
117      */
unregisterApp()118     public boolean unregisterApp() {
119         return unregisterAppNative();
120     }
121 
122     /**
123      * Send report to the remote host
124      *
125      * @param id report ID
126      * @param data report data array
127      * @return the result of the native call
128      */
sendReport(int id, byte[] data)129     public boolean sendReport(int id, byte[] data) {
130         return sendReportNative(id, data);
131     }
132 
133     /**
134      * Reply report to the remote host
135      *
136      * @param type report type
137      * @param id report ID
138      * @param data report data array
139      * @return the result of the native call
140      */
replyReport(byte type, byte id, byte[] data)141     public boolean replyReport(byte type, byte id, byte[] data) {
142         return replyReportNative(type, id, data);
143     }
144 
145     /**
146      * Send virtual unplug to the remote host
147      *
148      * @return the result of the native call
149      */
unplug()150     public boolean unplug() {
151         return unplugNative();
152     }
153 
154     /**
155      * Connect to the remote host
156      *
157      * @param device remote host device
158      * @return the result of the native call
159      */
connect(BluetoothDevice device)160     public boolean connect(BluetoothDevice device) {
161         return connectNative(getByteAddress(device));
162     }
163 
164     /**
165      * Disconnect from the remote host
166      *
167      * @return the result of the native call
168      */
disconnect()169     public boolean disconnect() {
170         return disconnectNative();
171     }
172 
173     /**
174      * Report error to the remote host
175      *
176      * @param error error byte
177      * @return the result of the native call
178      */
reportError(byte error)179     public boolean reportError(byte error) {
180         return reportErrorNative(error);
181     }
182 
183     @VisibleForTesting
onApplicationStateChanged(byte[] address, boolean registered)184     synchronized void onApplicationStateChanged(byte[] address, boolean registered) {
185         HidDeviceService service = HidDeviceService.getHidDeviceService();
186         if (service != null) {
187             service.onApplicationStateChangedFromNative(getDevice(address), registered);
188         } else {
189             Log.wtf(TAG, "FATAL: onApplicationStateChanged() "
190                     + "is called from the stack while service is not available.");
191         }
192     }
193 
194     @VisibleForTesting
onConnectStateChanged(byte[] address, int state)195     synchronized void onConnectStateChanged(byte[] address, int state) {
196         HidDeviceService service = HidDeviceService.getHidDeviceService();
197         if (service != null) {
198             service.onConnectStateChangedFromNative(getDevice(address), state);
199         } else {
200             Log.wtf(TAG, "FATAL: onConnectStateChanged() "
201                     + "is called from the stack while service is not available.");
202         }
203     }
204 
205     @VisibleForTesting
onGetReport(byte type, byte id, short bufferSize)206     synchronized void onGetReport(byte type, byte id, short bufferSize) {
207         HidDeviceService service = HidDeviceService.getHidDeviceService();
208         if (service != null) {
209             service.onGetReportFromNative(type, id, bufferSize);
210         } else {
211             Log.wtf(TAG, "FATAL: onGetReport() "
212                     + "is called from the stack while service is not available.");
213         }
214     }
215 
216     @VisibleForTesting
onSetReport(byte reportType, byte reportId, byte[] data)217     synchronized void onSetReport(byte reportType, byte reportId, byte[] data) {
218         HidDeviceService service = HidDeviceService.getHidDeviceService();
219         if (service != null) {
220             service.onSetReportFromNative(reportType, reportId, data);
221         } else {
222             Log.wtf(TAG, "FATAL: onSetReport() "
223                     + "is called from the stack while service is not available.");
224         }
225     }
226 
227     @VisibleForTesting
onSetProtocol(byte protocol)228     synchronized void onSetProtocol(byte protocol) {
229         HidDeviceService service = HidDeviceService.getHidDeviceService();
230         if (service != null) {
231             service.onSetProtocolFromNative(protocol);
232         } else {
233             Log.wtf(TAG, "FATAL: onSetProtocol() "
234                     + "is called from the stack while service is not available.");
235         }
236     }
237 
238     @VisibleForTesting
onInterruptData(byte reportId, byte[] data)239     synchronized void onInterruptData(byte reportId, byte[] data) {
240         HidDeviceService service = HidDeviceService.getHidDeviceService();
241         if (service != null) {
242             service.onInterruptDataFromNative(reportId, data);
243         } else {
244             Log.wtf(TAG, "FATAL: onInterruptData() "
245                     + "is called from the stack while service is not available.");
246         }
247     }
248 
249     @VisibleForTesting
onVirtualCableUnplug()250     synchronized void onVirtualCableUnplug() {
251         HidDeviceService service = HidDeviceService.getHidDeviceService();
252         if (service != null) {
253             service.onVirtualCableUnplugFromNative();
254         } else {
255             Log.wtf(TAG, "FATAL: onVirtualCableUnplug() "
256                     + "is called from the stack while service is not available.");
257         }
258     }
259 
getDevice(byte[] address)260     private BluetoothDevice getDevice(byte[] address) {
261         if (address == null) {
262             return null;
263         }
264         return mAdapterService.getDeviceFromByte(address);
265     }
266 
getByteAddress(BluetoothDevice device)267     private byte[] getByteAddress(BluetoothDevice device) {
268         return mAdapterService.getByteIdentityAddress(device);
269     }
270 
classInitNative()271     private static native void classInitNative();
272 
initNative()273     private native void initNative();
274 
cleanupNative()275     private native void cleanupNative();
276 
registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos)277     private native boolean registerAppNative(String name, String description, String provider,
278             byte subclass, byte[] descriptors, int[] inQos, int[] outQos);
279 
unregisterAppNative()280     private native boolean unregisterAppNative();
281 
sendReportNative(int id, byte[] data)282     private native boolean sendReportNative(int id, byte[] data);
283 
replyReportNative(byte type, byte id, byte[] data)284     private native boolean replyReportNative(byte type, byte id, byte[] data);
285 
unplugNative()286     private native boolean unplugNative();
287 
connectNative(byte[] btAddress)288     private native boolean connectNative(byte[] btAddress);
289 
disconnectNative()290     private native boolean disconnectNative();
291 
reportErrorNative(byte error)292     private native boolean reportErrorNative(byte error);
293 }
294