State and Notification Broker – Part. 1

di Michele Locuratolo- Microsoft MVP

Nel precedente articolo, abbiamo visto alcune delle novità relative agli strumenti di sviluppo introdotte con l’arrivo di Windows Mobile 6. I nuovi tool rendono estremamente più comodo lo sviluppo di applicazioni per dispositivi mobili ed i recenti sistemi operativi (Windows Mobile 5.0 e 6) permettono di sviluppare applicazioni più complesse esponendo una serie di API.

In questo articolo analizzeremo quella che, in un certo senso, rivoluziona il nostro modo di sviluppare applicazioni e di interagire con il sistema operativo: State and Notification Broker.

Tutti gli argomenti che tratteremo in questo articolo, fanno riferimento a Windows Mobile 6 ma sono compatibili al 100% anche con Windows Mobile 5.0 in quanto queste API non sono sostanzialmente cambiate. Nessuna compatibilità invece con Windows Mobile 2003 (SE) che non espone le suddette API.

In questa pagina

Overview Overview
Lettura degli stati Lettura degli stati
Uso degli stati in applicazioni reali Uso degli stati in applicazioni reali
Conclusioni Conclusioni
Riferimenti Riferimenti

Overview

State and Notification Broker API è indubbiamente una delle rivoluzioni che riguardano Windows Mobile 5.0 (ed il nuovo Windows Mobile 6). La sua introduzione ha di fatto modificato il modo in cui, dal punto di vista degli sviluppatori, la piattaforma Windows Mobile può essere vista. Si è passati infatti da un sistema in cui “far girare” le applicazioni, ad un sistema con cui le nostre applicazioni possono integrarsi in modo semplice e, in alcuni casi, possono anche interagire tra loro o con il sistema operativo.

Prima della realizzazione di questa struttura, le applicazioni sviluppate per dispositivi mobili erano sostanzialmente isolate. L’interazione con il sistema operativo e con le applicazioni su esso presenti, era un’operazione non sempre semplice tanto da far spesso desistere lo sviluppatore dall’includere determinate funzionalità nel proprio software. Funzionalità che spesso avrebbero potuto dare un valore aggiunto al software e, in alcuni casi, prevenire anche errori.

Pensiamo ad esempio ad una applicazione che, in alcuni casi, deve eseguire delle operazioni lunghe, come ad esempio l’elaborazione di una serie di dati acquisiti sul campo. Lavorando su un dispositivo mobile, è logico pensare al fatto che la batteria potrebbe scaricarsi o, ancora peggio, potrebbe essere già scarica al momento in cui l’operatore decide di avviare l’operazione lunga, causando magari inconsistenza dei dati se l’operazione si interrompe.

Uno dei valori aggiunti che potremmo dare ad un software di questo tipo potrebbe essere quello di impedire l’avvio della suddetta operazione in determinate condizioni o, ancora meglio, disabilitare le opportune voci di menù in automatico quando la batteria scende al di sotto di una soglia da noi definita critica per quella operazione.

Nulla che non si potesse fare anche prima, ma avremmo dovuto richiamare una serie di API, spesso usando Interop (Platform Invocation - P/Invoke) ed aggiungendo della logica spesso anche complessa alla nostra applicazione.

State and Notification Broker, come si evince dallo stesso nome, ha il grande pregio di fornire, in modo unificato, sia l’accesso ad una serie di informazioni di stato messe a disposizione del sistema operativo e dalle applicazioni in esso installate, sia eventualmente di notificare agli eventuali subscribers, il cambiamento di valore di questi stati.

L’unificazione delle modalità di accesso alle informazioni, unita al repository comune, ci permettono oggi di aggiungere funzionalità avanzate ai nostri software. Funzionalità in parte disponibili anche con le versioni passate di Windows Mobile, ma di sicuro non di così facile accesso.

Si pensi ad esempio all’orientamento dello schermo. Già in Windows Mobile 2003 SE era possibile passare dalla modalità portait (verticale) a quella landscape (orizzontale) ed era possibile recuperare questa informazione via codice richiamando GetSystemMetrics o controllando la proprietà Screen.PrimaryScreen.Bounds. Stesso discorso qualora volessimo recuperare la quantità di carica della batteria. Avremmo dovuto utilizzare GetSystemPowerStatusEx.

