diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2023-08-14 22:51:16 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2023-08-14 22:51:16 +0300 |
commit | b200abb7e3318683881ef955c0cfe095bf5a9798 (patch) | |
tree | 4a9ea1120ff3ccaa79fdcaddae2f2332d215e3d4 | |
parent | aa8aa784f89929cd615771bc3f61307fc3631c4a (diff) |
Autostart (issues #4 and #6)
7 files changed, 168 insertions, 55 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index facc8b0..90ea25d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-feature android:name="android.hardware.usb.host" /> @@ -15,11 +16,24 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.USBSerialTelnetServer"> + <receiver + android:name=".ConnectedReceiver" + android:enabled="true" + android:exported="true"> + <intent-filter> + <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> + </intent-filter> + + <meta-data + android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" + android:resource="@xml/usb_device_filter" /> + </receiver> <service android:name=".UsbSerialTelnetService" android:enabled="true" - android:exported="true" /> + android:exported="true" + android:foregroundServiceType="connectedDevice" /> <activity android:name=".MainActivity" @@ -27,6 +41,7 @@ android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> @@ -38,7 +53,9 @@ android:resource="@xml/usb_device_filter" /> </activity> - <receiver android:name=".BootCompletedReceiver" android:exported="true"> + <receiver + android:name=".BootCompletedReceiver" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> diff --git a/app/src/main/java/com/clusterrr/usbserialtelnetserver/BootCompletedReceiver.java b/app/src/main/java/com/clusterrr/usbserialtelnetserver/BootCompletedReceiver.java index 3a80fba..23cda8b 100644 --- a/app/src/main/java/com/clusterrr/usbserialtelnetserver/BootCompletedReceiver.java +++ b/app/src/main/java/com/clusterrr/usbserialtelnetserver/BootCompletedReceiver.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; +import android.util.Log; import com.hoho.android.usbserial.driver.UsbSerialPort; @@ -12,11 +13,13 @@ public class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - // App was started before shutdown SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(context.getString(R.string.app_name), Context.MODE_PRIVATE); - boolean needToStart = prefs.getBoolean(UsbSerialTelnetService.KEY_LAST_STATE, false); - if (needToStart) { + if ((prefs.getInt(MainActivity.SETTING_AUTOSTART, MainActivity.AUTOSTART_DISABLED) != MainActivity.AUTOSTART_DISABLED) + && MainActivity.isDevicePresent(context)) + { Intent mainActivityStartIntent = new Intent(context, MainActivity.class); + mainActivityStartIntent.setAction(intent.getAction()); + mainActivityStartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(mainActivityStartIntent); } } diff --git a/app/src/main/java/com/clusterrr/usbserialtelnetserver/ConnectedReceiver.java b/app/src/main/java/com/clusterrr/usbserialtelnetserver/ConnectedReceiver.java new file mode 100644 index 0000000..e75c038 --- /dev/null +++ b/app/src/main/java/com/clusterrr/usbserialtelnetserver/ConnectedReceiver.java @@ -0,0 +1,26 @@ +package com.clusterrr.usbserialtelnetserver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +public class ConnectedReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(UsbSerialTelnetService.TAG, "Connected device detected"); + SharedPreferences prefs = context.getApplicationContext().getSharedPreferences(context.getString(R.string.app_name), Context.MODE_PRIVATE); + if (prefs.getInt(MainActivity.SETTING_AUTOSTART, MainActivity.AUTOSTART_DISABLED) != MainActivity.AUTOSTART_DISABLED) + { + Intent mainActivityStartIntent = new Intent(context, MainActivity.class); + mainActivityStartIntent.setAction(intent.getAction()); + mainActivityStartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(mainActivityStartIntent); + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/clusterrr/usbserialtelnetserver/MainActivity.java b/app/src/main/java/com/clusterrr/usbserialtelnetserver/MainActivity.java index 6d539ee..2776a64 100644 --- a/app/src/main/java/com/clusterrr/usbserialtelnetserver/MainActivity.java +++ b/app/src/main/java/com/clusterrr/usbserialtelnetserver/MainActivity.java @@ -21,6 +21,7 @@ import android.os.PowerManager; import android.provider.Settings; import android.util.Log; import android.view.View; +import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; @@ -33,7 +34,7 @@ import com.hoho.android.usbserial.driver.UsbSerialProber; import java.util.List; -public class MainActivity extends AppCompatActivity implements View.OnClickListener, UsbSerialTelnetService.IOnStopListener { +public class MainActivity extends AppCompatActivity implements View.OnClickListener, UsbSerialTelnetService.IOnStartStopListener, AdapterView.OnItemSelectedListener { final static String SETTING_TCP_PORT = "tcp_port"; final static String SETTING_BAUD_RATE = "baud_rate"; final static String SETTING_DATA_BITS = "data_bits"; @@ -41,9 +42,15 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe final static String SETTING_PARITY = "parity"; final static String SETTING_NO_LOCAL_ECHO = "no_local_echo"; final static String SETTING_REMOVE_LF = "remove_lf"; + final static String SETTING_AUTOSTART = "autostart"; + + final static int AUTOSTART_DISABLED = 0; + final static int AUTOSTART_ENABLED = 1; + final static int AUTOSTART_CLOSE = 2; private UsbSerialTelnetService.ServiceBinder mServiceBinder = null; - private Handler mHandler; + private Handler mHandler = new Handler(); + private boolean mNeedClose = false; private Button mStartButton; private Button mStopButton; private EditText mTcpPort; @@ -54,18 +61,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private TextView mStatus; private Switch mNoLocalEcho; private Switch mRemoveLF; + private Spinner mAutostart; - private boolean isStarted() { + public boolean isStarted() { return mServiceBinder != null && mServiceBinder.isStarted(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Log.d(UsbSerialTelnetService.TAG, "Creating activity"); setContentView(R.layout.activity_main); - mHandler = new Handler(); - mStartButton = findViewById(R.id.buttonStart); mStopButton = findViewById(R.id.buttonStop); mTcpPort = findViewById(R.id.editTextTcpPort); @@ -76,44 +83,53 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe mStatus = findViewById(R.id.textViewStatus); mNoLocalEcho = findViewById(R.id.switchNoLocalEcho); mRemoveLF = findViewById(R.id.switchRemoveLf); + mAutostart = findViewById(R.id.spinnerAutostart); + mAutostart.setOnItemSelectedListener(this); mStartButton.setOnClickListener(this); mStopButton.setOnClickListener(this); Intent serviceIntent = new Intent(this, UsbSerialTelnetService.class); - bindService(serviceIntent, serviceConnection, 0); // in case if service already started + bindService(serviceIntent, mServiceConnection, 0); // in case if service already started updateSettings(); + } + @Override + protected void onNewIntent(Intent intent) { + // Start service if need + super.onNewIntent(intent); + if (intent == null) return; SharedPreferences prefs = getApplicationContext().getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); - boolean needToStart = prefs.getBoolean(UsbSerialTelnetService.KEY_LAST_STATE, false); - if (needToStart) { - mHandler.postDelayed(() -> { - boolean started = mServiceBinder != null && mServiceBinder.isStarted(); - if (!started) { + String action = intent.getAction(); + Log.d(UsbSerialTelnetService.TAG, "Received intent: " + action); + switch(action) + { + case UsbSerialTelnetService.ACTION_NEED_TO_START: + if (mServiceBinder == null || !mServiceBinder.isStarted()) + start(); + break; + case Intent.ACTION_BOOT_COMPLETED: + case UsbManager.ACTION_USB_DEVICE_ATTACHED: + if (!isStarted() && prefs.getInt(SETTING_AUTOSTART, AUTOSTART_DISABLED) != AUTOSTART_DISABLED) + { + mNeedClose = prefs.getInt(SETTING_AUTOSTART, AUTOSTART_DISABLED) == AUTOSTART_CLOSE; start(); } - }, 5000); + break; } } - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - if (intent != null) { - // Start service if need - if ((intent.getAction() == UsbSerialTelnetService.ACTION_NEED_TO_START) && - (!(mServiceBinder != null && mServiceBinder.isStarted()))) { - // Test that permission is granted - UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); - List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); - if (!availableDrivers.isEmpty()) { - UsbSerialDriver driver = availableDrivers.get(0); - UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); - if (connection != null) start(); - } - } + public static boolean isDevicePresent(Context context) + { + UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE); + List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); + if (!availableDrivers.isEmpty()) { + UsbSerialDriver driver = availableDrivers.get(0); + UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); + return connection != null; } + return false; } @Override @@ -128,6 +144,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe switch(view.getId()) { case R.id.buttonStart: + mNeedClose = false; start(); break; case R.id.buttonStop: @@ -136,6 +153,20 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } } + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + if (parent.getId() != R.id.spinnerAutostart) return; + SharedPreferences prefs = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); + prefs.edit() + .putInt(SETTING_AUTOSTART, position) + .commit(); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + // Unused + } + private void start() { saveSettings(); @@ -144,7 +175,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe if (ignoreOptimization != null) startActivity(ignoreOptimization); Intent serviceIntent = new Intent(this, UsbSerialTelnetService.class); - SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); + SharedPreferences prefs = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); serviceIntent.putExtra(UsbSerialTelnetService.KEY_TCP_PORT, prefs.getInt(SETTING_TCP_PORT, 2323)); serviceIntent.putExtra(UsbSerialTelnetService.KEY_BAUD_RATE, prefs.getInt(SETTING_BAUD_RATE, 115200)); serviceIntent.putExtra(UsbSerialTelnetService.KEY_DATA_BITS, prefs.getInt(SETTING_DATA_BITS, 3) + 5); @@ -167,15 +198,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } else { startService(serviceIntent); } - bindService(serviceIntent, serviceConnection, 0); - - // Save last state - mHandler.postDelayed(() -> { - boolean started = mServiceBinder != null && mServiceBinder.isStarted(); - SharedPreferences prefsShared = getApplicationContext().getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); - prefsShared.edit().putBoolean(UsbSerialTelnetService.KEY_LAST_STATE, started).commit(); - Log.d(UsbSerialTelnetService.TAG, "Last state saved: " + started); - }, 500); + bindService(serviceIntent, mServiceConnection, 0); } private void stop() { @@ -187,16 +210,23 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe updateSettings(); } - private ServiceConnection serviceConnection = new ServiceConnection() { + private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { mServiceBinder = (UsbSerialTelnetService.ServiceBinder) service; - mServiceBinder.setOnStopListener(MainActivity.this); + mServiceBinder.setOnStartStopListener(MainActivity.this); updateSettings(); SharedPreferences prefs = getApplicationContext().getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); prefs.edit().putBoolean(UsbSerialTelnetService.KEY_LAST_STATE, isStarted()).commit(); Log.d(UsbSerialTelnetService.TAG, "Service connected"); + // Close if autoclose enabled + if (isStarted() && mNeedClose) { + // Delay to prevent race condition + mHandler.postDelayed(() -> { + if (mNeedClose) finish(); + }, 1000); + } } @Override @@ -207,11 +237,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe }; @Override + public void usbSerialServiceStarted() { + } + + @Override public void usbSerialServiceStopped() { updateSettings(); } + private void saveSettings() { - SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); + SharedPreferences prefs = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); int tcpPort; try { tcpPort = Integer.parseInt(mTcpPort.getText().toString()); @@ -238,8 +273,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } private void updateSettings() { - SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); - boolean started = mServiceBinder != null && mServiceBinder.isStarted(); + SharedPreferences prefs = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); + boolean started = isStarted(); mStartButton.setEnabled(!started); mStopButton.setEnabled(started); mTcpPort.setEnabled(!started); @@ -256,6 +291,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe mParity.setSelection(prefs.getInt(SETTING_PARITY, 0)); mNoLocalEcho.setChecked(prefs.getBoolean(SETTING_NO_LOCAL_ECHO, true)); mRemoveLF.setChecked(prefs.getBoolean(SETTING_REMOVE_LF, true)); + mAutostart.setSelection(prefs.getInt(SETTING_AUTOSTART, AUTOSTART_DISABLED)); if (started) mStatus.setText(getString(R.string.started_please_connect) + " telnet://" + UsbSerialTelnetService.getIPAddress() + ":"+ mTcpPort.getText()); else diff --git a/app/src/main/java/com/clusterrr/usbserialtelnetserver/UsbSerialTelnetService.java b/app/src/main/java/com/clusterrr/usbserialtelnetserver/UsbSerialTelnetService.java index b90d445..3c53739 100644 --- a/app/src/main/java/com/clusterrr/usbserialtelnetserver/UsbSerialTelnetService.java +++ b/app/src/main/java/com/clusterrr/usbserialtelnetserver/UsbSerialTelnetService.java @@ -7,7 +7,6 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.graphics.BitmapFactory; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; @@ -65,7 +64,7 @@ public class UsbSerialTelnetService extends Service { { if (mStarted) { // Already started - new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(UsbSerialTelnetService.this.getApplicationContext(), getString(R.string.already_started), Toast.LENGTH_LONG).show()); + //new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(UsbSerialTelnetService.this.getApplicationContext(), getString(R.string.already_started), Toast.LENGTH_LONG).show()); return START_STICKY; } @@ -86,10 +85,11 @@ public class UsbSerialTelnetService extends Service { .setSmallIcon(R.drawable.ic_notification) .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) .setContentTitle(message) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(Notification.CATEGORY_SERVICE) .setShowWhen(false) .setContentIntent(mainActivityPendingIntent) + .setSound(null) .build(); startForeground(1, notification); @@ -145,12 +145,14 @@ public class UsbSerialTelnetService extends Service { if (message != null) Log.i(TAG, message); mStarted = true; + mBinder.started(); } else { if (message != null) Log.e(TAG, message); stopSelf(); mStarted = false; } + return START_STICKY; } @@ -201,16 +203,18 @@ public class UsbSerialTelnetService extends Service { private final ServiceBinder mBinder = new ServiceBinder(); public class ServiceBinder extends Binder { - private IOnStopListener onStopListener = null; + private IOnStartStopListener onStartStopListener = null; public boolean isStarted() { return mStarted; } - public void setOnStopListener(IOnStopListener listener) { onStopListener = listener; } - public void stopped() { if (onStopListener != null) onStopListener.usbSerialServiceStopped(); } + public void setOnStartStopListener(IOnStartStopListener listener) { onStartStopListener = listener; } + public void started() { if (onStartStopListener != null) onStartStopListener.usbSerialServiceStarted(); } + public void stopped() { if (onStartStopListener != null) onStartStopListener.usbSerialServiceStopped(); } } - public interface IOnStopListener + public interface IOnStartStopListener { + public void usbSerialServiceStarted(); public void usbSerialServiceStopped(); } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 467c010..e074ce3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -209,6 +209,27 @@ app:layout_constraintStart_toEndOf="@+id/textRemoveLf" app:layout_constraintTop_toBottomOf="@+id/switchNoLocalEcho" /> + <TextView + android:id="@+id/textAutostart" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:text="@string/autostart_on_device_connect" + app:layout_constraintBottom_toBottomOf="@+id/spinnerAutostart" + app:layout_constraintEnd_toStartOf="@+id/spinnerAutostart" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/spinnerAutostart" /> + + <Spinner + android:id="@+id/spinnerAutostart" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_marginEnd="24dp" + android:entries="@array/autostart" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/textAutostart" + app:layout_constraintTop_toBottomOf="@+id/switchRemoveLf" /> + </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc4d268..4269713 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,6 +16,7 @@ <string name="already_started">Already started</string> <string name="no_local_echo">Forced local echo off</string> <string name="remove_lf">Convert client\'s CR-LF to CR</string> + <string name="autostart_on_device_connect">Autostart on device attach</string> <string-array name="data_bits"> <item>5</item> <item>6</item> @@ -35,4 +36,9 @@ <item>Mark</item> <item>Space</item> </string-array> + <string-array name="autostart"> + <item>Disabled</item> + <item>Enabled</item> + <item>+Autoclose</item> + </string-array> </resources>
\ No newline at end of file |