diff --git a/app/build.gradle b/app/build.gradle index 1712de1..301e1d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7' implementation 'androidx.navigation:navigation-ui-ktx:2.7.7' - implementation 'com.budiyev.android:code-scanner:2.1.0' + implementation 'com.github.yuriy-budiyev:code-scanner:2.1.0' implementation 'com.karumi:dexter:6.2.2' implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'com.madgag.spongycastle:bcpkix-jdk15on:1.58.0.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e618687..f61bab1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,9 +14,16 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/meshcentral/agent/BootReceiver.kt b/app/src/main/java/com/meshcentral/agent/BootReceiver.kt new file mode 100644 index 0000000..807c2fc --- /dev/null +++ b/app/src/main/java/com/meshcentral/agent/BootReceiver.kt @@ -0,0 +1,22 @@ +package com.meshcentral.agent + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.os.Build +import androidx.preference.PreferenceManager + +class BootReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent?) { + if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { + val serviceIntent = Intent(context, BootService::class.java) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(serviceIntent) + } else { + context.startService(serviceIntent) + } + } + } +} diff --git a/app/src/main/java/com/meshcentral/agent/BootService.kt b/app/src/main/java/com/meshcentral/agent/BootService.kt new file mode 100644 index 0000000..684b13c --- /dev/null +++ b/app/src/main/java/com/meshcentral/agent/BootService.kt @@ -0,0 +1,89 @@ +package com.meshcentral.agent + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Intent +import android.content.SharedPreferences +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import androidx.preference.PreferenceManager + +class BootService : Service() { + private val CHANNEL_ID = "BootServiceChannel" + + override fun onCreate() { + super.onCreate() + createNotificationChannel() + + val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle(getString(R.string.starting_meshcentral_bootservice)) + .setContentText("") + .setSmallIcon(android.R.drawable.ic_dialog_info) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + startForeground(1, notification) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + performStartupTasks() + + return START_STICKY + } + + override fun onDestroy() { + super.onDestroy() + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Boot Service Channel", + NotificationManager.IMPORTANCE_HIGH + ).apply { + description = "Notification channel for BootService" + } + + val manager = getSystemService(NotificationManager::class.java) + manager?.createNotificationChannel(channel) + } + } + + private fun performStartupTasks() { + val pm: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + g_autoStart = pm.getBoolean("pref_autostart", false) + if (g_autoStart == true) { + Thread { + try { + Thread.sleep(5000) + val launchIntent = Intent(this, MainActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val pendingIntent = PendingIntent.getActivity( + this, + 0, + launchIntent, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + pendingIntent.send() + } else { + startActivity(launchIntent) + } + + } catch (e: Exception) { + } + }.start() + } + } +} diff --git a/app/src/main/java/com/meshcentral/agent/MainActivity.kt b/app/src/main/java/com/meshcentral/agent/MainActivity.kt index aca1448..1951a8a 100644 --- a/app/src/main/java/com/meshcentral/agent/MainActivity.kt +++ b/app/src/main/java/com/meshcentral/agent/MainActivity.kt @@ -20,6 +20,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.os.CountDownTimer +import android.os.PowerManager import android.provider.Settings import android.text.InputType import android.util.Base64 @@ -61,6 +62,7 @@ import kotlin.math.absoluteValue val hardCodedServerLink : String? = null //val hardCodedServerLink : String? = "mc://central.mesh.meshcentral.com,2ZNi1e2Lrqi\$nnQ7NLJCJWNwxGD9ZstiNzxs\$LIE1tcHQD45bPDvbcKzpC9zUTX9,7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c" + // User interface values var g_mainActivity : MainActivity? = null var mainFragment : MainFragment? = null @@ -79,6 +81,7 @@ var pageUrl : String? = null var cameraPresent : Boolean = false var pendingActivities : ArrayList = ArrayList() var pushMessagingToken : String? = null +var g_autoStart : Boolean = false var g_autoConnect : Boolean = true var g_autoConsent : Boolean = false var g_userDisconnect : Boolean = false // Indicate user initiated disconnection @@ -491,6 +494,34 @@ class MainActivity : AppCompatActivity() { if (permissions.isNotEmpty()) { ActivityCompat.requestPermissions(this, permissions.toTypedArray(), REQUEST_ALL_PERMISSIONS) } + + if (!Settings.canDrawOverlays(this)) { + val intent = Intent( + Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:$packageName") + ) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) + } + + // Check and add ignore battery optimization permissions if necessary + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager + if (!powerManager.isIgnoringBatteryOptimizations(packageName)) { + val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { + data = Uri.parse("package:$packageName") + } + startActivity(intent) + } + } + + // Check and add post notifications permissions if necessary + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1) + } + } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { @@ -680,6 +711,7 @@ class MainActivity : AppCompatActivity() { fun settingsChanged() { this.runOnUiThread { val pm: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + g_autoStart = pm.getBoolean("pref_autostart", false) g_autoConnect = pm.getBoolean("pref_autoconnect", false) g_autoConsent = pm.getBoolean("pref_autoconsent", false) g_userDisconnect = false diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index dfcf188..b6c1ad7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -58,4 +58,9 @@ Immer Zustimmung für Verbindung anfordern Verbinden mit: %1$s? Server-Setup löschen? + Server Pairing Link ungültig + Autostart + Manuell starten + Mit System starten + Starte MeshCentral BootService... \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e4a6ccd..018ba78 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,6 +61,10 @@ Always ask for consent when remote agent connects Setup to: %1$s? Clear server setup? - Server Pairing Link - Invalid Server Pairing Linbk + Server Pairing Link + Invalid Server Pairing Link + Autostart + Start manually + Start with system + Starting MeshCentral BootService... \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 50f85ef..29a4e10 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -3,6 +3,13 @@ +