Tutti elementi di API diverse, esposte in modo diverso e non sempre di facile accesso.

State and Notification espone in sostanza più di 100 valori relativi agli stati in un repository comune, collocato all’interno del registro di Windows Mobile e più precisamente sotto la chiave HKEY_LOCAL_MACHINE\System\State per i valori di sistema e sotto la chiave HKEY_CURRENT_USER\System\State.

Alcuni esempi di valori esposti sono:

  • per gli stati di sistema

    • ActiveSync: se stiamo eseguendo una sincronizzazione

    • Battery: informazioni sullo stato delle batterie presenti sul device

    • Bluetooth: numero delle connessioni bluetooth attive

    • Network: lista delle connessioni alla rete attive

    • Camera: indica la presenza di una fotocamera sul device

    • Handsfree: indica se stiamo utilizzando un kit vivavoce

    • etc.

  • per gli stati relativi all’utente:

    • Appointments: l’appuntamento corrente, quello successivo, quello precedente etc.

    • Messages: informazioni sulla presenza di SMS, MMS, E-mail, messaggi non letti etc.

    • Media Player: informazioni su Media Player come la traccia corrente etc.

    • Tasks: informazioni sui tasks (le attività)

    • etc.

Usando un tool come Windows CE Remote Registry Editor (presente in C:\Program Files\CE Remote Tools\5.01\bin\ccregedt.exe) abbiamo la possibilità di vedere esattamente queste chiavi e valori direttamente sul device o, come nel caso dell’esempio, sull’emulatore (Fig.1).

Remote_Registry.PNG

Figura 1: Il Remote Registry Editor

All’indirizzo https://msdn2.microsoft.com/en-us/library/bb154506.aspx è disponibile una utile tabella in cui sono elencati tutti gli stati esposti, la relativa descrizione ed il loro tipo .NET.

 

Lettura degli stati

La lettura degli stati contenuti nel registro di Windows Mobile, usando il codice managed, è una operazione decisamente molto semplice. L’uso di uno dei linguaggi supportati dal .NET Compact Framework infatti, nasconde molta della logica interna necessaria all’accesso dei valori contenuti nelle chiavi di registro. Il risultato è quello di poter accedere ai vari stati utilizzando poche righe di codice, rendendo la nostra applicazione più leggibile e di conseguenza più manutenibile.

Usando codice nativo infatti, per la lettura delle informazioni dovremmo necessariamente accedere al registro di Windows Mobile, ricercare la chiave che ci interessa, leggerne il valore e spesso effettuare operazioni di Bitmask sui valori letti al fine di recuperare il risultato che ci interessa.

Usando il .NET Compact Framework invece, l’accesso ai valore del registro avviene attraverso una serie di proprietà statiche dell’oggetto SystemState, contenuto all’interno del namespace Microsoft.WindowsMobile.Status. In Fig. 2 è visibile una porzione degli stati direttamente accessibili attraverso l’intellisense di Microsoft Visual Studio 2005.

SystemState_Intelli.PNG

Figura 2: acesso agli stati attraverso l'oggetto SystemState

Per poter accedere alle informazioni di stato, sarà quindi sufficiente aggiungere un riferimento a Microsoft.WindowsMobile.Status nel nostro progetto (Fig. 3) e leggere le proprietà SystemState che ci interessano. Tali proprietà sono tipizzate, il che ci permetterà di usarle in modo molto flessibile all’interno della nostra applicazione, nonché di accedere ad ulteriori informazioni relative al tipo specifico.

Add_Reference_State.PNG

Figura 3: aggiunta di Microsoft.WindowsMobile.Status

Di seguito, un esempio di codice che mostra come accedere ad una serie di proprietà diverse:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.WindowsMobile.Status;
using Microsoft.WindowsMobile.PocketOutlook;

