From 961fc4452f69fe0b07f20e73a82361cec998e8b7 Mon Sep 17 00:00:00 2001 From: Tim Schneeberger Date: Thu, 23 Mar 2023 23:06:43 +0100 Subject: [PATCH] feat(rootless): add auto-start support (requires new permissions) --- app/src/main/AndroidManifest.xml | 1 + .../fragment/OnboardingFragment.kt | 26 ++++++++++++++++--- .../receiver/BootCompletedReceiver.kt | 18 ++++++++++++- app/src/main/res/layout/onboarding_page4.xml | 10 +++++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 08875f3ff..fe5210308 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + diff --git a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/fragment/OnboardingFragment.kt b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/fragment/OnboardingFragment.kt index fd2ac8538..efab9288b 100644 --- a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/fragment/OnboardingFragment.kt +++ b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/fragment/OnboardingFragment.kt @@ -27,6 +27,7 @@ import me.timschneeberger.rootlessjamesdsp.activity.OnboardingActivity.Companion import me.timschneeberger.rootlessjamesdsp.databinding.OnboardingFragmentBinding import me.timschneeberger.rootlessjamesdsp.flavor.RootShellImpl import me.timschneeberger.rootlessjamesdsp.service.RootAudioProcessorService +import me.timschneeberger.rootlessjamesdsp.utils.SdkCheck import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.isPackageInstalled import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.launchApp import me.timschneeberger.rootlessjamesdsp.utils.extensions.ContextExtensions.openPlayStoreApp @@ -36,7 +37,6 @@ import me.timschneeberger.rootlessjamesdsp.utils.extensions.PermissionExtensions import me.timschneeberger.rootlessjamesdsp.utils.extensions.PermissionExtensions.hasNotificationPermission import me.timschneeberger.rootlessjamesdsp.utils.extensions.PermissionExtensions.hasRecordPermission import me.timschneeberger.rootlessjamesdsp.utils.preferences.Preferences -import me.timschneeberger.rootlessjamesdsp.utils.SdkCheck import me.timschneeberger.rootlessjamesdsp.utils.sdkAbove import org.koin.android.ext.android.inject import rikka.shizuku.Shizuku @@ -450,8 +450,26 @@ class OnboardingFragment : Fragment() { Timber .d("Granting DUMP via Shizuku (uid ${Shizuku.getUid()}) for $pkg") - // Grant DUMP as system - ShizukuSystemServerApi.PermissionManager_grantRuntimePermission(pkg, Manifest.permission.DUMP, UserHandle.USER_SYSTEM) + // Grant DUMP as shell + ShizukuSystemServerApi.PermissionManager_grantRuntimePermission( + pkg, + Manifest.permission.DUMP, + UserHandle.USER_SYSTEM + ) + + // Grant SYSTEM_ALERT_WINDOW as shell + try { + ShizukuSystemServerApi.PermissionManager_grantRuntimePermission( + pkg, + Manifest.permission.SYSTEM_ALERT_WINDOW, + UserHandle.USER_SYSTEM + ) + } + catch (ex: Exception) { + Timber.e(ex) + } + + // Grant permanent PROJECT_MEDIA op as shell try { val result = ShizukuSystemServerApi.AppOpsService_setMode( ShizukuSystemServerApi.APP_OPS_OP_PROJECT_MEDIA, @@ -530,6 +548,7 @@ class OnboardingFragment : Fragment() { page.step4.isVisible = selectedSetupMethod == SetupMethods.Adb page.step5.isVisible = selectedSetupMethod == SetupMethods.Adb page.step5bOptional.isVisible = selectedSetupMethod == SetupMethods.Adb && BuildConfig.ROOTLESS + page.step5cOptional.isVisible = selectedSetupMethod == SetupMethods.Adb && BuildConfig.ROOTLESS if(selectedSetupMethod == SetupMethods.Shizuku) { val installed = requireContext().isPackageInstalled(SHIZUKU_PKG) @@ -574,6 +593,7 @@ class OnboardingFragment : Fragment() { page.step4.bodyText = getString(R.string.onboarding_adb_manual_step4, requireContext().packageName) page.step5.bodyText = getString(R.string.onboarding_adb_manual_step5) page.step5bOptional.bodyText = getString(R.string.onboarding_adb_manual_step5b, requireContext().packageName) + page.step5cOptional.bodyText = getString(R.string.onboarding_adb_manual_step5c, requireContext().packageName) page.title.text = getString(R.string.onboarding_adb_adb_title) } diff --git a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/receiver/BootCompletedReceiver.kt b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/receiver/BootCompletedReceiver.kt index dd58251f6..f23f837e5 100644 --- a/app/src/main/java/me/timschneeberger/rootlessjamesdsp/receiver/BootCompletedReceiver.kt +++ b/app/src/main/java/me/timschneeberger/rootlessjamesdsp/receiver/BootCompletedReceiver.kt @@ -3,13 +3,17 @@ package me.timschneeberger.rootlessjamesdsp.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.provider.Settings import me.timschneeberger.rootlessjamesdsp.BuildConfig import me.timschneeberger.rootlessjamesdsp.R +import me.timschneeberger.rootlessjamesdsp.activity.EngineLauncherActivity import me.timschneeberger.rootlessjamesdsp.service.RootAudioProcessorService -import me.timschneeberger.rootlessjamesdsp.utils.preferences.Preferences +import me.timschneeberger.rootlessjamesdsp.utils.extensions.PermissionExtensions.hasProjectMediaAppOp import me.timschneeberger.rootlessjamesdsp.utils.notifications.ServiceNotificationHelper +import me.timschneeberger.rootlessjamesdsp.utils.preferences.Preferences import org.koin.core.component.KoinComponent import org.koin.core.component.inject +import timber.log.Timber class BootCompletedReceiver : BroadcastReceiver(), KoinComponent { @@ -23,6 +27,18 @@ class BootCompletedReceiver : BroadcastReceiver(), KoinComponent { if (!preferences.get(R.string.key_autostart_prompt_at_boot)) return + if(Settings.canDrawOverlays(context) && context.hasProjectMediaAppOp()) { + Timber.i("Preconditions for a silent auto-start met") + context.startActivity(Intent(context, EngineLauncherActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or + Intent.FLAG_ACTIVITY_MULTIPLE_TASK or + Intent.FLAG_ACTIVITY_NO_USER_ACTION or + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or + Intent.FLAG_ACTIVITY_NO_ANIMATION + }) + return + } + ServiceNotificationHelper.pushPermissionPromptNotification(context) } else { diff --git a/app/src/main/res/layout/onboarding_page4.xml b/app/src/main/res/layout/onboarding_page4.xml index a857c5727..75391bae2 100644 --- a/app/src/main/res/layout/onboarding_page4.xml +++ b/app/src/main/res/layout/onboarding_page4.xml @@ -96,6 +96,16 @@ app:iconSrc="@drawable/ic_twotone_info_24dp" app:iconTint="?attr/colorOnSurface" /> + + + Navigate to \'Interactive Shell\' and execute the following command in the shell: \'pm grant %s android.permission.DUMP\' Tap \'Next\' in this app to continue. (Optional) You can permanently skip the audio capture permission prompts by executing this command: \'appops set %s PROJECT_MEDIA allow\' + (Optional) In addition to the previous step, you can also enable auto-start by executing the following command: \'pm grant %s android.permission.SYSTEM_ALERT_WINDOW\' Open development settings Other permissions