Files
LockScreenWallpaper/plugins/android/src/main/java/ScreenOnRotationService.kt
T
Christoph 75c79a8344 feat(android): switch to screen-on rotation service and updated scheduler
The rotation service now responds to screen on/off events via a
dedicated ScreenOnRotationService, reducing background work and
avoiding perpetual wakeful states. Manifest and receiver logic were
adjusted to align with the new behavior and energy constraints.

Scheduling and enablement now consistently use timed-based rules and
screen-on preferences, with the boot and alarm paths updated to honor
these settings. This avoids unnecessary foreground services and keeps
the app compliant with Doze and battery optimizations.

Immich image handling improvements include throttled progress updates,
larger cache allowances, and a connectivity-aware automatic download
check to avoid unwanted network usage.

- Use ScreenOnRotationService for screen-on based rotation scheduling
- Centralize enablement via timed-enabled paths and AlarmManager windowing
- Improve Immich cache and progress reporting with connectivity checks
2026-08-22 20:04:42 +02:00

107 lines
3.6 KiB
Kotlin

package de.wechselbild.wallpaper
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
class ScreenOnRotationService : Service() {
private val worker = Executors.newSingleThreadExecutor()
private val rotating = AtomicBoolean(false)
private val changedWhileScreenOff = AtomicBoolean(false)
private val screenReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!WallpaperStore.screenOnEnabled(context)) return
when (intent.action) {
Intent.ACTION_SCREEN_OFF -> rotate(context, preparedForScreenOn = true)
Intent.ACTION_SCREEN_ON -> {
if (!changedWhileScreenOff.getAndSet(false)) rotate(context, preparedForScreenOn = false)
}
}
}
}
private fun rotate(context: Context, preparedForScreenOn: Boolean) {
if (!rotating.compareAndSet(false, true)) return
worker.execute {
try {
if (WallpaperStore.applyNext(context, automatic = true) && preparedForScreenOn) {
changedWhileScreenOff.set(true)
}
} finally { rotating.set(false) }
}
}
override fun onCreate() {
super.onCreate()
createChannel()
val launch = packageManager.getLaunchIntentForPackage(packageName)
val pending = PendingIntent.getActivity(this, 0, launch, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
val notification = NotificationCompat.Builder(this, CHANNEL)
.setSmallIcon(android.R.drawable.ic_menu_gallery)
.setContentTitle(getString(R.string.wallpaper_service_title))
.setContentText(getString(R.string.wallpaper_service_text))
.setOngoing(true)
.setSilent(true)
.setContentIntent(pending)
.build()
startForeground(NOTIFICATION_ID, notification)
val filter = IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_OFF)
addAction(Intent.ACTION_SCREEN_ON)
}
if (Build.VERSION.SDK_INT >= 33) {
registerReceiver(screenReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
} else {
@Suppress("DEPRECATION")
registerReceiver(screenReceiver, filter)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (!WallpaperStore.screenOnEnabled(this)) {
stopSelf()
return START_NOT_STICKY
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
override fun onDestroy() {
runCatching { unregisterReceiver(screenReceiver) }
worker.shutdown()
super.onDestroy()
}
companion object {
private const val CHANNEL = "wechselbild_screen_on"
private const val NOTIFICATION_ID = 4217
fun start(context: Context) {
ContextCompat.startForegroundService(context, Intent(context, ScreenOnRotationService::class.java))
}
fun stop(context: Context) {
context.stopService(Intent(context, ScreenOnRotationService::class.java))
}
}
private fun createChannel() {
if (Build.VERSION.SDK_INT >= 26) {
val channel = NotificationChannel(CHANNEL, getString(R.string.wallpaper_channel_name), NotificationManager.IMPORTANCE_LOW)
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
}
}
}