diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt index ad7f5bf5..1043c8a2 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt @@ -48,6 +48,7 @@ class App : Application() { // alternative to PreferenceManager.getDefaultSharedPreferencesName(this) deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager(this).sharedPreferencesName) deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME) + BootReceiver.migrateIfNecessary() } else deviceStorage = this Services.init { this } @@ -92,7 +93,6 @@ class App : Application() { }) EBegFragment.init() if (DhcpWorkaround.shouldEnable) DhcpWorkaround.enable(true) - BootReceiver.init() } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/BootReceiver.kt b/mobile/src/main/java/be/mygod/vpnhotspot/BootReceiver.kt index 9964dbea..6ecd19fc 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/BootReceiver.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/BootReceiver.kt @@ -5,13 +5,11 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.os.Build import android.os.Parcelable -import android.widget.Toast +import androidx.annotation.RequiresApi import be.mygod.librootkotlinx.toByteArray import be.mygod.librootkotlinx.toParcelable import be.mygod.vpnhotspot.App.Companion.app -import be.mygod.vpnhotspot.util.readableMessage import kotlinx.parcelize.Parcelize import timber.log.Timber import java.io.DataInputStream @@ -30,6 +28,7 @@ class BootReceiver : BroadcastReceiver() { set(value) = app.packageManager.setComponentEnabledSetting(componentName, if (value) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) + private val userEnabled get() = app.pref.getBoolean(KEY, false) fun onUserSettingUpdated(shouldStart: Boolean) { enabled = shouldStart && try { config @@ -39,7 +38,7 @@ class BootReceiver : BroadcastReceiver() { }?.startables?.isEmpty() == false } private fun onConfigUpdated(isNotEmpty: Boolean) { - enabled = isNotEmpty && app.pref.getBoolean(KEY, false) + enabled = isNotEmpty && userEnabled } private const val FILENAME = "bootconfig" @@ -75,16 +74,19 @@ class BootReceiver : BroadcastReceiver() { inline fun add(value: Startable) = add(T::class.java.name, value) inline fun delete() = delete(T::class.java.name) - fun init() { - if (Build.VERSION.SDK_INT >= 24) { - val oldFile = File(app.noBackupFilesDir, FILENAME) - if (oldFile.canRead()) try { - if (!configFile.exists()) oldFile.copyTo(configFile) - if (!oldFile.delete()) oldFile.deleteOnExit() - } catch (e: Exception) { - Timber.w(e) - } + @RequiresApi(24) + fun migrateIfNecessary() { + val oldFile = File(app.noBackupFilesDir, FILENAME) + if (oldFile.canRead()) try { + if (!configFile.exists()) oldFile.copyTo(configFile) + if (!oldFile.delete()) oldFile.deleteOnExit() + } catch (e: Exception) { + Timber.w(e) } + } + private var started = false + private fun startIfNecessary() { + if (started) return val config = try { synchronized(BootReceiver) { config } } catch (e: Exception) { @@ -93,12 +95,11 @@ class BootReceiver : BroadcastReceiver() { } if (config == null || config.startables.isEmpty()) { enabled = false - } else for (startable in config.startables.values) try { - startable.start(app) - } catch (e: IllegalStateException) { // ForegroundServiceStartNotAllowedException - Timber.w(e) - Toast.makeText(app, e.readableMessage, Toast.LENGTH_LONG).show() - } + } else for (startable in config.startables.values) startable.start(app) + started = true + } + fun startIfEnabled() { + if (started && userEnabled) startIfNecessary() } } @@ -109,5 +110,11 @@ class BootReceiver : BroadcastReceiver() { @Parcelize private data class Config(var startables: MutableMap = mutableMapOf()) : Parcelable - override fun onReceive(context: Context, intent: Intent) { } + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_LOCKED_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED -> { + if (userEnabled) startIfNecessary() else enabled = false + } + } + } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyHotspotService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyHotspotService.kt index 76023a9b..47069135 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyHotspotService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyHotspotService.kt @@ -68,6 +68,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope { override fun onBind(intent: Intent?) = binder override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + BootReceiver.startIfEnabled() if (binder.iface != null) return START_STICKY binder.iface = "" updateNotification() // show invisible foreground notification to avoid being killed diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt index e5c99c59..c7a8cde6 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt @@ -62,6 +62,7 @@ class MainActivity : AppCompatActivity(), NavigationBarView.OnItemSelectedListen SmartSnackbar.Register(binding.fragmentHolder) WifiDoubleLock.ActivityListener(this) lifecycleScope.launch { + BootReceiver.startIfEnabled() repeatOnLifecycle(Lifecycle.State.STARTED) { onAppUpdateAvailable(null) try { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index 8ff0b061..3c8d2aff 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -354,6 +354,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene * startService Step 1 */ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + BootReceiver.startIfEnabled() if (status != Status.IDLE) return START_NOT_STICKY val channel = channel ?: return START_NOT_STICKY.also { stopSelf() } status = Status.STARTING diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt index c981c9db..7f68ed66 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt @@ -111,6 +111,7 @@ class TetheringService : IpNeighbourMonitoringService(), TetheringManager.Tether override fun onBind(intent: Intent?) = binder override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + BootReceiver.startIfEnabled() // call this first just in case we are shutting down immediately if (Build.VERSION.SDK_INT >= 26) updateNotification() launch { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/KillableTileService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/KillableTileService.kt index 78224b21..53142e11 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/util/KillableTileService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/KillableTileService.kt @@ -1,12 +1,14 @@ package be.mygod.vpnhotspot.util import android.content.ComponentName +import android.content.Intent import android.content.ServiceConnection import android.os.Build import android.os.IBinder import android.service.quicksettings.Tile import android.service.quicksettings.TileService import androidx.annotation.RequiresApi +import be.mygod.vpnhotspot.BootReceiver @RequiresApi(24) abstract class KillableTileService : TileService(), ServiceConnection { @@ -25,4 +27,6 @@ abstract class KillableTileService : TileService(), ServiceConnection { onClick() } } + + override fun onBind(intent: Intent?) = super.onBind(intent).also { BootReceiver.startIfEnabled() } }