• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.bluetooth.csip;
19 
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothDevice;
22 import android.util.Log;
23 
24 import com.android.bluetooth.Utils;
25 import com.android.internal.annotations.GuardedBy;
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.util.UUID;
29 
30 /**
31  * CSIP Set Coordinator role native interface
32  */
33 public class CsipSetCoordinatorNativeInterface {
34     private static final String TAG = "CsipSetCoordinatorNativeInterface";
35     private static final boolean DBG = false;
36     private BluetoothAdapter mAdapter;
37 
38     @GuardedBy("INSTANCE_LOCK") private static CsipSetCoordinatorNativeInterface sInstance;
39     private static final Object INSTANCE_LOCK = new Object();
40 
41     static {
classInitNative()42         classInitNative();
43     }
44 
CsipSetCoordinatorNativeInterface()45     private CsipSetCoordinatorNativeInterface() {
46         mAdapter = BluetoothAdapter.getDefaultAdapter();
47         if (mAdapter == null) {
48             Log.wtf(TAG, "No Bluetooth Adapter Available");
49         }
50     }
51 
52     /**
53      * Get singleton instance.
54      */
getInstance()55     public static CsipSetCoordinatorNativeInterface getInstance() {
56         synchronized (INSTANCE_LOCK) {
57             if (sInstance == null) {
58                 sInstance = new CsipSetCoordinatorNativeInterface();
59             }
60             return sInstance;
61         }
62     }
63 
64     /**
65      * Initializes the native interface.
66      *
67      * priorities to configure.
68      */
69     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
init()70     public void init() {
71         initNative();
72     }
73 
74     /**
75      * Cleanup the native interface.
76      */
77     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
cleanup()78     public void cleanup() {
79         cleanupNative();
80     }
81 
82     /**
83      * Initiates CsipSetCoordinator connection to a remote device.
84      *
85      * @param device the remote device
86      * @return true on success, otherwise false.
87      */
88     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
connect(BluetoothDevice device)89     public boolean connect(BluetoothDevice device) {
90         return connectNative(getByteAddress(device));
91     }
92 
93     /**
94      * Disconnects CsipSetCoordinator from a remote device.
95      *
96      * @param device the remote device
97      * @return true on success, otherwise false.
98      */
99     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
disconnect(BluetoothDevice device)100     public boolean disconnect(BluetoothDevice device) {
101         return disconnectNative(getByteAddress(device));
102     }
103 
104     /**
105      * Get the device by the address
106      *
107      * @return the device
108      */
109     @VisibleForTesting
getDevice(byte[] address)110     public BluetoothDevice getDevice(byte[] address) {
111         return mAdapter.getRemoteDevice(address);
112     }
113 
getByteAddress(BluetoothDevice device)114     private byte[] getByteAddress(BluetoothDevice device) {
115         if (device == null) {
116             return Utils.getBytesFromAddress("00:00:00:00:00:00");
117         }
118         return Utils.getBytesFromAddress(device.getAddress());
119     }
120 
sendMessageToService(CsipSetCoordinatorStackEvent event)121     private void sendMessageToService(CsipSetCoordinatorStackEvent event) {
122         CsipSetCoordinatorService service =
123                 CsipSetCoordinatorService.getCsipSetCoordinatorService();
124         if (service != null) {
125             service.messageFromNative(event);
126         } else {
127             Log.e(TAG, "Event ignored, service not available: " + event);
128         }
129     }
130 
131     // Callbacks from the native stack back into the Java framework.
132     // All callbacks are routed via the Service which will disambiguate which
133     // state machine the message should be routed to.
134 
135     /** Device connection state change */
136     @VisibleForTesting
onConnectionStateChanged(byte[] address, int state)137     public void onConnectionStateChanged(byte[] address, int state) {
138         CsipSetCoordinatorStackEvent event = new CsipSetCoordinatorStackEvent(
139                 CsipSetCoordinatorStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
140         event.device = getDevice(address);
141         event.valueInt1 = state;
142 
143         if (DBG) {
144             Log.d(TAG, "onConnectionStateChanged: " + event);
145         }
146         sendMessageToService(event);
147     }
148 
149     /** Device availability */
150     @VisibleForTesting
onDeviceAvailable( byte[] address, int groupId, int groupSize, int rank, long uuidLsb, long uuidMsb)151     public void onDeviceAvailable(
152             byte[] address, int groupId, int groupSize, int rank, long uuidLsb, long uuidMsb) {
153         UUID uuid = new UUID(uuidMsb, uuidLsb);
154         CsipSetCoordinatorStackEvent event = new CsipSetCoordinatorStackEvent(
155                 CsipSetCoordinatorStackEvent.EVENT_TYPE_DEVICE_AVAILABLE);
156         event.device = getDevice(address);
157         event.valueInt1 = groupId;
158         event.valueInt2 = groupSize;
159         event.valueInt3 = rank;
160         event.valueUuid1 = uuid;
161 
162         if (DBG) {
163             Log.d(TAG, "onDeviceAvailable: " + event);
164         }
165         sendMessageToService(event);
166     }
167 
168     // Callbacks from the native stack back into the Java framework.
169     // All callbacks are routed via the Service which will disambiguate which
170     // state machine the message should be routed to.
171 
172     /**
173      * Set member available callback
174      */
175     @VisibleForTesting
onSetMemberAvailable(byte[] address, int groupId)176     public void onSetMemberAvailable(byte[] address, int groupId) {
177         CsipSetCoordinatorStackEvent event = new CsipSetCoordinatorStackEvent(
178                 CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE);
179         event.device = getDevice(address);
180         event.valueInt1 = groupId;
181         if (DBG) {
182             Log.d(TAG, "onSetMemberAvailable: " + event);
183         }
184         sendMessageToService(event);
185     }
186 
187     /**
188      * Group lock changed callback as a result of lock or unlock request or
189      * autonomous event.
190      *
191      * @param groupId group identifier
192      * @param locked whether group is locked or unlocked
193      * @param status status of a requested lock/unlock
194      */
195     @VisibleForTesting
onGroupLockChanged(int groupId, boolean locked, int status)196     public void onGroupLockChanged(int groupId, boolean locked, int status) {
197         CsipSetCoordinatorStackEvent event = new CsipSetCoordinatorStackEvent(
198                 CsipSetCoordinatorStackEvent.EVENT_TYPE_GROUP_LOCK_CHANGED);
199         event.valueInt1 = groupId;
200         event.valueInt2 = status;
201         event.valueBool1 = locked;
202         if (DBG) {
203             Log.d(TAG, "onGroupLockChanged: " + event);
204         }
205         sendMessageToService(event);
206     }
207 
208     /**
209      * Set lock on the group.
210      * @param groupId  group identifier
211      * @param lock  True for lock, false for unlock
212      */
213     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
groupLockSet(int groupId, boolean lock)214     public void groupLockSet(int groupId, boolean lock) {
215         groupLockSetNative(groupId, lock);
216     }
217 
218     // Native methods that call into the JNI interface
classInitNative()219     private static native void classInitNative();
initNative()220     private native void initNative();
cleanupNative()221     private native void cleanupNative();
connectNative(byte[] address)222     private native boolean connectNative(byte[] address);
disconnectNative(byte[] address)223     private native boolean disconnectNative(byte[] address);
groupLockSetNative(int groupId, boolean lock)224     private native void groupLockSetNative(int groupId, boolean lock);
225 }
226