cmake_minimum_required(VERSION 3.4.1)
-project("aitt-android" CXX)
+project("aitt-native" CXX)
if(NOT DEFINED PROJECT_ROOT_DIR)
set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
--- /dev/null
+plugins {
+ id 'com.android.library'
+ id "de.undercouch.download" version "5.0.1"
+}
+
+def thirdPartyDir = new File ("${rootProject.projectDir}/third_party")
+
+def flatbuffersDir = new File("${thirdPartyDir}/flatbuffers-2.0.0")
+def mosquittoDir = new File("${thirdPartyDir}/mosquitto-2.0.14")
+
+android {
+ compileSdkVersion 33
+ ndkVersion "21.3.6528147"
+
+ defaultConfig {
+ minSdkVersion 28
+ targetSdkVersion 33
+ versionCode 1
+ versionName '1.0'
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ externalNativeBuild {
+ cmake {
+ arguments '-DLOG_STDOUT=OFF'
+ arguments '-DCMAKE_VERBOSE_MAKEFILE=1'
+ arguments '-DCMAKE_INSTALL_PREFIX:PATH=/usr'
+ arguments '-DANDROID_STL=c++_shared'
+ arguments "-DANDROID_NDK_HOME=${System.env.ANDROID_NDK_ROOT}"
+ arguments "-DGSTREAMER_ROOT_ANDROID=${System.env.GSTREAMER_ROOT_ANDROID}"
+ arguments '-DBUILD_TESTING=OFF'
+ arguments '-DUSE_PREBUILT=OFF'
+ arguments '-DVERSIONING=OFF'
+ arguments '-DPLATFORM=android'
+ arguments '-DCOVERAGE=OFF'
+ abiFilters 'arm64-v8a', 'x86'
+ cppFlags "-std=c++17"
+ targets "aitt-native", "aitt-transport-tcp"
+ }
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path file('./CMakeLists.txt')
+ }
+ }
+
+ buildFeatures {
+ prefab true
+ }
+
+ packagingOptions {
+ jniLibs {
+ useLegacyPackaging = true
+ }
+ pickFirst 'lib/arm64-v8a/libaitt-common.so'
+ }
+ libraryVariants.all { variant ->
+ variant.outputs.all {
+ outputFileName = "${archivesBaseName}-${defaultConfig.versionName}.aar"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ compileOnly project(":android:flatbuffers")
+ compileOnly project(":android:mosquitto")
+ implementation 'com.google.flatbuffers:flatbuffers-java:2.0.0'
+ implementation 'com.android.ndk.thirdparty:openssl:1.1.1g-alpha-1'
+
+ implementation 'androidx.appcompat:appcompat:1.5.0'
+ implementation 'com.google.android.material:material:1.6.1'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+}
+
+task downloadFlatBuffers(type: Download) {
+ doFirst {
+ println("Downloading FlatBuffers")
+ }
+ src "https://github.com/google/flatbuffers/archive/refs/tags/v2.0.0.zip"
+ dest new File(thirdPartyDir, "flatbuffers.zip")
+ onlyIfModified true
+}
+
+task unzipFlatBuffers(type: Copy, dependsOn: downloadFlatBuffers) {
+ doFirst {
+ println("Unzipping FlatBuffers")
+ }
+ from zipTree(downloadFlatBuffers.dest)
+ into thirdPartyDir
+ onlyIf { !flatbuffersDir.exists() }
+}
+
+task downloadMosquitto(type: Download) {
+ doFirst {
+ println("Downloading Mosquitto")
+ }
+ src "https://github.com/eclipse/mosquitto/archive/refs/tags/v2.0.14.zip"
+ dest new File(thirdPartyDir, "mosquitto-2.0.14.zip")
+ onlyIfModified true
+}
+
+task unzipMosquitto(type: Copy, dependsOn: downloadMosquitto) {
+ doFirst {
+ println("Unzipping Mosquitto")
+ }
+ from zipTree(downloadMosquitto.dest)
+ into thirdPartyDir
+ onlyIf { !mosquittoDir.exists() }
+}
+
+preBuild.dependsOn(unzipFlatBuffers)
+preBuild.dependsOn(unzipMosquitto)
+preBuild.dependsOn ":android:flatbuffers:build"
+preBuild.dependsOn ":android:mosquitto:build"
--- /dev/null
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
--- /dev/null
+package com.example.aittnative;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.aittnative.test", appContext.getPackageName());
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.samsung.android.aittnative">
+
+</manifest>
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.samsung.android.aittnative;
+
+/**
+ * Jni Interface class as intermediate layer for android aitt and other transport modules to interact with JNI module.
+ */
+public class JniInterface {
+
+ private JniCallback jniCallback;
+ private JniConnectionCallback jniConnectionCallback;
+ private long instance = 0;
+
+ /**
+ * Load aitt-android library
+ */
+ static {
+ try {
+ System.loadLibrary("aitt-native");
+ } catch (UnsatisfiedLinkError e) {
+ // only ignore exception in non-android env
+ if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e;
+ }
+ }
+
+ /**
+ * JNI callback interface to send data from JNI layer to Java layer(aitt or transport module)
+ */
+ public interface JniCallback {
+ void jniDataPush(String topic, byte[] data);
+ }
+
+ /**
+ * JNI callback interface to send connection callback status to aitt layer
+ */
+ public interface JniConnectionCallback {
+ void jniConnectionCB(int status);
+ }
+
+ /**
+ * JNI interface constructor
+ */
+ public JniInterface() {
+
+ }
+
+ /**
+ * JNI interface API to initialize JNI module
+ * @param id unique mqtt id
+ * @param ip self IP address of device
+ * @param clearSession to clear current session if client disconnects
+ * @return returns the JNI instance object in long
+ */
+ public long init(String id, String ip, boolean clearSession) {
+ instance = initJNI(id, ip, clearSession);
+ return instance;
+ }
+
+ /**
+ * JNI Interface API to connect to MQTT broker
+ * @param brokerIp mqtt broker ip address
+ * @param port mqtt broker port number
+ */
+ public void connect(String brokerIp, int port) {
+ connectJNI(instance, brokerIp, port);
+ }
+
+ /**
+ * JNI Interface API to subscribe to a topic
+ * @param topic String to which applications can subscribe, to receive data
+ * @param protocol Protocol supported by application, invoking subscribe
+ * @param qos QoS at which the message should be delivered
+ * @return returns the subscribe instance in long
+ */
+ public long subscribe(final String topic, int protocol, int qos) {
+ return subscribeJNI(instance, topic, protocol, qos);
+ }
+
+ /**
+ * JNI Interface API to disconnect from broker
+ */
+ public void disconnect() {
+ disconnectJNI(instance);
+ }
+
+ /**
+ * JNI Interface API to publish data to specified topic
+ * @param topic String to which message needs to be published
+ * @param data Byte message to be published
+ * @param datalen Size/length of the message to be published
+ * @param protocol Protocol to be used to publish message
+ * @param qos QoS at which the message should be delivered
+ * @param retain Boolean to decide whether or not the message should be retained by the broker
+ */
+ public void publish(final String topic, final byte[] data, long datalen, int protocol, int qos, boolean retain) {
+ publishJNI(instance, topic, data, datalen, protocol, qos, retain);
+ }
+
+ /**
+ * JNI Interface API to unsubscribe the given topic
+ * @param aittSubId Subscribe ID of the topics to be unsubscribed
+ */
+ public void unsubscribe(final long aittSubId) {
+ unsubscribeJNI(instance, aittSubId);
+ }
+
+ /**
+ * JNI Interface API to set connection callback instance
+ * @param cb callback instance of JniConnectionCallback interface
+ */
+ public void setConnectionCallback(JniConnectionCallback cb) {
+ jniConnectionCallback = cb;
+ setConnectionCallbackJNI(instance);
+ }
+
+ /**
+ * JNI Interface API to register jni callback instance
+ * @param callBack callback instance of JniCallback interface
+ */
+ public void registerJniCallback(JniCallback callBack) {
+ jniCallback = callBack;
+ }
+
+ /**
+ * messageCallback API to receive data from JNI layer to JNI interface layer
+ * @param topic Topic to which data is received
+ * @param payload Data that is sent from JNI to JNI interface layer
+ */
+ private void messageCallback(String topic, byte[] payload) {
+ jniCallback.jniDataPush(topic, payload);
+ }
+
+ /**
+ * connectionStatusCallback API to receive connection status from JNI to JNI interface layer
+ * @param status status of the device connection with mqtt broker
+ */
+ private void connectionStatusCallback(int status) {
+ if (jniConnectionCallback != null) {
+ jniConnectionCallback.jniConnectionCB(status);
+ }
+ }
+
+ /* native API's set */
+ /* Native API to initialize JNI */
+ private native long initJNI(String id, String ip, boolean clearSession);
+
+ /* Native API for connecting to broker */
+ private native void connectJNI(long instance, final String host, int port);
+
+ /* Native API for disconnecting from broker */
+ private native void disconnectJNI(long instance);
+
+ /* Native API for setting connection callback */
+ private native void setConnectionCallbackJNI(long instance);
+
+ /* Native API for publishing to a topic */
+ private native void publishJNI(long instance, final String topic, final byte[] data, long datalen, int protocol, int qos, boolean retain);
+
+ /* Native API for subscribing to a topic */
+ private native long subscribeJNI(long instance, final String topic, int protocol, int qos);
+
+ /* Native API for unsubscribing a topic */
+ private native void unsubscribeJNI(long instance, final long aittSubId);
+}
* @param jniInterfaceObject JNI interface object
* @param id unique mqtt id
* @param ip self IP address of device
- * @param clearSession "to clear current session if client disconnects
+ * @param clearSession to clear current session if client disconnects
* @return returns the aitt interface object in long
*/
jlong AittNativeInterface::init(JNIEnv *env,
try {
instance->cbObject = env->NewGlobalRef(jniInterfaceObject);
- jclass callbackClass = env->FindClass("com/samsung/android/aitt/Aitt");
+ jclass callbackClass = env->FindClass("com/samsung/android/aittnative/JniInterface");
cbContext.messageCallbackMethodID =
env->GetMethodID(callbackClass, "messageCallback", "(Ljava/lang/String;[B)V");
cbContext.connectionCallbackMethodID =
JNI_LOG(ANDROID_LOG_ERROR, TAG, "Not a valid JNI version");
return JNI_ERR;
}
- jclass klass = env->FindClass("com/samsung/android/aitt/Aitt");
+ jclass klass = env->FindClass("com/samsung/android/aittnative/JniInterface");
if (nullptr == klass) {
JNI_LOG(ANDROID_LOG_ERROR, TAG, "klass is null");
return JNI_ERR;
--- /dev/null
+package com.example.aittnative;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
plugins {
id 'com.android.library'
- id "de.undercouch.download" version "5.0.1"
}
-def thirdPartyDir = new File("${rootProject.projectDir}/third_party")
-
-def flatbuffersDir = new File("${thirdPartyDir}/flatbuffers-2.0.0")
-def mosquittoDir = new File("${thirdPartyDir}/mosquitto-2.0.14")
-
android {
- compileSdkVersion 31
- ndkVersion "21.3.6528147"
+ compileSdkVersion 32
defaultConfig {
minSdkVersion 28
targetSdkVersion 31
versionName '1.0'
project.archivesBaseName = "aitt"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- externalNativeBuild {
- cmake {
- arguments '-DLOG_STDOUT=OFF'
- arguments '-DCMAKE_VERBOSE_MAKEFILE=1'
- arguments '-DCMAKE_INSTALL_PREFIX:PATH=/usr'
- arguments '-DANDROID_STL=c++_shared'
- arguments "-DANDROID_NDK_HOME=${System.env.ANDROID_NDK_ROOT}"
- arguments "-DGSTREAMER_ROOT_ANDROID=${System.env.GSTREAMER_ROOT_ANDROID}"
- arguments '-DBUILD_TESTING=OFF'
- arguments '-DUSE_PREBUILT=OFF'
- arguments '-DVERSIONING=OFF'
- arguments '-DPLATFORM=android'
- arguments '-DCOVERAGE=OFF'
- abiFilters 'arm64-v8a', 'x86'
- cppFlags "-std=c++17"
- targets "aitt-android", "aitt-transport-tcp"
- }
- }
}
- externalNativeBuild {
- cmake {
- path file('./CMakeLists.txt')
- }
- }
- buildFeatures {
- prefab true
- }
buildTypes {
debug {
debuggable true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
- packagingOptions {
- jniLibs {
- useLegacyPackaging = true
- }
- pickFirst 'lib/armeabi-v7a/libaitt.so'
- }
+
libraryVariants.all { variant ->
variant.outputs.all {
outputFileName = "${archivesBaseName}-${defaultConfig.versionName}.aar"
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
}
+ jvmArgs '-noverify'
}
}
}
dependencies {
- compileOnly project(":android:flatbuffers")
- compileOnly project(":android:mosquitto")
-
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.flatbuffers:flatbuffers-java:2.0.0'
- implementation 'com.android.ndk.thirdparty:openssl:1.1.1g-alpha-1'
-
implementation project(path: ':android:modules:tcp')
implementation project(path: ':android:modules:webrtc')
+ implementation project(path: ':android:aitt-native')
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:2.25.0'
- testImplementation 'org.powermock:powermock-core:2.0.0-beta.5'
- testImplementation 'org.powermock:powermock-module-junit4:2.0.0-beta.5'
- testImplementation 'org.powermock:powermock-api-mockito2:2.0.0-beta.5'
+ testImplementation 'org.robolectric:robolectric:4.8.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
-task downloadFlatBuffers(type: Download) {
- doFirst {
- println("Downloading FlatBuffers")
- }
- src "https://github.com/google/flatbuffers/archive/refs/tags/v2.0.0.zip"
- dest new File(thirdPartyDir, "flatbuffers.zip")
- onlyIfModified true
-}
-
-task unzipFlatBuffers(type: Copy, dependsOn: downloadFlatBuffers) {
- doFirst {
- println("Unzipping FlatBuffers")
- }
- from zipTree(downloadFlatBuffers.dest)
- into thirdPartyDir
- onlyIf { !flatbuffersDir.exists() }
-}
-
-task downloadMosquitto(type: Download) {
- doFirst {
- println("Downloading Mosquitto")
- }
- src "https://github.com/eclipse/mosquitto/archive/refs/tags/v2.0.14.zip"
- dest new File(thirdPartyDir, "mosquitto-2.0.14.zip")
- onlyIfModified true
-}
-
-task unzipMosquitto(type: Copy, dependsOn: downloadMosquitto) {
- doFirst {
- println("Unzipping Mosquitto")
- }
- from zipTree(downloadMosquitto.dest)
- into thirdPartyDir
- onlyIf { !mosquittoDir.exists() }
-}
-
-preBuild.dependsOn(unzipFlatBuffers)
-preBuild.dependsOn(unzipMosquitto)
-preBuild.dependsOn ":android:flatbuffers:build"
-preBuild.dependsOn ":android:mosquitto:build"
-
apply plugin: 'jacoco'
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
import androidx.annotation.Nullable;
import com.google.flatbuffers.FlexBuffers;
+import com.samsung.android.aittnative.JniInterface;
import java.nio.ByteBuffer;
import java.util.ArrayList;
private static final String TAG = "AITT_ANDROID";
private static final String INVALID_TOPIC = "Invalid topic";
- /**
- * Load aitt-android library
- */
- static {
- try {
- System.loadLibrary("aitt-android");
- }catch (UnsatisfiedLinkError e){
- // only ignore exception in non-android env
- if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e;
- }
- }
private Map<String, ArrayList<SubscribeCallback>> subscribeCallbacks = new HashMap<>();
private Map<String, HostTable> publishTable = new HashMap<>();
private Map<String, Pair<Protocol, Object>> subscribeMap = new HashMap<>();
private Map<String, Long> aittSubId = new HashMap<>();
private ConnectionCallback connectionCallback = null;
+ private JniInterface mJniInterface = new JniInterface();
private long instance = 0;
private String ip;
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("Invalid id");
}
- instance = initJNI(id, ip, clearSession);
+ instance = mJniInterface.init(id, ip, clearSession);
if (instance == 0L) {
throw new InstantiationException("Failed to instantiate native instance");
}
this.ip = ip;
this.appContext = appContext;
+ mJniInterface.registerJniCallback(new JniInterface.JniCallback(){
+ @Override
+ public void jniDataPush(String _topic, byte[] payload) {
+ messageCallback(_topic, payload);
+ }
+ });
}
/**
throw new IllegalArgumentException("Invalid callback");
}
connectionCallback = callback;
- setConnectionCallbackJNI(instance);
+ mJniInterface.setConnectionCallback(new JniInterface.JniConnectionCallback(){
+ @Override
+ public void jniConnectionCB(int status) {
+ connectionStatusCallback(status);
+ }
+ });
}
/**
if (brokerIp == null || brokerIp.isEmpty()) {
brokerIp = Definitions.AITT_LOCALHOST;
}
- connectJNI(instance, brokerIp, port);
+ mJniInterface.connect(brokerIp, port);
//Subscribe to java discovery topic
- subscribeJNI(instance, Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, Protocol.MQTT.getValue(), QoS.EXACTLY_ONCE.ordinal());
+ mJniInterface.subscribe(Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, Protocol.MQTT.getValue(), QoS.EXACTLY_ONCE.ordinal());
}
/**
* Method to disconnect from MQTT broker
*/
public void disconnect() {
- publishJNI(instance, Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, new byte[0], 0, Protocol.MQTT.getValue(), QoS.AT_LEAST_ONCE.ordinal(), true);
+ mJniInterface.publish(Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, new byte[0], 0, Protocol.MQTT.getValue(), QoS.AT_LEAST_ONCE.ordinal(), true);
- disconnectJNI(instance);
+ mJniInterface.disconnect();
try {
close();
} catch (Exception e) {
}
if(jniProtocols > 0) {
- publishJNI(instance, topic, message, message.length, jniProtocols, qos.ordinal(), retain);
+ mJniInterface.publish(topic, message, message.length, jniProtocols, qos.ordinal(), retain);
}
for(Protocol pro : protocols) {
}
if(jniProtocols > 0) {
- Long pObject = subscribeJNI(instance, topic, jniProtocols, qos.ordinal());
+ Long pObject = mJniInterface.subscribe(topic, jniProtocols, qos.ordinal());
synchronized (this) {
aittSubId.put(topic, pObject);
}
messageReceived(message);
});
byte[] data = transportHandler.getPublishData();
- publishJNI(instance, Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, data, data.length, Protocol.MQTT.value, QoS.EXACTLY_ONCE.ordinal(), true);
+ mJniInterface.publish(Definitions.JAVA_SPECIFIC_DISCOVERY_TOPIC, data, data.length, Protocol.MQTT.value, QoS.EXACTLY_ONCE.ordinal(), true);
}
} catch (Exception e) {
Log.e(TAG, "Error during subscribe", e);
}
}
if (paittSubId != null) {
- unsubscribeJNI(instance, paittSubId);
+ mJniInterface.unsubscribe(paittSubId);
}
}
* 2: MQTT connection failed
*/
private void connectionStatusCallback(int status) {
-
switch (status) {
case 0:
connectionCallback.onDisconnected();
}
}
- /* native API's set */
- /* Native API to initialize JNI */
- private native long initJNI(String id, String ip, boolean clearSession);
-
- /* Native API for connecting to broker */
- private native void connectJNI(long instance, final String host, int port);
-
- /* Native API for disconnecting from broker */
- private native void disconnectJNI(long instance);
-
- /* Native API for setting connection callback */
- private native void setConnectionCallbackJNI(long instance);
-
- /* Native API for publishing to a topic */
- private native void publishJNI(long instance, final String topic, final byte[] data, long datalen, int protocol, int qos, boolean retain);
-
- /* Native API for subscribing to a topic */
- private native long subscribeJNI(long instance, final String topic, int protocol, int qos);
-
- /* Native API for unsubscribing a topic */
- private native void unsubscribeJNI(long instance, final long aittSubId);
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.api.support.membermodification.MemberMatcher;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(Aitt.class)
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowJniInterface.class)
public class AittUnitTest {
@Mock
private final Context appContext = mock(Context.class);
private final String message = "test message";
private final String aittId = "aitt";
+ ShadowJniInterface shadowJniInterface = new ShadowJniInterface();
+
private Method messageCallbackMethod;
@Before
public void initialize() {
try {
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "initJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return 1L;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "connectJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return null;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "disconnectJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return null;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "setConnectionCallbackJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return null;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "publishJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return null;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "subscribeJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return 1L;
- }
- });
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "unsubscribeJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return null;
- }
- });
-
messageCallbackMethod = Aitt.class.getDeclaredMethod("messageCallback", String.class, byte[].class);
messageCallbackMethod.setAccessible(true);
} catch(Exception e) {
- fail("Failed to mock Aitt " + e);
+ fail("Failed to Initialize " + e);
}
}
public void testAittConstructor_P(){
String id = "aitt";
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, id);
assertNotNull("Aitt Instance not null", aitt);
} catch(Exception e) {
public void testInitializeInvalidId_N() {
String _id = "";
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, _id);
aitt.close();
} catch(InstantiationException e) {
public void testInitializeInvalidContext_N() {
String _id = "";
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(null, _id);
aitt.close();
} catch(InstantiationException e) {
@Test(expected = InstantiationException.class)
public void testConstructorFail_N() throws InstantiationException {
- try{
- PowerMockito.replace(MemberMatcher.method(Aitt.class, "initJNI")).with(new InvocationHandler() {
- @Override
- public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return 0L;
- }
- });
- } catch(Exception e) {
- fail("Failed to replace method" + e);
- }
+ shadowJniInterface.setInitReturn(false);
String id = "aitt";
Aitt aitt = new Aitt(appContext,id);
aitt.close();
@Test
public void testConnect_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testConnectWithoutIP_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testDisconnect_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testPublishMqtt_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testPublishWebRTC_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testPublishInvalidTopic_N(){
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
String _topic = "";
@Test
public void testPublishAnyProtocol_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testPublishProtocolSet_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testPublishInvalidProtocol_N(){
try{
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp,port);
byte[] payload = message.getBytes();
@Test
public void testSubscribeMqtt_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testSubscribeWebRTC_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
}
}
-
@Test
public void testSubscribeInvalidTopic_N() {
-
try{
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
@Test
public void testSubscribeInvalidCallback_N() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
@Test
public void testSubscribeAnyProtocol_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testSubscribeInvalidProtocol_N() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
@Test
public void testSubscribeProtocolSet_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testUnsubscribe_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testUnsubscribeInvalidTopic_N() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
@Test
public void testSetConnectionCallback_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testSetConnectionCallbackInvalidCallback_N() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertThrows(IllegalArgumentException.class, () -> {
@Test
public void testSubscribeMultipleCallbacks_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testDiscoveryMessageCallbackConnected_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testDiscoveryMessageCallbackDisconnected_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testDiscoveryMessageCallbackEmptyPayload_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
assertNotNull("Aitt Instance not null", aitt);
@Test
public void testSubscribeCallbackVerifyTopic_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
@Test
public void testSubscribeCallbackVerifyPayload_P() {
try {
+ shadowJniInterface.setInitReturn(true);
Aitt aitt = new Aitt(appContext, aittId);
aitt.connect(brokerIp, port);
--- /dev/null
+package com.samsung.android.aitt;
+
+import com.samsung.android.aittnative.JniInterface;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(JniInterface.class)
+public class ShadowJniInterface {
+ private static boolean initReturn = true;
+
+ @Implementation
+ public long init(String id, String ip, boolean clearSession){
+ if(initReturn)
+ return 1L;
+ else
+ return 0L;
+ }
+
+ @Implementation
+ public void connect(long instance, final String host, int port){
+ }
+
+ @Implementation
+ public void publish(long instance, final String topic, final byte[] data, long datalen, int protocol, int qos, boolean retain){
+ }
+
+ @Implementation
+ public void disconnect(long instance){
+
+ }
+ @Implementation
+ public long subscribe(long instance, final String topic, int protocol, int qos){
+ return 1L;
+ }
+
+ @Implementation
+ public void unsubscribe(long instance, final long aittSubId){
+ }
+
+ public void setInitReturn(boolean initReturn) {
+ this.initReturn = initReturn;
+ }
+}
include ':android:mosquitto'
include ':android:modules:tcp'
include ':android:modules:webrtc'
+include ':android:aitt-native'