Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Développement Windows Mobile 6.x : Niveau de batterie / Alimentation / Reset / Mise en veille / Connectivité... Les états du terminal en C#

Introduction :

Afficher le niveau de la batterie du terminal dans une barre d’état, détecter la connectivité de l’appareil ou encore sa mise sous tension, effectuer un reset automatique du terminal… De nombreuses fonctionnalités qu’il est intéressant d’implémenter dans une application mobile professionnelle…

Malheureusement, le .NET Compact Framework est très limité en ce qui concerne la gestion du système et la récupération des états du terminal mobile. Pourtant ces différents aspects sont essentiels dans le cadre du développement d’une application mobile professionnelle…

C’est pourquoi, j’ai décidé de réunir dans cet article quelques méthodes et astuces qui permettent d’effectuer ces actions en C#, notamment en utilisant la technique du PInvoke, ou encore à l’aide du SDK Windows Mobile.

Liens :

 

Etats de la batterie & Alimentation :

Il peut s’avérer très intéressant de récupérer le niveau de la batterie à un instant t; notamment pour l’afficher sous la forme d’un pourcentage dans une barre d’état. De la même façon, et pour des besoins spécifiques, il peut être intéressant de savoir si le terminal est sous tension (en charge) avant de lancer une action particulière qui nécessite que le terminal reste alimenté.

La récupération des états de la batterie est possible grâce à la classe que je vous livre ci-dessous et qui utilise la technique du PInvoke :

using System.Runtime.InteropServices;

namespace TestPower
{
    public class BatteryState
    {
        public const byte AC_LINE_OFFLINE = 0x00;
        public const byte AC_LINE_ONLINE = 0x01;
        public const byte AC_LINE_BACKUP_POWER = 0x02;
        public const byte AC_LINE_UNKNOWN = 0xFF;
        public const byte BATTERY_FLAG_HIGH = 0x01;
        public const byte BATTERY_FLAG_LOW = 0x02;
        public const byte BATTERY_FLAG_CRITICAL = 0x04;
        public const byte BATTERY_FLAG_CHARGING = 0x08;
        public const byte BATTERY_FLAG_NO_BATTERY = 0x80;
        public const byte BATTERY_FLAG_UNKNOWN = 0xFF;
        public const byte BATTERY_PERCENTAGE_UNKNOWN = 0xFF;
        public const uint BATTERY_LIFE_UNKNOWN = 0xFFFFFFFF;
        public const byte BATTERY_CHEMISTRY_ALKALINE = 0x01;
        public const byte BATTERY_CHEMISTRY_NICD = 0x02;
        public const byte BATTERY_CHEMISTRY_NIMH = 0x03;
        public const byte BATTERY_CHEMISTRY_LION = 0x04;
        public const byte BATTERY_CHEMISTRY_LIPOLY = 0x05;
        public const byte BATTERY_CHEMISTRY_UNKNOWN = 0xFF;

        public byte ACLineStatus; 
        public byte BatteryFlag; 
        public byte BatteryLifePercent; 
        public byte Reserved1;
        public uint BatteryLifeTime;
        public uint BatteryFullLifeTime;
        public byte Reserved2;
        public byte BackupBatteryFlag;
        public byte BackupBatteryLifePercent;
        public byte Reserved3;
        public uint BackupBatteryLifeTime;
        public uint BackupBatteryFullLifeTime;
        public uint BatteryVoltage;
        public uint BatteryCurrent;
        public uint BatteryAverageCurrent;
        public uint BatteryAverageInterval;
        public uint BatterymAHourConsumed;
        public uint BatteryTemperature;
        public uint BackupBatteryVoltage;
        public byte BatteryChemistry;

        private BatteryState()
        {
            GetSystemPowerStatusEx(this, false);
        }

        public static BatteryState CurrentState
        {
            get
            {
                return new BatteryState();
            }
        }
        
        [DllImport("coredll")]
        private static extern uint 
            GetSystemPowerStatusEx(BatteryState lpSystemPowerStatus, bool fUpdate);
    }
}

La classe “BatteryState” se base sur la fonction “GetSystemPowerStatusEx” de la DLL système “coredll” pour récupérer les différents états de la batterie à un instant t. Grâce au PInvoke et à la méthode “GetSystemPowerStatusEx”, nous sommes capables de récupérer des informations telles que le niveau de charge de la batterie, ou simplement savoir si le terminal est actuellement en charge.

Pour utiliser cette classe: rien de plus simple. A n’importe quel endroit de votre code .NET (dans une Form par exemple), il vous suffit de faire appel à la propriété statique “CurrentState” de “BatteryState” pour récupérer les informations batterie à un instant t.

Exemples :

