kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Convert sample project to Kotlin (#3111)
rodzic
be6e9ad5ec
commit
58344c1c0f
|
@ -1,26 +0,0 @@
|
|||
package com.meshtastic.android.meshserviceexample;
|
||||
|
||||
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.meshtastic.android.meshserviceexample", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.meshtastic.android.meshserviceexample
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
Assert.assertEquals("com.meshtastic.android.meshserviceexample", appContext.packageName)
|
||||
}
|
||||
}
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.meshtastic.android.meshserviceexample;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.geeksville.mesh.DataPacket;
|
||||
import com.geeksville.mesh.IMeshService;
|
||||
import com.geeksville.mesh.MessageStatus;
|
||||
import com.geeksville.mesh.NodeInfo;
|
||||
import com.geeksville.mesh.Portnums;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "MeshServiceExample";
|
||||
private IMeshService meshService;
|
||||
private ServiceConnection serviceConnection;
|
||||
private boolean isMeshServiceBound = false;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_main);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
|
||||
TextView mainTextView = findViewById(R.id.mainTextView);
|
||||
ImageView statusImageView = findViewById(R.id.statusImageView);
|
||||
Button sendButton = findViewById(R.id.sendBtn);
|
||||
|
||||
sendButton.setOnClickListener(v -> {
|
||||
if (meshService != null) {
|
||||
try {
|
||||
byte[] bytes = "Hello from MeshServiceExample".getBytes();
|
||||
DataPacket dataPacket = new DataPacket(DataPacket.ID_BROADCAST, bytes, Portnums.PortNum.TEXT_MESSAGE_APP_VALUE, DataPacket.ID_LOCAL, System.currentTimeMillis(), 0, MessageStatus.UNKNOWN, 3, 0, true);
|
||||
meshService.send(dataPacket);
|
||||
Log.d(TAG, "Message sent successfully");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to send message", e);
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "MeshService is not bound, cannot send message");
|
||||
}
|
||||
});
|
||||
|
||||
// Now you can call methods on meshService
|
||||
serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
meshService = IMeshService.Stub.asInterface(service);
|
||||
Log.i(TAG, "Connected to MeshService");
|
||||
isMeshServiceBound = true;
|
||||
statusImageView.setImageResource(android.R.color.holo_green_light);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
meshService = null;
|
||||
isMeshServiceBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle the received broadcast
|
||||
// handle node changed
|
||||
// handle position app data
|
||||
BroadcastReceiver meshtasticReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent == null || intent.getAction() == null) {
|
||||
Log.w(TAG, "Received null intent or action");
|
||||
return;
|
||||
}
|
||||
// Handle the received broadcast
|
||||
String action = intent.getAction();
|
||||
Log.d(TAG, "Received broadcast: " + action);
|
||||
|
||||
switch (Objects.requireNonNull(action)) {
|
||||
case "com.geeksville.mesh.NODE_CHANGE":
|
||||
// handle node changed
|
||||
try {
|
||||
NodeInfo ni = intent.getParcelableExtra("com.geeksville.mesh.NodeInfo");
|
||||
Log.d(TAG, "NodeInfo: " + ni);
|
||||
mainTextView.setText("NodeInfo: " + ni);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onReceive: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "com.geeksville.mesh.MESSAGE_STATUS":
|
||||
int id = intent.getIntExtra("com.geeksville.mesh.PacketId", 0);
|
||||
MessageStatus status = intent.getParcelableExtra("com.geeksville.mesh.Status");
|
||||
Log.d(TAG, "Message Status ID: " + id + " Status: " + status);
|
||||
break;
|
||||
case "com.geeksville.mesh.MESH_CONNECTED": {
|
||||
String extraConnected = intent.getStringExtra("com.geeksville.mesh.Connected");
|
||||
boolean connected = extraConnected.equalsIgnoreCase("connected");
|
||||
Log.d(TAG, "Received ACTION_MESH_CONNECTED: " + extraConnected);
|
||||
if (connected) {
|
||||
statusImageView.setImageResource(android.R.color.holo_green_light);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "com.geeksville.mesh.MESH_DISCONNECTED": {
|
||||
String extraConnected = intent.getStringExtra("com.geeksville.mesh.Disconnected");
|
||||
boolean disconnected = extraConnected.equalsIgnoreCase("disconnected");
|
||||
Log.d(TAG, "Received ACTION_MESH_DISTCONNECTED: " + extraConnected);
|
||||
if (disconnected) {
|
||||
statusImageView.setImageResource(android.R.color.holo_red_light);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "com.geeksville.mesh.RECEIVED.POSITION_APP": {
|
||||
// handle position app data
|
||||
try {
|
||||
NodeInfo ni = intent.getParcelableExtra("com.geeksville.mesh.NodeInfo");
|
||||
Log.d(TAG, "Position App NodeInfo: " + ni);
|
||||
mainTextView.setText("Position App NodeInfo: " + ni);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Log.w(TAG, "Unknown action: " + action);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.geeksville.mesh.NODE_CHANGE");
|
||||
filter.addAction("com.geeksville.mesh.RECEIVED.NODEINFO_APP");
|
||||
filter.addAction("com.geeksville.mesh.RECEIVED.POSITION_APP");
|
||||
filter.addAction("com.geeksville.mesh.MESH_CONNECTED");
|
||||
filter.addAction("com.geeksville.mesh.MESH_DISCONNECTED");
|
||||
registerReceiver(meshtasticReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
|
||||
Log.d(TAG, "Registered meshtasticPacketReceiver");
|
||||
|
||||
while (!bindMeshService()) {
|
||||
try {
|
||||
// Wait for the service to bind
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Binding interrupted", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindMeshService();
|
||||
}
|
||||
|
||||
private boolean bindMeshService() {
|
||||
try {
|
||||
Log.i(TAG, "Attempting to bind to Mesh Service...");
|
||||
Intent intent = new Intent("com.geeksville.mesh.Service");
|
||||
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.service.MeshService");
|
||||
return bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to bind", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unbindMeshService() {
|
||||
if (isMeshServiceBound) {
|
||||
try {
|
||||
unbindService(serviceConnection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "MeshService not registered or already unbound: " + e.getMessage());
|
||||
}
|
||||
isMeshServiceBound = false;
|
||||
meshService = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.meshtastic.android.meshserviceexample
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.geeksville.mesh.DataPacket
|
||||
import com.geeksville.mesh.IMeshService
|
||||
import com.geeksville.mesh.MessageStatus
|
||||
import com.geeksville.mesh.NodeInfo
|
||||
import com.geeksville.mesh.Portnums
|
||||
|
||||
private const val TAG: String = "MeshServiceExample"
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var meshService: IMeshService? = null
|
||||
private var serviceConnection: ServiceConnection? = null
|
||||
private var isMeshServiceBound = false
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
this.enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_main)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
val mainTextView = findViewById<TextView>(R.id.mainTextView)
|
||||
val statusImageView = findViewById<ImageView>(R.id.statusImageView)
|
||||
|
||||
findViewById<Button>(R.id.sendBtn).setOnClickListener { _ ->
|
||||
meshService?.let {
|
||||
try {
|
||||
it.send(
|
||||
DataPacket(
|
||||
to = DataPacket.ID_BROADCAST,
|
||||
bytes = "Hello from MeshServiceExample".toByteArray(),
|
||||
dataType = Portnums.PortNum.TEXT_MESSAGE_APP_VALUE,
|
||||
from = DataPacket.ID_LOCAL,
|
||||
time = System.currentTimeMillis(),
|
||||
id = 0,
|
||||
status = MessageStatus.UNKNOWN,
|
||||
hopLimit = 3,
|
||||
channel = 0,
|
||||
wantAck = true,
|
||||
),
|
||||
)
|
||||
Log.d(TAG, "Message sent successfully")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to send message", e)
|
||||
}
|
||||
} ?: Log.w(TAG, "MeshService is not bound, cannot send message")
|
||||
}
|
||||
|
||||
// Now you can call methods on meshService
|
||||
serviceConnection =
|
||||
object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
meshService = IMeshService.Stub.asInterface(service)
|
||||
Log.i(TAG, "Connected to MeshService")
|
||||
isMeshServiceBound = true
|
||||
statusImageView.setImageResource(android.R.color.holo_green_light)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
meshService = null
|
||||
isMeshServiceBound = false
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the received broadcast
|
||||
// handle node changed
|
||||
// handle position app data
|
||||
val meshtasticReceiver: BroadcastReceiver =
|
||||
object : BroadcastReceiver() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null) {
|
||||
Log.w(TAG, "Received null intent")
|
||||
return
|
||||
}
|
||||
|
||||
val action = intent.action
|
||||
|
||||
if (intent.action == null) {
|
||||
Log.w(TAG, "Received null action")
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Received broadcast: $action")
|
||||
|
||||
when (action) {
|
||||
"com.geeksville.mesh.NODE_CHANGE" ->
|
||||
try {
|
||||
val ni = intent.getParcelableExtra("com.geeksville.mesh.NodeInfo", NodeInfo::class.java)
|
||||
Log.d(TAG, "NodeInfo: $ni")
|
||||
mainTextView.text = "NodeInfo: $ni"
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "onReceive: ${e.message}")
|
||||
return
|
||||
}
|
||||
|
||||
"com.geeksville.mesh.MESSAGE_STATUS" -> {
|
||||
val id = intent.getIntExtra("com.geeksville.mesh.PacketId", 0)
|
||||
val status =
|
||||
intent.getParcelableExtra("com.geeksville.mesh.Status", MessageStatus::class.java)
|
||||
Log.d(TAG, "Message Status ID: $id Status: $status")
|
||||
}
|
||||
|
||||
"com.geeksville.mesh.MESH_CONNECTED" -> {
|
||||
val extraConnected = intent.getStringExtra("com.geeksville.mesh.Connected")
|
||||
val connected = extraConnected.equals("connected", ignoreCase = true)
|
||||
Log.d(TAG, "Received ACTION_MESH_CONNECTED: $extraConnected")
|
||||
if (connected) {
|
||||
statusImageView.setImageResource(android.R.color.holo_green_light)
|
||||
}
|
||||
}
|
||||
|
||||
"com.geeksville.mesh.MESH_DISCONNECTED" -> {
|
||||
val extraConnected = intent.getStringExtra("com.geeksville.mesh.Disconnected")
|
||||
val disconnected = extraConnected.equals("disconnected", ignoreCase = true)
|
||||
Log.d(TAG, "Received ACTION_MESH_DISCONNECTED: $extraConnected")
|
||||
if (disconnected) {
|
||||
statusImageView.setImageResource(android.R.color.holo_red_light)
|
||||
}
|
||||
}
|
||||
|
||||
"com.geeksville.mesh.RECEIVED.POSITION_APP" -> {
|
||||
try {
|
||||
val ni = intent.getParcelableExtra("com.geeksville.mesh.NodeInfo", NodeInfo::class.java)
|
||||
Log.d(TAG, "Position App NodeInfo: $ni")
|
||||
mainTextView.text = "Position App NodeInfo: $ni"
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
else -> Log.w(TAG, "Unknown action: $action")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filter =
|
||||
IntentFilter().apply {
|
||||
addAction("com.geeksville.mesh.NODE_CHANGE")
|
||||
addAction("com.geeksville.mesh.RECEIVED.NODEINFO_APP")
|
||||
addAction("com.geeksville.mesh.RECEIVED.POSITION_APP")
|
||||
addAction("com.geeksville.mesh.MESH_CONNECTED")
|
||||
addAction("com.geeksville.mesh.MESH_DISCONNECTED")
|
||||
}
|
||||
registerReceiver(meshtasticReceiver, filter, RECEIVER_NOT_EXPORTED)
|
||||
Log.d(TAG, "Registered meshtasticPacketReceiver")
|
||||
|
||||
while (!bindMeshService()) {
|
||||
try {
|
||||
Thread.sleep(1000)
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, "Binding interrupted", e)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unbindMeshService()
|
||||
}
|
||||
|
||||
private fun bindMeshService(): Boolean {
|
||||
try {
|
||||
Log.i(TAG, "Attempting to bind to Mesh Service...")
|
||||
val intent = Intent("com.geeksville.mesh.Service")
|
||||
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.service.MeshService")
|
||||
return bindService(intent, serviceConnection!!, BIND_AUTO_CREATE)
|
||||
} catch (e: java.lang.Exception) {
|
||||
Log.e(TAG, "Failed to bind", e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun unbindMeshService() {
|
||||
if (isMeshServiceBound) {
|
||||
try {
|
||||
unbindService(serviceConnection!!)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.w(TAG, "MeshService not registered or already unbound: " + e.message)
|
||||
}
|
||||
isMeshServiceBound = false
|
||||
meshService = null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.meshtastic.android.meshserviceexample;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.meshtastic.android.meshserviceexample
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
Assert.assertEquals(4, (2 + 2).toLong())
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue