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