Improved TNC connection/disconnection with service integration

pull/37/head
sh123 2022-07-08 11:38:55 +03:00
rodzic e1b3519dd7
commit a2fd55ff4b
27 zmienionych plików z 208 dodań i 48 usunięć

Wyświetl plik

@ -10,8 +10,8 @@ android {
applicationId "com.radio.codec2talkie"
minSdkVersion 23
targetSdkVersion 30
versionCode 123
versionName "1.23"
versionCode 124
versionName "1.24"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Wyświetl plik

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true" />

Wyświetl plik

@ -104,6 +104,8 @@ public class MainActivity extends AppCompatActivity {
private ProgressBar _progressRssi;
private Button _btnPtt;
private boolean _isPaused = false;
private boolean _isConnecting = false;
private boolean _isAppExit = false;
private boolean _isAppRestart = false;
@ -112,8 +114,8 @@ public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
// title
String appName = getResources().getString(R.string.app_name);
@ -142,6 +144,7 @@ public class MainActivity extends AppCompatActivity {
// PTT button
_btnPtt = findViewById(R.id.btnPtt);
_btnPtt.setEnabled(false);
_btnPtt.setOnTouchListener(onBtnPttTouchListener);
_textCodecMode = findViewById(R.id.codecMode);
@ -172,17 +175,56 @@ public class MainActivity extends AppCompatActivity {
_isAppRestart = false;
_isAppExit = false;
startTransportConnection();
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart()");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop()");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy()");
unregisterReceiver(onBluetoothDisconnected);
unregisterReceiver(onUsbDetached);
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause()");
_isPaused = true;
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume()");
_isPaused = false;
if (!AppService.isRunning && !_isConnecting) {
_btnPtt.setEnabled(false);
startTransportConnection();
}
}
private void exitApplication() {
Log.i(TAG, "exitApplication()");
_isAppExit = true;
if (_appService != null) {
_appService.stopRunning();
@ -190,6 +232,7 @@ public class MainActivity extends AppCompatActivity {
}
private void restartApplication() {
Log.i(TAG, "restartApplication()");
_isAppRestart = true;
if (_appService != null) {
_appService.stopRunning();
@ -197,8 +240,10 @@ public class MainActivity extends AppCompatActivity {
}
private void startTransportConnection() {
Log.i(TAG, "Starting transport connection");
if (_isTestMode) {
Log.i(TAG, "startTransportConnection()");
if (AppService.isRunning) {
startAppService(AppService.transportType);
} else if (_isTestMode) {
_textConnInfo.setText(R.string.main_status_loopback_test);
startAppService(TransportFactory.TransportType.LOOPBACK);
} else if (requestPermissions()) {
@ -227,6 +272,7 @@ public class MainActivity extends AppCompatActivity {
);
protected void startUsbConnectActivity() {
_isConnecting = true;
_usbActivityLauncher.launch(new Intent(this, UsbConnectActivity.class));
}
@ -252,6 +298,7 @@ public class MainActivity extends AppCompatActivity {
);
protected void startBluetoothConnectActivity() {
_isConnecting = true;
Intent bluetoothConnectIntent;
if (_isBleEnabled) {
bluetoothConnectIntent = new Intent(this, BleConnectActivity.class);
@ -279,6 +326,7 @@ public class MainActivity extends AppCompatActivity {
);
protected void startTcpIpConnectActivity() {
_isConnecting = true;
_tcpipActivityLauncher.launch(new Intent(this, TcpIpConnectActivity.class));
}
@ -357,6 +405,7 @@ public class MainActivity extends AppCompatActivity {
startForegroundService(serviceIntent);
else
startService(serviceIntent);
bindAppService();
}
@ -585,6 +634,8 @@ public class MainActivity extends AppCompatActivity {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.i(TAG, "Connected to app service");
_appService = ((AppService.AppServiceBinder)service).getService();
if (AppService.isRunning)
_textConnInfo.setText(_appService.getTransportName());
}
@Override
@ -599,21 +650,26 @@ public class MainActivity extends AppCompatActivity {
public void handleMessage(Message msg) {
switch (AppMessage.values()[msg.what]) {
case EV_CONNECTED:
_isConnecting = false;
_btnPtt.setEnabled(true);
Toast.makeText(getBaseContext(), R.string.processor_connected, Toast.LENGTH_SHORT).show();
break;
case EV_DISCONNECTED:
_btnPtt.setText(R.string.main_status_stop);
unbindAppService();
stopAppService();
// finish and start ourselves on app exit
_btnPtt.setEnabled(false);
// app restart, stop app service and restart ourselves
if (_isAppRestart) {
unbindAppService();
stopAppService();
finish();
startActivity(getIntent());
// finish ourselves on app exist
// app exit, stop app service and finish
} else if (_isAppExit) {
unbindAppService();
stopAppService();
finish();
// otherwise just restart app service with reconnect
} else {
// otherwise just reconnect if app is not on pause
} else if (!_isPaused) {
Toast.makeText(getBaseContext(), R.string.processor_disconnected, Toast.LENGTH_SHORT).show();
startTransportConnection();
}

Wyświetl plik

@ -37,9 +37,13 @@ import java.io.IOException;
public class AppService extends Service {
public static TransportFactory.TransportType transportType;
public static boolean isRunning = false;
private static final String TAG = AppService.class.getSimpleName();
private final int NOTIFICATION_ID = 1;
private final int BASE_NOTIFICATION_ID = 1;
private final int RX_NOTIFICATION_ID = 2;
private AppWorker _appWorker;
private Messenger _callbackMessenger;
@ -54,6 +58,8 @@ public class AppService extends Service {
}
}
public String getTransportName() { return _appWorker.getTransportName(); }
public void startTransmit() {
_appWorker.startTransmit();
}
@ -67,12 +73,12 @@ public class AppService extends Service {
}
public void startTracking() {
showNotification(R.string.app_service_notif_text_tracking);
showNotification(R.string.app_service_notif_text_tracking, R.drawable.ic_app_action);
_tracker.startTracking();
}
public void stopTracking() {
showNotification(R.string.app_service_notif_text_ptt_ready);
showNotification(R.string.app_service_notif_text_ptt_ready, R.drawable.ic_app_action);
_tracker.stopTracking();
}
@ -108,14 +114,16 @@ public class AppService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Staring app service");
Log.i(TAG, "onStartCommand()");
// update callback from new intent
Bundle extras = intent.getExtras();
_callbackMessenger = (Messenger) extras.get("callback");
// create if not running
if (_appWorker == null) {
if (isRunning) {
Log.i(TAG, "Not starting app service, already running");
} else {
_notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert _notificationManager != null;
SharedPreferences _sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
@ -124,15 +132,15 @@ public class AppService extends Service {
_tracker = TrackerFactory.create(trackerName);
_tracker.initialize(getApplicationContext(), position -> _appWorker.sendPosition(position));
TransportFactory.TransportType transportType = (TransportFactory.TransportType) extras.get("transportType");
transportType = (TransportFactory.TransportType) extras.get("transportType");
startAppWorker(transportType);
Notification notification = buildNotification(getString(R.string.app_service_notif_text_ptt_ready));
startForeground(NOTIFICATION_ID, notification);
Notification notification = buildNotification(getString(R.string.app_service_notif_text_ptt_ready), R.drawable.ic_app_action);
startForeground(BASE_NOTIFICATION_ID, notification);
isRunning = true;
Log.i(TAG, "App service started");
} else {
Log.i(TAG, "App service is already running");
}
return START_REDELIVER_INTENT;
@ -171,6 +179,8 @@ public class AppService extends Service {
switch (AppMessage.values()[msg.what]) {
case EV_DISCONNECTED:
_appWorker = null;
isRunning = false;
showNotification(R.string.app_service_notif_connection_lost, R.drawable.ic_app_action_disconnected);
break;
default:
break;
@ -181,15 +191,13 @@ public class AppService extends Service {
}
};
private void showNotification(int resId) {
private void showNotification(int resId, int iconResId) {
String text = getString(resId);
_notificationManager.notify(NOTIFICATION_ID, buildNotification(text));
_notificationManager.notify(BASE_NOTIFICATION_ID, buildNotification(text, iconResId));
}
@RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel() {
String channelId = "alpha";
String channelName = "Service";
private String createNotificationChannel(String channelId, String channelName) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
channel.setImportance(NotificationManager.IMPORTANCE_LOW);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
@ -197,22 +205,19 @@ public class AppService extends Service {
return channelId;
}
private Notification buildNotification(String text) {
private Notification buildNotification(String text, int iconResId) {
String channelId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
channelId = createNotificationChannel();
channelId = createNotificationChannel("alpha", "Service");
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(getApplicationContext(), 0,
notificationIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
this, channelId);
return notificationBuilder
return new NotificationCompat.Builder(this, channelId)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_app_action)
.setSmallIcon(iconResId)
.setContentTitle(getString(R.string.app_service_notif_title))
.setContentText(text)
.setPriority(NotificationManagerCompat.IMPORTANCE_LOW)
@ -222,4 +227,24 @@ public class AppService extends Service {
.setOnlyAlertOnce(true)
.build();
}
private Notification buildFullScreenNotification(String text) {
String channelId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
channelId = createNotificationChannel("beta", "VoiceRx");
Intent fullScreenIntent = new Intent(this, MainActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_app_action)
.setContentTitle("Incoming transmission")
.setContentText(text)
.setChannelId(channelId)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(fullScreenPendingIntent, true)
.build();
}
}

Wyświetl plik

@ -145,6 +145,10 @@ public class AppWorker extends Thread {
return AUDIO_MAX_LEVEL;
}
public String getTransportName() {
return _transport.name();
}
public void startReceive() {
_needsRecording = false;
}
@ -295,9 +299,7 @@ public class AppWorker extends Thread {
logItem.setSrcCallsign(callsignData[0]);
logItem.setLogLine(logData);
logItem.setIsTransmit(isTransmit);
Log.i(TAG, "Insert:" + logItem);
_logItemRepository.insertLogItem(logItem);
//LogItemDatabase.getDatabase(_context).logItemDao().insertLogItem(logItem);
}
}

Wyświetl plik

@ -217,6 +217,7 @@ public class BleConnectActivity extends AppCompatActivity {
} else {
toastMsg = getString(R.string.bt_le_services_discovered);
BleHandler.setGatt(_btGatt);
BleHandler.setName(_btSelectedName);
Intent resultIntent = new Intent();
resultIntent.putExtra("name", _btSelectedName);
setResult(Activity.RESULT_OK, resultIntent);

Wyświetl plik

@ -2,12 +2,19 @@ package com.radio.codec2talkie.connect;
public class BleHandler {
private static BleGattWrapper bleGatt;
private static String name;
public static synchronized BleGattWrapper getGatt(){
return bleGatt;
}
public static synchronized String getName(){
return name;
}
public static synchronized void setGatt(BleGattWrapper gatt){
BleHandler.bleGatt = gatt;
}
public static synchronized void setName(String name){
BleHandler.name = name;
}
}

Wyświetl plik

@ -202,6 +202,7 @@ public class BluetoothConnectActivity extends AppCompatActivity {
} else {
toastMsg = getString(R.string.bt_connected);
BluetoothSocketHandler.setSocket(_btSocket);
BluetoothSocketHandler.setName(_btSelectedName);
Intent resultIntent = new Intent();
resultIntent.putExtra("name", _btSelectedName);
setResult(Activity.RESULT_OK, resultIntent);

Wyświetl plik

@ -4,12 +4,19 @@ import android.bluetooth.BluetoothSocket;
public class BluetoothSocketHandler {
private static BluetoothSocket socket;
private static String name;
public static synchronized BluetoothSocket getSocket(){
return socket;
}
public static synchronized String getName(){
return name;
}
public static synchronized void setSocket(BluetoothSocket socket){
BluetoothSocketHandler.socket = socket;
}
public static synchronized void setName(String name){
BluetoothSocketHandler.name = name;
}
}

Wyświetl plik

@ -109,6 +109,7 @@ public class TcpIpConnectActivity extends AppCompatActivity {
}
if (_socket.isConnected()) {
TcpIpSocketHandler.setSocket(_socket);
TcpIpSocketHandler.setName(String.format("%s:%s", _address, _port));
resultMsg.what = TCP_IP_CONNECTED;
} else {
resultMsg.what = TCP_IP_FAILED;

Wyświetl plik

@ -4,12 +4,17 @@ import java.net.Socket;
public class TcpIpSocketHandler {
private static Socket socket;
private static String name;
public static synchronized Socket getSocket(){
return socket;
}
public static synchronized String getName() { return name; }
public static synchronized void setSocket(Socket socket){
TcpIpSocketHandler.socket = socket;
}
public static synchronized void setName(String name){
TcpIpSocketHandler.name = name;
}
}

Wyświetl plik

@ -151,6 +151,7 @@ public class UsbConnectActivity extends AppCompatActivity {
String toastMsg;
if (msg.what == USB_CONNECTED) {
UsbPortHandler.setPort(_usbPort);
UsbPortHandler.setName(_usbDeviceName);
toastMsg = String.format("USB connected %s", _usbDeviceName);
Toast.makeText(getBaseContext(), toastMsg, Toast.LENGTH_SHORT).show();

Wyświetl plik

@ -4,12 +4,19 @@ import com.hoho.android.usbserial.driver.UsbSerialPort;
public class UsbPortHandler {
private static UsbSerialPort port;
private static String name;
public static synchronized UsbSerialPort getPort(){
return port;
}
public static synchronized String getName(){
return name;
}
public static synchronized void setPort(UsbSerialPort port){
UsbPortHandler.port = port;
}
public static synchronized void setName(String name){
UsbPortHandler.name = name;
}
}

Wyświetl plik

@ -6,9 +6,16 @@ import java.io.IOException;
public class Ble implements Transport {
private final BleGattWrapper _gattWrapper;
private final String _name;
public Ble(BleGattWrapper gattWrapper) {
public Ble(BleGattWrapper gattWrapper, String name) {
_gattWrapper = gattWrapper;
_name = name;
}
@Override
public String name() {
return _name;
}
@Override

Wyświetl plik

@ -11,11 +11,18 @@ public class Bluetooth implements Transport {
private final BluetoothSocket _btSocket;
private final OutputStream _btOutputStream;
private final InputStream _btInputStream;
private final String _name;
public Bluetooth(BluetoothSocket btSocket) throws IOException {
public Bluetooth(BluetoothSocket btSocket, String name) throws IOException {
_btSocket = btSocket;
_btInputStream = btSocket.getInputStream();
_btOutputStream = btSocket.getOutputStream();
_name = name;
}
@Override
public String name() {
return _name;
}
@Override

Wyświetl plik

@ -18,6 +18,11 @@ public class Loopback implements Transport {
_isReading = true;
}
@Override
public String name() {
return "ECHO TEST";
}
@Override
public int read(byte[] data) {
if (!_isReading) {

Wyświetl plik

@ -13,15 +13,22 @@ public class TcpIp implements Transport {
private final int RX_TIMEOUT = 10;
private final Socket _socket;
private final String _name;
private final InputStream _inputStream;
private final OutputStream _outputStream;
public TcpIp(Socket socket) throws IOException {
public TcpIp(Socket socket, String name) throws IOException {
_socket = socket;
_socket.setSoTimeout(RX_TIMEOUT);
_inputStream = _socket.getInputStream();
_outputStream = _socket.getOutputStream();
_name = name;
}
@Override
public String name() {
return _name;
}
@Override

Wyświetl plik

@ -3,6 +3,7 @@ package com.radio.codec2talkie.transport;
import java.io.IOException;
public interface Transport {
String name();
int read(byte[] data) throws IOException;
int write(byte[] data) throws IOException;
void close() throws IOException;

Wyświetl plik

@ -20,13 +20,13 @@ public class TransportFactory {
public static Transport create(TransportType transportType) throws IOException {
switch (transportType) {
case USB:
return new UsbSerial(UsbPortHandler.getPort());
return new UsbSerial(UsbPortHandler.getPort(), UsbPortHandler.getName());
case BLUETOOTH:
return new Bluetooth(BluetoothSocketHandler.getSocket());
return new Bluetooth(BluetoothSocketHandler.getSocket(), BluetoothSocketHandler.getName());
case TCP_IP:
return new TcpIp(TcpIpSocketHandler.getSocket());
return new TcpIp(TcpIpSocketHandler.getSocket(), TcpIpSocketHandler.getName());
case BLE:
return new Ble(BleHandler.getGatt());
return new Ble(BleHandler.getGatt(), BleHandler.getName());
case LOOPBACK:
default:
return new Loopback();

Wyświetl plik

@ -13,9 +13,16 @@ public class UsbSerial implements Transport {
private final int TX_TIMEOUT = 2000;
private final UsbSerialPort _usbPort;
private final String _name;
public UsbSerial(UsbSerialPort usbPort) {
public UsbSerial(UsbSerialPort usbPort, String name) {
_usbPort = usbPort;
_name = name;
}
@Override
public String name() {
return _name;
}
@Override

Wyświetl plik

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M15,3L6,3c-0.83,0 -1.54,0.5 -1.84,1.22l-3.02,7.05c-0.09,0.23 -0.14,0.47 -0.14,0.73v2c0,1.1 0.9,2 2,2h6.31l-0.95,4.57 -0.03,0.32c0,0.41 0.17,0.79 0.44,1.06L9.83,23l6.59,-6.59c0.36,-0.36 0.58,-0.86 0.58,-1.41L17,5c0,-1.1 -0.9,-2 -2,-2zM19,3v12h4L23,3h-4z"/>
</vector>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 354 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 263 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 490 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 761 B

Wyświetl plik

@ -12,7 +12,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:text="Device"
android:text=""
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="2dp"
android:text="Mode"
android:text=""
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"

Wyświetl plik

@ -245,9 +245,10 @@
<string name="aprs_location_source_smart_min_turn_angle_summary">Minimum angle at high speed</string>
<string name="aprs_location_source_smart_turn_slope_title">Turn slope</string>
<string name="aprs_location_source_smart_min_turn_slope_summary">Influence of speed on the minimum angle</string>
<string name="app_service_notif_title">Radio is running, touch to open</string>
<string name="app_service_notif_text_ptt_ready">Receiving and ready for PTT</string>
<string name="app_service_notif_title">Running, touch to open</string>
<string name="app_service_notif_text_ptt_ready">Connected to the TNC, ready for PTT</string>
<string name="app_service_notif_text_tracking">APRS tracking is active</string>
<string name="app_service_notif_connection_lost">Disconnected from the TNC, click to reconnect</string>
<string name="aprs_log_view_title">APRS raw log</string>
<string name="log_view_menu_clear">Clear log</string>
</resources>