namespace MSDN.Article.SNBroker {
    public partial class Form2 : Form {
        /// <summary>
        /// Livello della batteria
        /// </summary>
        private BatteryLevel _batteryLevel = SystemState.PowerBatteryStrength;
        /// <summary>
        /// Collegamento ad ActiveSync presente
        /// </summary>
        private ActiveSyncStatus _activeSyncStatus = SystemState.ActiveSyncStatus;
        /// <summary>
        /// Presenza della fotocamera nel Device
        /// </summary>
        private bool _cameraPresent = SystemState.CameraPresent;
        /// <summary>
        /// Lettura del prossimo appuntamento dal PocketOutlook
        /// </summary>
        private Appointment _nextAppointment = SystemState.CalendarNextAppointment;

        public Form2() {
            InitializeComponent();
        }

        /// <summary>
        /// Caricamento del form principale dell'applicazione
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form2_Load( object sender, EventArgs e ) {
            tbxBatteryLevel.Text  = _batteryLevel.ToString();
            tbxActiveSync.Text    = _activeSyncStatus.ToString();
            tbxCameraPresent.Text = _cameraPresent.ToString();
            tbxNextAppointment.Text = _nextAppointment.Subject;
        }

        /// <summary>
        /// Chiusura dell'applicazione
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menu_Exit_Click( object sender, EventArgs e ) {
            Application.Exit();
        }
    }
}

Il risultato del codice sopra riportato è visibile in Fig. 4.

SomeStates.PNG

Figura 4: l'applicazione di esempio in esecuzione

Come visibile dalla figura, una volta avviata l’applicazione, vengono letti i vari stati impostati via codice e ne viene mostrato il risultato a video.

 

Uso degli stati in applicazioni reali

La lettura degli stati esposti da Windows Mobile fine a sé stessa, ha poco senso in applicazioni pratiche. Il codice del paragrafo precedente che mostra come accedere ad una serie di informazioni mostrandone il risultato a video, in applicazioni reali ha, di per se, poca utilità.

La possibilità di conoscere lo stato di alcuni parametri del device, ritorna invece estremamente utile quando abbiamo la necessità di modificare il comportamento del nostro software in funzione di essi.

In apertura, si è fatto un esempio pratico di quanto appena detto: “pensiamo ad esempio ad una applicazione che, in alcuni casi, deve eseguire delle operazioni lunghe, come ad esempio l’elaborazione di una serie di dati acquisiti sul campo. Lavorando su un dispositivo mobile, è logico pensare al fatto che la batteria potrebbe scaricarsi o, ancora peggio, potrebbe essere già scarica al momento in cui l’operatore decide di avviare l’operazione lunga, causando magari inconsistenza dei dati se l’operazione si interrompe.

Uno dei valori aggiunti che potremmo dare ad un software di questo tipo potrebbe essere quello di impedire l’avvio della suddetta operazione in determinate condizioni o, ancora meglio, disabilitare le opportune voci di menù in automatico quando la batteria scende al di sotto di una soglia da noi definita critica per quella operazione”.

L’implementazione di un requisito come questo, grazie alle API esposte da Windows Mobile, è decisamente molto semplice. Oltre alla possibilità di conoscere programmaticamente il valore di uno stato, Windows Mobile ci permette di ricevere una serie di notifiche relative al cambio del valore degli stati esposti. Ed è qui che entra in gioco la parte “Notification” di State and Notification Broker.

Per poter ricevere le notifiche di cambio di stato, dobbiamo sostanzialmente eseguire tre step fondamentali:

  1. Registrarsi alle notifica di cambiamento di uno stato: è la prima cosa da fare. Se vogliamo essere notificati circa il cambio di livello della batterie, come prima cosa dobbiamo “informare” il sistema operativo che vogliamo ricevere quella particolare notifica.

  2. Gestire l’evento di notifica: una volta registrati ad un evento, nel nostro codice dobbiamo gestire la notifica relativa all’evento registrato in modo da poter compiere delle operazioni specifiche.

  3. Leggere il nuovo valore: l’arrivo di una notifica indica che un particolare valore è stato modificato. A questo punto possiamo leggere il nuovo valore.

Vediamo quindi come implementare il nostro sistema che impedisce l’avvio di operazioni notoriamente lunghe se la batteria del device non è successivamente carica.

Come prima cosa, registriamo la nostra applicazione alle notifiche, passando come argomento del costruttore dell’oggetto SystemState, lo stato che di cui vogliamo ricevere le notifiche:

