From 91777fc4598a444ad2cabbce5e4f271cce5b254a Mon Sep 17 00:00:00 2001 From: nk Date: Thu, 11 Jun 2026 14:46:06 +0300 Subject: [PATCH] =?UTF-8?q?feat(background):=20=D0=BF=D0=BE=D0=B4=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=BA=D0=B0=20ColorOS=20=C2=AB=D0=A0=D0=B0?= =?UTF-8?q?=D0=B7=D1=80=D0=B5=D1=88=D0=B8=D1=82=D1=8C=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D1=83=20=D0=B2=20=D1=84=D0=BE=D0=BD=D0=B5=C2=BB=20?= =?UTF-8?q?+=20bump=208/1.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit На Oppo/OnePlus/Realme стандартного исключения из оптимизации батареи мало — система схлопывает приложение в фоне. Один раз показываем пояснение и открываем настройки приложения, чтобы юзер включил «Разрешить работу в фоновом режиме». --- app/build.gradle.kts | 4 +- app/src/main/java/com/radiola/MainActivity.kt | 66 ++++++++++++++++--- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 401824f..b0139c7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,8 +23,8 @@ android { applicationId = "com.radiola" minSdk = 26 targetSdk = 34 - versionCode = 7 - versionName = "1.6" + versionCode = 8 + versionName = "1.7" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/radiola/MainActivity.kt b/app/src/main/java/com/radiola/MainActivity.kt index 28fc9dc..e9d5db1 100644 --- a/app/src/main/java/com/radiola/MainActivity.kt +++ b/app/src/main/java/com/radiola/MainActivity.kt @@ -370,18 +370,64 @@ class MainActivity : ComponentActivity() { private fun maybeRequestBatteryExemption() { val pm = getSystemService(Context.POWER_SERVICE) as android.os.PowerManager - if (pm.isIgnoringBatteryOptimizations(packageName)) return - // Спрашиваем один раз на установку, чтобы не надоедать. val prefs = getSharedPreferences("radiola_prefs", MODE_PRIVATE) - if (prefs.getBoolean("battery_opt_asked", false)) return - prefs.edit().putBoolean("battery_opt_asked", true).apply() - runCatching { - startActivity( - Intent( - android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - android.net.Uri.parse("package:$packageName") + // Спрашиваем один раз на установку, чтобы не надоедать. + if (!pm.isIgnoringBatteryOptimizations(packageName) && + !prefs.getBoolean("battery_opt_asked", false) + ) { + prefs.edit().putBoolean("battery_opt_asked", true).apply() + runCatching { + startActivity( + Intent( + android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + android.net.Uri.parse("package:$packageName") + ) ) - ) + } + } + maybeGuideColorOsBackground() + } + + /** + * ColorOS/OxygenOS (Oppo, OnePlus, Realme) агрессивно «схлопывают» приложение в + * фоне при выключённом экране — стандартного исключения из оптимизации батареи + * мало. Реально помогает галочка «Разрешить работу в фоновом режиме» в разделе + * «Использование батареи» приложения. Прямого API для неё нет, поэтому один раз + * показываем пояснение и открываем экран настроек приложения, чтобы юзер включил. + */ + private fun maybeGuideColorOsBackground() { + val m = android.os.Build.MANUFACTURER.lowercase() + val isColorOs = m.contains("oppo") || m.contains("oneplus") || m.contains("realme") + if (!isColorOs) return + val prefs = getSharedPreferences("radiola_prefs", MODE_PRIVATE) + if (prefs.getBoolean("bg_activity_guided", false)) return + prefs.edit().putBoolean("bg_activity_guided", true).apply() + runCatching { + android.app.AlertDialog.Builder(this) + .setTitle("Фоновое воспроизведение") + .setMessage( + "На вашем устройстве система может выгружать приложение при " + + "выключённом экране, и радио прерывается.\n\n" + + "Чтобы этого не происходило, откройте «Использование батареи» " + + "и включите «Разрешить работу в фоновом режиме»." + ) + .setPositiveButton("Открыть настройки") { _, _ -> openAppBatterySettings() } + .setNegativeButton("Позже", null) + .show() + } + } + + /** Экран «Использование батареи» приложения; фолбэк — страница «О приложении». */ + private fun openAppBatterySettings() { + val uri = android.net.Uri.parse("package:$packageName") + val candidates = listOf( + // На части ColorOS открывает прямо управление батареей приложения. + Intent("android.settings.APP_BATTERY_SETTINGS").apply { data = uri }, + // Универсальный фолбэк — «О приложении», оттуда «Использование батареи». + Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri) + ) + for (intent in candidates) { + if (runCatching { startActivity(intent); true }.getOrDefault(false)) return } } }