Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Empêcher le screen lock sous UWP, Android et iOS

Votre application peut nécessiter de laisser l’écran allumer même s’il n’y pas d’interaction avec l’utilisateur (lecture de vidéo, de diaporama…). Comment faire ?

C’est prévu !

Après un certain temps paramétrable par l’utilisateur Windows 10 va diminuer la luminosité de l’écran voire l’éteindre ou même entrer en veille pour économiser la batterie. Certains logiciels ont parfois besoin d’éviter cette situation, même temporairement (et je vous conseille de ne le faire que temporairement).

UWP prévoit ce besoin et cela se règle facilement :

displayRequest = new Windows.System.Display.DisplayRequest();
displayRequest.RequestActive();

Fermez la porte en sortant !

Les bonnes pratiques respectueuses de l’environnement de travail et des choix de l’utilisateur oblige à rappeler qu’il est indispensable d’annuler la demande avant de sortir de l’application, peu importe comment l’utilisateur sortira (mise en arrière plan, arrêt définitif…).

Bien entendu Windows 10 n’est pas si bête… si l’App passe en arrière-plan il arrêtera lui-même la demande de maintien d’activité de l’écran. Et si l’utilisateur revient sur votre App la fonction ne sera pas rétablie. Il est donc préférable de tout gérer soi-même. Toutefois le passage en arrière-plan suivi d’un passage en avant-plan semble être bien géré sur PC et l’OS rétablit lui-même la demande d’activation. Tout gérer soi-même est conseillé par certains, d’autres disent qu’il est préférable de laisser l’OS faire. Mais si vous devez écrire un code cross-plateforme méfiez-vous de tous ces comportements “par défaut” qui sont généralement très différents d’une plateforme à l’autre. Dans ce cas mieux vaut une gestion impérative qu’une gestion utilisant les comportements par défaut.

Pour annuler la demande sous UWP :

displayRequest.RequestRelease();

Bon à savoir

Cela me semble logique mais ce ne l’est pas forcément à première vue : la demande de relâchement doit être effectuée sur la même instance que la demande RequestActive() sinon il y aura une exception. C’est bien pour cela qu’il faut tout gérer proprement pour réclamer le maintien de l’activité et l’annuler.

On pourra généraliser tout cela de cette façon (UWP) :

private Windows.System.Display.DisplayRequest displayRequest;
private int displayRequestCpt; public void ActivateDisplay() { if (displayRequest == null) displayRequest = new Windows.System.Display.DisplayRequest(); displayRequest.RequestActive();
displayRequestCpt++; } public void ReleaseDisplay() { if (displayRequest == null) return; displayRequest.RequestRelease();
displayRequestCpt—; }

La notion de focus pour une App est différente sur un PC ou une tablette ou un smartphone. Sur PC l’App sera considérée comme en “avant plan” même si sa fenêtre est recouverte par une autre. Seule l’action de minimiser la fera passer en arrière plan. Il faut donc penser à gérer aussi cet événement pour désactiver et réactiver plus tard le maintien de l’écran.

Les appels à RequestActive() peuvent être imbriqués car l’OS gère un compteur. Mais il ne vous donne pas accès à ce dernier. Et il est essentiel de faire un même nombre d’appels à RequestRelease(). D’où l’intérêt de maintenir son propre compteur comme le montre le code ci-dessus. Toutefois je ne conseille pas d’imbriquer ce genre d’appel d’autant que ce que Windows 10 accepte peut ne pas l’être sous Android ou iOS… Et l’importance d’un code cross-plateforme n’est plus à démontrer.

Sous Android

Sous cet OS il faut commencer par déclarer une demande d’autorisation :

<uses-permission android:name="android.permission.WAKE_LOCK" />

Et comme souvent sous cet OS la suite se passe dans l’Activity concernée :

PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Lock");
wakeLock.acquire();

On retrouve le même mécanisme que sous UWP avec la nécessité de relâcher la demande :

wakeLock.release();

En général on utilise le acquire() dans le onResume et le release dans le onPause.

Je parle ici de code purement natif. Si vous travailler avec les XForms il faut utiliser le service de dépendances, créer une interface et enregistrer les implémentations natives ce qui permet d’utiliser le code depuis le noyau partagé.

Google précise que l’oubli des verrous est pénalisant pour l’OS et préconise de déclarer ces derniers directement dans le code dans vue par un android:KeepScreenOn=true. Cette stratégie peut être difficile à utiliser en cross-plateforme avec un service global.

En C# sous Xamarin.Droid Le code ressemble à celui-là (avec la même permission déclarée dans le manifeste et généralement appelé dans le OnCreate de l’activité) :

this.Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn);

Sous iOS

Avec Xamarin.iOS il est possible d’arriver au même résultat avec le code suivant :

// Coupe l’Auto-Lock
UIApplication.SharedApplication.IdleTimerDisabled = true;

// code…
// Rétablit l’Auto-Lock UIApplication.SharedApplication.IdleTimerDisabled = false;

Conclusion

Cette petite fonction semble insignifiante mais bien utilisée dans certains contextes elle peut franchement sauver l’UX de votre App.

Si l’exemple des vidéos est le premier qui vient entête il existe bien d’autres situations dans le monde des applications LOB où cela peut être utile, par exemple un écran de surveillance ou de supervision d’un processus, l’affichage des cours de la bourse, des statistiques sur un traitement temps réel, etc. Il n’est pas concevable que l’écran s���éteigne tout seul lors de tels affichages. Il peut être même intéressant de proposer un paramétrage de mise en veille propre à l’application qui permet ainsi à l’utilisateur d’overrider les réglages globaux au niveau de l’OS.

Bref, ce n’est pas grand chose mais c’est important !

Stay Tuned !

blog comments powered by Disqus