1 /* 2 * Copyright 2018 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 interface that is used by state machine/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 package com.android.bluetooth.hearingaid; 23 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothDevice; 26 import android.util.Log; 27 28 import com.android.bluetooth.Utils; 29 import com.android.internal.annotations.GuardedBy; 30 import com.android.internal.annotations.VisibleForTesting; 31 32 /** 33 * HearingAid Native Interface to/from JNI. 34 */ 35 public class HearingAidNativeInterface { 36 private static final String TAG = "HearingAidNativeInterface"; 37 private static final boolean DBG = true; 38 private BluetoothAdapter mAdapter; 39 40 @GuardedBy("INSTANCE_LOCK") 41 private static HearingAidNativeInterface sInstance; 42 private static final Object INSTANCE_LOCK = new Object(); 43 44 static { classInitNative()45 classInitNative(); 46 } 47 HearingAidNativeInterface()48 private HearingAidNativeInterface() { 49 mAdapter = BluetoothAdapter.getDefaultAdapter(); 50 if (mAdapter == null) { 51 Log.wtfStack(TAG, "No Bluetooth Adapter Available"); 52 } 53 } 54 55 /** 56 * Get singleton instance. 57 */ getInstance()58 public static HearingAidNativeInterface getInstance() { 59 synchronized (INSTANCE_LOCK) { 60 if (sInstance == null) { 61 sInstance = new HearingAidNativeInterface(); 62 } 63 return sInstance; 64 } 65 } 66 67 /** 68 * Initializes the native interface. 69 * 70 * priorities to configure. 71 */ 72 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) init()73 public void init() { 74 initNative(); 75 } 76 77 /** 78 * Cleanup the native interface. 79 */ 80 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) cleanup()81 public void cleanup() { 82 cleanupNative(); 83 } 84 85 /** 86 * Initiates HearingAid connection to a remote device. 87 * 88 * @param device the remote device 89 * @return true on success, otherwise false. 90 */ 91 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) connectHearingAid(BluetoothDevice device)92 public boolean connectHearingAid(BluetoothDevice device) { 93 return connectHearingAidNative(getByteAddress(device)); 94 } 95 96 /** 97 * Disconnects HearingAid from a remote device. 98 * 99 * @param device the remote device 100 * @return true on success, otherwise false. 101 */ 102 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) disconnectHearingAid(BluetoothDevice device)103 public boolean disconnectHearingAid(BluetoothDevice device) { 104 return disconnectHearingAidNative(getByteAddress(device)); 105 } 106 107 /** 108 * Add a hearing aid device to white list. 109 * 110 * @param device the remote device 111 * @return true on success, otherwise false. 112 */ 113 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) addToWhiteList(BluetoothDevice device)114 public boolean addToWhiteList(BluetoothDevice device) { 115 return addToWhiteListNative(getByteAddress(device)); 116 } 117 118 /** 119 * Sets the HearingAid volume 120 * @param volume 121 */ 122 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) setVolume(int volume)123 public void setVolume(int volume) { 124 setVolumeNative(volume); 125 } 126 getDevice(byte[] address)127 private BluetoothDevice getDevice(byte[] address) { 128 return mAdapter.getRemoteDevice(address); 129 } 130 getByteAddress(BluetoothDevice device)131 private byte[] getByteAddress(BluetoothDevice device) { 132 if (device == null) { 133 return Utils.getBytesFromAddress("00:00:00:00:00:00"); 134 } 135 return Utils.getBytesFromAddress(device.getAddress()); 136 } 137 sendMessageToService(HearingAidStackEvent event)138 private void sendMessageToService(HearingAidStackEvent event) { 139 HearingAidService service = HearingAidService.getHearingAidService(); 140 if (service != null) { 141 service.messageFromNative(event); 142 } else { 143 Log.e(TAG, "Event ignored, service not available: " + event); 144 } 145 } 146 147 // Callbacks from the native stack back into the Java framework. 148 // All callbacks are routed via the Service which will disambiguate which 149 // state machine the message should be routed to. 150 onConnectionStateChanged(int state, byte[] address)151 private void onConnectionStateChanged(int state, byte[] address) { 152 HearingAidStackEvent event = 153 new HearingAidStackEvent(HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 154 event.device = getDevice(address); 155 event.valueInt1 = state; 156 157 if (DBG) { 158 Log.d(TAG, "onConnectionStateChanged: " + event); 159 } 160 sendMessageToService(event); 161 } 162 onDeviceAvailable(byte capabilities, long hiSyncId, byte[] address)163 private void onDeviceAvailable(byte capabilities, long hiSyncId, byte[] address) { 164 HearingAidStackEvent event = new HearingAidStackEvent( 165 HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); 166 event.device = getDevice(address); 167 event.valueInt1 = capabilities; 168 event.valueLong2 = hiSyncId; 169 170 if (DBG) { 171 Log.d(TAG, "onDeviceAvailable: " + event); 172 } 173 sendMessageToService(event); 174 } 175 176 // Native methods that call into the JNI interface classInitNative()177 private static native void classInitNative(); initNative()178 private native void initNative(); cleanupNative()179 private native void cleanupNative(); connectHearingAidNative(byte[] address)180 private native boolean connectHearingAidNative(byte[] address); disconnectHearingAidNative(byte[] address)181 private native boolean disconnectHearingAidNative(byte[] address); addToWhiteListNative(byte[] address)182 private native boolean addToWhiteListNative(byte[] address); setVolumeNative(int volume)183 private native void setVolumeNative(int volume); 184 } 185