- Pour récupérer le niveau de charge actuel de la batterie sous la forme d’un pourcentage :

int niveauBatterie = BatteryState.CurrentState.BatteryLifePercent;

- Pour savoir si le terminal portable est actuellement alimenté :

bool enCharge = BatteryState.CurrentState.ACLineStatus == 1;

La valeur de la variable “ACLineStatus” vaut 1 si le terminal est en charge, 0 sinon.

Plus d’informations sur les états récupérés par la fonction système GetSystemPowerStatusEx ici : http://msdn.microsoft.com/fr-fr/library/ms940384.aspx 

 

Empêcher la mise en veille du terminal :

Nous allons voir ici comment nous pouvons “empêcher” le terminal portable de se mettre en veille en utilisant une fois de plus le PInvoke, et notamment la fonction “SystemIdleTimerReset”.

En fait, la fonction “SystemIdleTimerReset” de la DLL système “coredll” ne permet pas en réalité d’annuler la mise en veille du terminal, mais plus particulièrement de remettre à zéro le timer de mise en veille, c’est à dire de “réveiller” le terminal. Le fait d’appeler cette fonction de manière régulière est donc un bon moyen pour empêcher réellement le terminal de se mettre en veille.

L’idée de la classe “ResetIdleTimerThread”, présentée ci-dessous, est de centraliser l’appel à cette fonction dans un process en arrière-plan (Thread). La fonction “SystemIdleTimerReset” est ainsi appelée indéfiniment dans la boucle du thread, toutes les 20 secondes par exemple. De cette façon, nous effectuons un reset répétitif du timer de mise en veille du terminal.

Les méthodes “StartIdleTimerReset” et “StopIdleTimerReset”de la classe “ResetIdleTimerThread” permettent de démarrer ou d’arrêter l’exécution du thread, c’est à dire d’annuler ou non la mise en veille du terminal.

using System.Runtime.InteropServices;

namespace TestPower
{
    public class ResetIdleTimerThread
    {
        [DllImport("coredll")]
        private static extern void SystemIdleTimerReset();

        private System.Threading.Thread _threadReset = null;
        private System.Threading.ThreadStart _startReset = null;
        private bool _isRunning = false;

        public void StartIdleTimerReset()
        {
            if (!_isRunning)
            {
                _isRunning = true;
                _startReset = new System.Threading.ThreadStart(resetIdleTime);
                _threadReset = new System.Threading.Thread(_startReset);
                _threadReset.Start();
            }
        }

        public void StopIdleTimerReset()
        {
            if (_isRunning)
            {
                _isRunning = false;
                try
                {
                    _threadReset.Abort();
                }
                catch { }
            }
        }
        
        private void resetIdleTime()
        {
            while (_isRunning)
            {
                SystemIdleTimerReset();

                System.Threading.Thread.Sleep(20000);
            }
        }
    }
}

Si vous souhaitez que le terminal mobile ne se mette jamais en veille durant toute l’exécution de votre application, il vous suffit de faire appel à la classe “ResetIdleTimerThread”  et à sa méthode “StartIdleTimerReset” dans le constructeur de la Form principale (ou du moins la Form initiale de l’application), et mettre fin au thread en appelant la méthode “StopIdleTimerReset” lorsque l’utilisateur quitte l’application.

Exemple :

public partial class FormMain : Form
{
   private ResetIdleTimerThread _resetTimerThread = null;

   public FormMain()
   {
      InitializeComponent();

      _resetTimerThread = new ResetIdleTimerThread();
      _resetTimerThread.StartIdleTimerReset();
   }

   // (...)

   protected override void OnClosing(CancelEventArgs e)
   {
       base.OnClosing(e);
       if (_resetTimerThread != null)
           _resetTimerThread.StopIdleTimerReset();
   }
}

 

Reset du terminal en C# :

Pour des besoins particuliers, notamment pour des process de mises à jour logicielles, il peut parfois s’avérer pratique de programmer le reset du terminal au sein d’une application mobile .NET.

Je vous présente encore ci-dessous une classe qui vous permettra d’ordonner un reset du terminal.

La classe “SystemReset” s’appuie sur la fonction “KernelIoControl” de la DLL système “coredll” qui permet de provoquer un reset immédiat de l’appareil :

using System;
using System.Runtime.InteropServices;

namespace TestPower
{
    class SystemReset
    {
        private const uint FILE_DEVICE_HAL = 0x00000101;
        private const uint FILE_DEVICE_CONSOLE = 0x00000102;
        private const uint FILE_DEVICE_PSL = 0x00000103;
        private const uint METHOD_BUFFERED = 0;
        private const uint METHOD_IN_DIRECT = 1;
        private const uint METHOD_OUT_DIRECT = 2;
        private const uint METHOD_NEITHER = 3;
        private const uint FILE_ANY_ACCESS = 0;
        private const uint FILE_READ_ACCESS = 0x0001;
        private const uint FILE_WRITE_ACCESS = 0x0002;

