Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
21 changes: 21 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_BOOT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application
android:allowBackup="true"
Expand Down Expand Up @@ -52,6 +59,20 @@
</intent-filter>
</activity>

<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

<service
android:name=".BootService"
android:foregroundServiceType="location|mediaProjection"
android:exported="false" />
<service
android:name=".MeshFirebaseMessagingService"
android:exported="false">
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/com/meshcentral/agent/BootReceiver.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
}
89 changes: 89 additions & 0 deletions app/src/main/java/com/meshcentral/agent/BootService.kt
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
32 changes: 32 additions & 0 deletions app/src/main/java/com/meshcentral/agent/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -79,6 +81,7 @@ var pageUrl : String? = null
var cameraPresent : Boolean = false
var pendingActivities : ArrayList<PendingActivityData> = ArrayList<PendingActivityData>()
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
Expand Down Expand Up @@ -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<out String>, grantResults: IntArray) {
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@
<string name="always_ask_for_consent_when_remote_agent_connects">Immer Zustimmung für Verbindung anfordern</string>
<string name="setup_message">Verbinden mit: %1$s?</string>
<string name="clear_server_setup">Server-Setup löschen?</string>
<string name="invalid_server_pairing_link">Server Pairing Link ungültig</string>
<string name="autostart">Autostart</string>
<string name="start_manually">Manuell starten</string>
<string name="start_with_system">Mit System starten</string>
<string name="starting_meshcentral_bootservice">Starte MeshCentral BootService...</string>
</resources>
8 changes: 6 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
<string name="always_ask_for_consent_when_remote_agent_connects">Always ask for consent when remote agent connects</string>
<string name="setup_message">Setup to: %1$s?</string>
<string name="clear_server_setup">Clear server setup?</string>
<string name="server_pairing_link">Server Pairing Link</string>
<string name="invalid_server_pairing_link">Invalid Server Pairing Linbk</string>
<string name="server_pairing_link" translatable="false">Server Pairing Link</string>
<string name="invalid_server_pairing_link">Invalid Server Pairing Link</string>
<string name="autostart">Autostart</string>
<string name="start_manually">Start manually</string>
<string name="start_with_system">Start with system</string>
<string name="starting_meshcentral_bootservice">Starting MeshCentral BootService...</string>
</resources>
7 changes: 7 additions & 0 deletions app/src/main/res/xml/root_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
<PreferenceCategory
app:title="@string/settings"
app:icon="@drawable/ic_baseline_settings_24">
<SwitchPreferenceCompat
app:key="pref_autostart"
app:title="@string/autostart"
app:summaryOn="@string/start_with_system"
app:summaryOff="@string/start_manually"
app:defaultValue="false"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:key="pref_autoconnect"
app:title="@string/automatic_connection"
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url "https://jitpack.io" }
}
}

Expand Down