Android: comment écouter les changements de luminosité

Partager cet article

Temps estimé pour la lecture de cet article : 20 min

Nous allons embarquer dans le monde fabuleux d’Android et de ses ContentResolver afin de créer un listener sur la luminosité et ainsi pouvoir réagir à un changement provoqué par l’utilisateur !

La classe Settings

Android, nous permet grâce à la classe Settings d’obtenir différentes informations systèmes sur le smarpthone de l’utilisateur. On y retrouve ainsi différentes classes :

  • Settings.Global: On y retrouve le nom du device, des informations sur le status des composants (WIFI, Bluetooth, …) ou encore des informations de debug (status d’ADB, mode debug…)
  • Settings.Secure: Contient les préférences que l’utilisateur doit explicitement modifier via l’interface du système. Ces valeurs ne sont pas modifiables directement par une application.
  • Settings.System: Ensemble de paramètres système, c’est cette classe que l’on va appeler afin d’obtenir le niveau de luminosité actuel de l’appareil. Cette table contient des fonctions pratiques permettant d’accéder aux différents réglages mais surtout elle peut retourner une URI sur une valeur donnée, ce qui va nous intéresser vous allez voir.

Pour pouvoir lire la valeur actuelle de la luminosité, il suffira d’utiliser la méthode getInt() :

private fun getScreenBrightness(): Int {
    return Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, 0)
}

Le premier paramètre est une référence vers le contentResolver accessible par exemple grâce à un context. Le second correspond à la variable à récupérer, la luminosité donc et enfin le dernier paramètre, c’est une valeur par défaut en cas d’erreur lors de la récupération de la variable.

ContentResolver mon ami

La classe ContentResolver où fournisseur de contenu en français est un object qui va permettre grâce à une URI de renvoyer un flux de données. On peut alors effectuer les opérations CRUD habituelles et ainsi gérer les contacts du téléphone par exemple.

Dans notre cas la méthode qui va nous intéresser, s’appelle registerContentObserver. Elle permet d’enregistrer un observer et ainsi d’être notifié d’un changement sur l’URI passée en paramètre. Ce qui nous donne par exemple pour la luminosité :

contentResolver.registerContentObserver(
    Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, this)
)

On a donc trois paramètres :

  • Une URI: qui correspond à la valeur que l’on veut observer, ici on utilise la fonction getUriFor de la classe Settings.System.
  • notifyForDescendants: la seconde variable est un boolean permet d’être notifié lorsque des modifications ont lieu sur les URIs héritant de celle que l’on veut observer.
  • ContentObserver: ici, c’est tout simplement le listener permettant d’être notifié d’un changement

On fera donc implémenter notre classe de la classe abstraite ContentObserver, il faut alors overrider la méthode onChange, comme ceci :

override fun onChange(selfChange: Boolean) {
    screenBrightnessListener?.onBrightnessChange(getScreenBrightness())
}

Quand on enregistre un listener, il ne faut pas oublier de se désenregistrer, ici rien de plus simple :

contentResolver.unregisterContentObserver(this)

Maintenant qu’on a une vue détaillée de l’ensemble des classes nécessaires, on va pouvoir facilement se développer une classe pour gérer tout ça.

La classe finale et son utilisation

On va définir une classe ScreenBrightnessManager qui va être capable de gérer l’enregistrement et les changements de luminosité :

class ScreenBrightnessManager(private val contentResolver: ContentResolver, handler: Handler) : ContentObserver(handler) {
    companion object {
        const val MAX_BRIGHTNESS = 255
    }
    private var screenBrightnessListener: ScreenBrightnessListener? = null

    fun registerContentObserver() {
        contentResolver.registerContentObserver(
            Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, this
        )
    }

    fun unregisterContentObserver() {
        contentResolver.unregisterContentObserver(this)
    }

    override fun onChange(selfChange: Boolean) {
        screenBrightnessListener?.onBrightnessChange(getScreenBrightness())
    }

    fun getScreenBrightness(): Int {
        return Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, 0)
    }

    fun setScreenBrightnessListener(screenBrightnessListener: ScreenBrightnessListener) {
        this.screenBrightnessListener = screenBrightnessListener
    }
}

La variable MAX_BRIGHTNESS est définie en dur, je ne connais pas de moyen de la récupérer directement, si vous en connaissez un n’hésitez pas à intervenir.

Maintenant, qu’on a notre manager, il faut pouvoir se renvoyer la variable modifiée. On peut ainsi créer l’interface ScreenBrightnessListener associée :

interface ScreenBrightnessListener {
    fun onBrightnessChange(brightness: Int)
}

Et enfin, l’utilisation du tout qui est très simple :

class MainActivity : AppCompatActivity(), ScreenBrightnessListener {
    private lateinit var screenBrightnessManager: ScreenBrightnessManager
    private lateinit var textView: TextView
    private lateinit var relativeLayout: RelativeLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        screenBrightnessManager = ScreenBrightnessManager(contentResolver, Handler(mainLooper))
        screenBrightnessManager.setScreenBrightnessListener(this)
        relativeLayout = findViewById(R.id.relative_layout_background)
        textView = findViewById(R.id.text_view_brightness)
        textView.text = getString(R.string.screen_brightness, brightnessPercentage(screenBrightnessManager.getScreenBrightness()))
    }

    override fun onResume() {
        super.onResume()
        screenBrightnessManager.registerContentObserver()
    }

    private fun brightnessPercentage(brightness: Int): Float {
        return brightness * 100.0f / ScreenBrightnessManager.MAX_BRIGHTNESS
    }

    override fun onBrightnessChange(brightness: Int) {
        textView.text = getString(R.string.screen_brightness, brightnessPercentage(brightness))
    }

    override fun onPause() {
        screenBrightnessManager.unregisterContentObserver()
        super.onPause()
    }
}

On initialise notre manager dans le onCreate(), s’enregistre dans le onResume et enfin se désenregistre dans le onPause(). Si vous ne connaissez pas le lifecycle classique d’une application Android, c’est par ici.

Enfin, on n’oublie pas de faire implémenter notre Activity de notre superbe interface ScreenBrightnessListener et c’est bon. Si vous voulez tester le tout, je vous ai mis le code sur github.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.