        private static uint CTL_CODE(uint DeviceType,
            uint Function, uint Method, uint Access)
        {
            return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method);
        }

        [DllImport("Coredll.dll")]
        private extern static uint KernelIoControl
        (
            uint dwIoControlCode,
            IntPtr lpInBuf,
            uint nInBufSize,
            IntPtr lpOutBuf,
            uint nOutBufSize,
            ref uint lpBytesReturned
        );
        
        public static void ResetDevice()
        {
            uint bytesReturned = 0;
            uint IOCTL_HAL_REBOOT = CTL_CODE(FILE_DEVICE_HAL, 15,
                METHOD_BUFFERED, FILE_ANY_ACCESS);
            KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0,
                IntPtr.Zero, 0, ref bytesReturned);
        }
    }
}

Pour effectuer un reset de l’appareil à un endroit précis de votre application mobile, il vous suffit alors d’écrire tout simplement la ligne de code suivante :

SystemReset.ResetDevice();

Bien sûr, libre à vous d’afficher un message de confirmation à l’utilisateur avant de provoquer un redémarrage brutal du terminal.

 

Classe SystemState  - Connectivité du terminal :

Enfin, dans ce paragraphe nous allons voir comment nous pouvons facilement détecter la connectivité du terminal mobile. Pour ce faire, nous n’allons plus utiliser le PInvoke, mais plutôt le SDK de Windows Mobile et les librairies qu’il propose.

Vous pouvez télécharger le SDK Windows Mobile 6 en cliquant sur ce lien :

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=06111a3a-a651-4745-88ef-3d48091a390b&displaylang=en . Vous pouvez ainsi télécharger la version “professional” pour les pockets PC, ou la version “standard” pour les smartphones.

La classe “SystemState”, présente dans le namespace “Microsoft.WindowsMobile.Status” du SDK Windows Mobile, peut être utilisée pour récupérer très facilement toute une liste d’informations sur le système.

Les propriétés statiques de la classe permettent de récupérer des informations comme le journal d’appels du téléphone, les rendez-vous de l’agenda, les informations sur le propriétaire,… et également de nombreuses informations sur la connectivité du terminal.

Liste complète des propriétés de la classe “SystemState” :

http://msdn.microsoft.com/en-us/library/microsoft.windowsmobile.status.systemstate_properties.aspx

Pour utiliser la classe “SystemState” et l’ensemble de ses propriétés, vous devez dans un premier temps ajouter 2 références dans votre solution Visual Studio :

imageExemples :

- Pour savoir si le terminal est actuellement posé sur une station d’accueil (cradle):

bool cradle = SystemState.CradlePresent;

- Pour savoir si le terminal dispose actuellement d’une couverture GPRS :

bool grps = SystemState.PhoneGprsCoverage;

- Pour savoir si le terminal est actuellement connecté à un réseau :

bool connected = SystemState.ConnectionsCount > 0;

- Pour savoir si le terminal est actuellement connecté en Ethernet :

bool onEthernet = SystemState.ConnectionsNetworkCount > 0;

OU

bool onEthernet = SystemState.CradlePresent && SystemState.ConnectionsCount > 0;

- Pour savoir si une connection Bluetooth est établie :

bool bluetooth = SystemState.ConnectionsBluetoothCount > 0;

- Etc…

 

Remarque :

A noter que vous pouvez également “surveiller” facilement les changements d’états en instanciant la classe “SystemState” et en utilisant “SystemProperty” pour spécifier la propriété à surveiller :

private SystemState _systemState;

private void RunSystemStateMonitoring()
{
     _systemState = new SystemState(SystemProperty.ConnectionsCount);
     _systemState.Changed += new ChangeEventHandler(_systemState_Changed);
}

void _systemState_Changed(object sender, ChangeEventArgs args)
{
     if ((int)args.NewValue == 1)
     {
          // Le terminal vient de se connecter au réseau !
     }
}

L’évènement “Changed” est levé lorsque la valeur de la propriété spécifiée est modifiée. De cette manière, nous pouvons automatiquement lancer une action lorsque le terminal se connecte à un réseau (exemple ci-dessus).

 

Voilà, c’est tout pour le moment… ;-)

J’espère que toutes ces astuces vous seront utiles…

Encore une fois, n’hésitez pas à me laisser vos commentaires et/ou questions !

Pi-R.

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Pas de commentaires
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01