1 /*
2  * Copyright 2023 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.bluetooth.btservice;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothClass;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothQualityReport;
23 import android.bluetooth.BluetoothStatusCodes;
24 import android.util.Log;
25 
26 import com.android.bluetooth.Utils;
27 import com.android.internal.annotations.GuardedBy;
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 /** Native interface to BQR */
31 public class BluetoothQualityReportNativeInterface {
32     private static final String TAG = "BluetoothQualityReportNativeInterface";
33 
34     @GuardedBy("INSTANCE_LOCK")
35     private static BluetoothQualityReportNativeInterface sInstance;
36 
37     private static final Object INSTANCE_LOCK = new Object();
38 
BluetoothQualityReportNativeInterface()39     private BluetoothQualityReportNativeInterface() {}
40 
41     /** Get singleton instance. */
getInstance()42     public static BluetoothQualityReportNativeInterface getInstance() {
43         synchronized (INSTANCE_LOCK) {
44             if (sInstance == null) {
45                 sInstance = new BluetoothQualityReportNativeInterface();
46             }
47             return sInstance;
48         }
49     }
50 
51     /** Set singleton instance. */
52     @VisibleForTesting
setInstance(BluetoothQualityReportNativeInterface instance)53     static void setInstance(BluetoothQualityReportNativeInterface instance) {
54         synchronized (INSTANCE_LOCK) {
55             sInstance = instance;
56         }
57     }
58 
59     /**
60      * Initializes the native interface.
61      *
62      * <p>priorities to configure.
63      */
init()64     public void init() {
65         initNative();
66     }
67 
68     /** Cleanup the native interface. */
cleanup()69     public void cleanup() {
70         cleanupNative();
71     }
72 
73     /** Callback from the native stack back into the Java framework. */
bqrDeliver( byte[] remoteAddr, int lmpVer, int lmpSubVer, int manufacturerId, byte[] bqrRawData)74     private void bqrDeliver(
75             byte[] remoteAddr, int lmpVer, int lmpSubVer, int manufacturerId, byte[] bqrRawData) {
76         BluetoothClass remoteBtClass = null;
77         BluetoothDevice device = null;
78         String remoteName = null;
79 
80         String remoteAddress = Utils.getAddressStringFromByte(remoteAddr);
81         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
82 
83         if (remoteAddress != null && adapter != null) {
84             device = adapter.getRemoteDevice(remoteAddress);
85             if (device == null) {
86                 Log.e(TAG, "bqrDeliver failed: device is null");
87                 return;
88             }
89             remoteName = device.getName();
90             remoteBtClass = device.getBluetoothClass();
91         } else {
92             Log.e(
93                     TAG,
94                     "bqrDeliver failed: "
95                             + (remoteAddress == null
96                                     ? "remoteAddress is null"
97                                     : "adapter is null"));
98             return;
99         }
100 
101         BluetoothQualityReport bqr;
102         try {
103             bqr =
104                     new BluetoothQualityReport.Builder(bqrRawData)
105                             .setRemoteAddress(remoteAddress)
106                             .setLmpVersion(lmpVer)
107                             .setLmpSubVersion(lmpSubVer)
108                             .setManufacturerId(manufacturerId)
109                             .setRemoteName(remoteName)
110                             .setBluetoothClass(remoteBtClass)
111                             .build();
112             Log.i(TAG, bqr.toString());
113         } catch (Exception e) {
114             Log.e(TAG, "bqrDeliver failed: failed to create BluetotQualityReport", e);
115             return;
116         }
117 
118         try {
119             AdapterService adapterService = AdapterService.getAdapterService();
120             if (adapterService == null) {
121                 Log.e(TAG, "bqrDeliver failed: adapterService is null");
122                 return;
123             }
124             int status = adapterService.bluetoothQualityReportReadyCallback(device, bqr);
125             if (status != BluetoothStatusCodes.SUCCESS) {
126                 Log.e(TAG, "bluetoothQualityReportReadyCallback failed, status: " + status);
127             }
128         } catch (Exception e) {
129             Log.e(TAG, "bqrDeliver failed: bluetoothQualityReportReadyCallback error", e);
130             return;
131         }
132     }
133 
134     // Native methods that call into the JNI interface
initNative()135     private native void initNative();
136 
cleanupNative()137     private native void cleanupNative();
138 }
139