Add Android AITT APIs to align with native AITT APIs
[platform/core/ml/aitt.git] / android / aitt-native / src / main / java / com / samsung / android / aittnative / JniInterface.java
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
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 package com.samsung.android.aittnative;
17
18 import android.util.Log;
19 import android.util.Pair;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.Map;
24
25 /**
26  * Jni Interface class as intermediate layer for android aitt and other transport modules to interact with JNI module.
27  */
28 public class JniInterface {
29     private static final String TAG = "JniInterface";
30     private final Map<String, ArrayList<JniMessageCallback>> subscribeCallbacks = new HashMap<>();
31     private final Map<String, Pair<Integer, JniDiscoveryCallback>> discoveryCallbacks = new HashMap<>();
32     private JniConnectionCallback jniConnectionCallback;
33     private long instance = 0;
34
35     /*
36       Load aitt-native library
37      */
38     static {
39         try {
40             System.loadLibrary("aitt-native");
41         } catch (UnsatisfiedLinkError e) {
42             // only ignore exception in non-android env
43             if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e;
44         }
45     }
46
47     /**
48      * JNI callback interface to send data from JNI layer to Java layer(aitt or transport module)
49      */
50     public interface JniMessageCallback {
51         void onDataReceived(String topic, byte[] data);
52     }
53
54     /**
55      * JNI callback interface to send connection callback status to aitt layer
56      */
57     public interface JniConnectionCallback {
58         void onConnectionStatusReceived(int status);
59     }
60
61     /**
62      * JNI callback interface to receive discovery messages
63      */
64     public interface JniDiscoveryCallback {
65         void onDiscoveryMessageReceived(String status, byte[] data);
66     }
67
68     /**
69      * JNI interface API to initialize JNI module
70      * @param id unique mqtt id
71      * @param ip self IP address of device
72      * @param clearSession to clear current session if client disconnects
73      * @return returns the JNI instance object in long
74      */
75     public long init(String id, String ip, boolean clearSession) {
76         instance = initJNI(id, ip, clearSession);
77         return instance;
78     }
79
80     /**
81      * JNI Interface API to connect to MQTT broker
82      * @param brokerIp mqtt broker ip address
83      * @param port mqtt broker port number
84      */
85     public void connect(String brokerIp, int port) {
86         connectJNI(instance, brokerIp, port);
87     }
88
89     /**
90      * JNI Interface API to subscribe to a topic
91      * @param topic String to which applications can subscribe, to receive data
92      * @param protocol Protocol supported by application, invoking subscribe
93      * @param qos QoS at which the message should be delivered
94      * @return returns the subscribe instance in long
95      */
96     public long subscribe(final String topic, JniMessageCallback callback, int protocol, int qos) {
97         addCallBackToSubscribeMap(topic, callback);
98         return subscribeJNI(instance, topic, protocol, qos);
99     }
100
101     /**
102      * JNI Interface API to disconnect from broker
103      */
104     public void disconnect() {
105         synchronized (this) {
106             subscribeCallbacks.clear();
107             discoveryCallbacks.clear();
108             jniConnectionCallback = null;
109         }
110         disconnectJNI(instance);
111     }
112
113     /**
114      * JNI Interface API to publish data to specified topic
115      * @param topic String to which message needs to be published
116      * @param data Byte message to be published
117      * @param dataLen Size/length of the message to be published
118      * @param protocol Protocol to be used to publish message
119      * @param qos QoS at which the message should be delivered
120      * @param retain Boolean to decide whether or not the message should be retained by the broker
121      */
122     public void publish(final String topic, final byte[] data, long dataLen, int protocol, int qos, boolean retain) {
123         publishJNI(instance, topic, data, dataLen, protocol, qos, retain);
124     }
125
126     /**
127      * JNI Interface API to unsubscribe the given topic
128      * @param aittSubId Subscribe ID of the topics to be unsubscribed
129      */
130     public void unsubscribe(String topic, final long aittSubId) {
131         synchronized (this) {
132             subscribeCallbacks.remove(topic);
133         }
134         unsubscribeJNI(instance, aittSubId);
135     }
136
137     /**
138      * JNI Interface API to set connection callback instance
139      * @param cb callback instance of JniConnectionCallback interface
140      */
141     public void setConnectionCallback(JniConnectionCallback cb) {
142         jniConnectionCallback = cb;
143         setConnectionCallbackJNI(instance);
144     }
145
146     /**
147      * JNI Interface API to set discovery callback
148      * @param topic String for which discovery information is required
149      * @param callback callback instance of JniDiscoveryCallback interface
150      */
151     public void setDiscoveryCallback(String topic, JniDiscoveryCallback callback) {
152         int cb = setDiscoveryCallbackJNI(instance, topic);
153         synchronized (this) {
154             discoveryCallbacks.put(topic, new Pair<>(cb, callback));
155         }
156     }
157
158     /**
159      * JNI Interface API to remove discovery callback
160      * @param topic String for which discovery information is not required
161      */
162     public void removeDiscoveryCallback(String topic) {
163         synchronized (this) {
164             Pair<Integer, JniDiscoveryCallback> pair = discoveryCallbacks.get(topic);
165             if (pair != null) {
166                 removeDiscoveryCallbackJNI(instance, pair.first);
167             }
168             discoveryCallbacks.remove(topic);
169         }
170     }
171
172     /**
173      * JNI Interface API to update discovery message
174      * @param topic String for which discovery information is to be updated
175      * @param discoveryMessage ByteArray containing discovery information
176      */
177     public void updateDiscoveryMessage(String topic, byte[] discoveryMessage) {
178         updateDiscoveryMessageJNI(instance, topic, discoveryMessage, discoveryMessage.length);
179     }
180
181     /**
182      * messageCallback API to receive data from JNI layer to JNI interface layer
183      * @param topic Topic to which data is received
184      * @param payload Data that is sent from JNI to JNI interface layer
185      */
186     void messageCallback(String topic, byte[] payload) {
187         try {
188             synchronized (this) {
189                 ArrayList<JniMessageCallback> cbList = subscribeCallbacks.get(topic);
190
191                 if (cbList != null) {
192                     for (JniMessageCallback cb : cbList) {
193                         cb.onDataReceived(topic, payload);
194                     }
195                 }
196             }
197         } catch (Exception e) {
198             Log.e(TAG, "Error during messageReceived", e);
199         }
200     }
201
202     /**
203      * connectionStatusCallback API to receive connection status from JNI to JNI interface layer
204      * @param status status of the device connection with mqtt broker
205      */
206     void connectionStatusCallback(int status) {
207         if (jniConnectionCallback != null) {
208             jniConnectionCallback.onConnectionStatusReceived(status);
209         }
210     }
211
212     void discoveryMessageCallback(String topic, String status, byte[] message) {
213         synchronized (this) {
214             Pair<Integer, JniDiscoveryCallback> pair = discoveryCallbacks.get(topic);
215             if (pair != null) {
216                 pair.second.onDiscoveryMessageReceived(status, message);
217             }
218         }
219     }
220
221     /**
222      * Method to map JNI callback instance to topic
223      *
224      * @param topic    String to which application can subscribe
225      * @param callback JniInterface callback instance created during JNI subscribe call
226      */
227     private void addCallBackToSubscribeMap(String topic, JniMessageCallback callback) {
228         synchronized (this) {
229             try {
230                 ArrayList<JniMessageCallback> cbList = subscribeCallbacks.get(topic);
231
232                 if (cbList != null) {
233                     // check whether the list already contains same callback
234                     if (!cbList.contains(callback)) {
235                         cbList.add(callback);
236                     }
237                 } else {
238                     cbList = new ArrayList<>();
239                     cbList.add(callback);
240                     subscribeCallbacks.put(topic, cbList);
241                 }
242             } catch (Exception e) {
243                 Log.e(TAG, "Error during JNI callback add", e);
244             }
245         }
246     }
247
248     /* native API set */
249     /* Native API to initialize JNI */
250     private native long initJNI(String id, String ip, boolean clearSession);
251
252     /* Native API for connecting to broker */
253     private native void connectJNI(long instance, final String host, int port);
254
255     /* Native API for disconnecting from broker */
256     private native void disconnectJNI(long instance);
257
258     /* Native API for setting connection callback */
259     private native void setConnectionCallbackJNI(long instance);
260
261     /* Native API for setting discovery callback */
262     private native int setDiscoveryCallbackJNI(long instance, final String topic);
263
264     /* Native API for removing discovery callback */
265     private native void removeDiscoveryCallbackJNI(long instance, int cbHandle);
266
267     /* Native API for updating discovery message */
268     private native void updateDiscoveryMessageJNI(long instance, final String topic, final byte[] data, long dataLen);
269
270     /* Native API for publishing to a topic */
271     private native void publishJNI(long instance, final String topic, final byte[] data, long dataLen, int protocol, int qos, boolean retain);
272
273     /* Native API for subscribing to a topic */
274     private native long subscribeJNI(long instance, final String topic, int protocol, int qos);
275
276     /* Native API for unsubscribing a topic */
277     private native void unsubscribeJNI(long instance, final long aittSubId);
278 }