//Creazione dell'istanza di SystemState relativa allo stato da monitorare
SystemState _batteryState = new SystemState( SystemProperty.PowerBatteryStrength );
//Registrazione all'evento Changed dello state monitorato
_batteryState.Changed += new ChangeEventHandler( battery_Changed );

Fatto ciò, Windows Mobile ci informerà ogni qual volt ail valore della proprietà PowerbatteryStrenght verrà modificato. Ora non ci resta che implementare il metodo battery_changed per gestire la notifica e leggerne il nuovo valore dello stato.

Lo scopo che ci siamo prefissi è quello di impedire l’avvio di determinate operazioni se la batteria è scarica e, quando possibile, inibire la relativa voce di menù. Per farlo, all’interno del gestore dell’evento di notifica, ci basterà leggere il nuovo valore di PowerBatteryStrenght e comportarci di conseguenza. Il seguente codice mostra come fare:

/// <summary>
/// Gestione dell'evento Change
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void battery_Changed( object sender, ChangeEventArgs args ) {
    //Leggo il nuovo valore di PowerBatteryStrength
    _batteryLevel = (BatteryLevel) args.NewValue;
    //Imposto il testo nella label con il nuovo valore
    tbxBatteryLevel.Text = _batteryLevel.ToString();
    //in base al livello della batteria, abilito o disabilito il menù
    if ( _batteryLevel == BatteryLevel.VeryLow ) {
        menu_LongRunning.Enabled = false;
    } else if ( _batteryLevel == BatteryLevel.High || _batteryLevel == BatteryLevel.VeryHigh) {
        menu_LongRunning.Enabled = true;
    }
}

Il nuovo valore dello stato monitorato, ritorna attraverso gli EventArgs (ChangeEventArgs) dell’evento Changed sotto forma di Object. Prima di usare tale valore, dovremmo quindi castarlo al tipo specifico che stiamo gestendo.

Ai fini pratici, la sola gestione dell’evento Changed potrebbe non essere sufficiente a prevenire l’esecuzione di comandi lunghi. Il codice mostrato infatti, disabilita la voce di menù solo se viene ricevuto l’evento di cambio di valore dello stato monitorato. Ma se avviamo l’applicazione quando la batteria è già scarica, dobbiamo prevenire l’esecuzione del comando anche se la voce di menù è ancora abilitata.

Per farlo, non ci resta che verificare il livello della batteria prima di eseguire l’operazione:

/// <summary>
/// Esecuzione del comando
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void menu_LongRunning_Click( object sender, EventArgs e ) {
    //Prima di avviare l'esecuzione, controllo lo stato della batteria
    if ( _batteryLevel == BatteryLevel.VeryLow) {
        MessageBox.Show("Batteria insufficiente per eseguire l\'operazione. Caricare la batteria e riprovare",
                        "Alert!");
        menu_LongRunning.Enabled = false;
    }else {
        //Do something
        MessageBox.Show("Esecuzione dell\'operazione in corso...", "Esecuzione...");
    }
}

Per testare questa applicazione, ci vengono in contro i nuovi emulatori di Windows Mobile che ci permettono, tra le altre cose, di modificare il livello della batteria (vedi l’articolo pubblicato al seguente url: https://www.microsoft.com/italy/msdn/risorsemsdn/mobile/overview.mspx ).

Avviamo quindi l’emulatore, scegliamo la voce File, Configure ed il tab Peripherals, modifichiamo il livello della batteria e verifichiamo il funzionamento del software.

Di seguito alcune immagini del testing:

settings.JPG

Figura 5: modifica del livello della batteria

Test.png

Figura 6: testing dell'applicazione con l'emulatore

 

Conclusioni

L’argomento relativo a State and Notification Broker è abbastanza vasto ed importante per concludersi in un solo articolo. In questa prima parte abbiamo affrontato le nozioni di base e l’architettura alla base del sistema di notifiche. Nel prossimo articolo, analizzeremo gli aspetti avanzati di queste API, come il filtraggio delle notifiche e le così dette “notifiche persistenti”.

 

Riferimenti