Fix possible NPE during refresh rate switch (#448)

Use current thread's looper or fallback to the main looper for the
display change callback.

This is the behavior in newer versions of Android whereas older versions
assumed a non-null looper.

Fixes #446
This commit is contained in:
damontecres 2025-12-13 17:58:30 -05:00 committed by GitHub
parent d2e1c4683d
commit a386028b6b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3,9 +3,12 @@ package com.github.damontecres.wholphin.services
import android.content.Context import android.content.Context
import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.Display import android.view.Display
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.github.damontecres.wholphin.ui.setValueOnMain import com.github.damontecres.wholphin.ui.setValueOnMain
import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.EqualityMutableLiveData import com.github.damontecres.wholphin.util.EqualityMutableLiveData
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -57,12 +60,18 @@ class RefreshRateService
Timber.i("Found display mode: %s, current=${display.mode}", targetMode) Timber.i("Found display mode: %s, current=${display.mode}", targetMode)
if (targetMode != null && targetMode != display.mode) { if (targetMode != null && targetMode != display.mode) {
val listener = Listener(display.displayId) val listener = Listener(display.displayId)
displayManager.registerDisplayListener(listener, null) displayManager.registerDisplayListener(
listener,
Handler(Looper.myLooper() ?: Looper.getMainLooper()),
)
_refreshRateMode.setValueOnMain(targetMode) _refreshRateMode.setValueOnMain(targetMode)
try { try {
listener.latch.await(5, TimeUnit.SECONDS) if (!listener.latch.await(5, TimeUnit.SECONDS)) {
} catch (_: InterruptedException) {
Timber.w("Timed out waiting for display change") Timber.w("Timed out waiting for display change")
showToast(context, "Refresh rate switch is taking a long time")
}
} catch (ex: InterruptedException) {
Timber.w(ex, "Exception waiting for refresh rate switch")
} }
val targetRate = (targetMode.refreshRate * 100).roundToInt() val targetRate = (targetMode.refreshRate * 100).roundToInt()
val isSeamless = val isSeamless =