Panoramica dei sensori

La maggior parte dei dispositivi Android è dotata di sensori integrati che misurano movimento, orientamento e varie condizioni ambientali. Questi sensori sono in grado di fornire dati non elaborati con elevata precisione e sono utili se vuoi monitorare il movimento o il posizionamento tridimensionale del dispositivo oppure se vuoi monitorare le variazioni dell'ambiente circostante un dispositivo. Ad esempio, un gioco potrebbe monitorare le letture del sensore di gravità di un dispositivo per dedurre gesti e movimenti complessi dell'utente, come inclinazione, scuotimento, rotazione o oscillazione. Analogamente, un'applicazione meteo potrebbe utilizzare il sensore di temperatura e il sensore di umidità di un dispositivo per calcolare e segnalare il punto di rugiada oppure un'applicazione per i viaggi potrebbe utilizzare il sensore del campo geomagnetico e l'accelerometro per segnalare la bussola.

La piattaforma Android supporta tre ampie categorie di sensori:

  • Sensori di movimento

    Questi sensori misurano le forze di accelerazione e le forze di rotazione lungo tre assi. Questa categoria include accelerometri, sensori di gravità, giroscopi e sensori di vettore di rotazione.

  • Sensori ambientali

    Questi sensori misurano vari parametri ambientali, come la temperatura e la pressione dell'aria ambiente, l'illuminazione e l'umidità. Questa categoria include barometri, fotometri e termometri.

  • Sensori di posizione

    Questi sensori misurano la posizione fisica di un dispositivo. Questa categoria include sensori di orientamento e magnetometri.

Puoi accedere ai sensori disponibili sul dispositivo e acquisire i dati non elaborati dei sensori utilizzando il framework di sensori Android. Il framework del sensore fornisce diverse classi e interfacce che ti aiutano a eseguire un'ampia gamma di attività correlate ai sensori. Ad esempio, puoi utilizzare il framework del sensore per:

  • Determina quali sensori sono disponibili su un dispositivo.
  • Determina le funzionalità di un singolo sensore, ad esempio la sua portata massima, il produttore, i requisiti di alimentazione e la risoluzione.
  • Acquisisci i dati dei sensori non elaborati e definisci la frequenza minima di acquisizione dei dati dei sensori.
  • Registra e annulla la registrazione degli ascoltatori di eventi del sensore che monitorano le modifiche del sensore.

Questo argomento fornisce una panoramica dei sensori disponibili sulla piattaforma Android. Fornisce inoltre un'introduzione al framework del sensore.

Introduzione ai sensori

Il framework dei sensori Android ti consente di accedere a molti tipi di sensori. Alcuni di questi sensori sono basati su hardware e altri su software. I sensori basati su hardware sono componenti fisici integrati in un cellulare o un tablet. Ricavano i dati misurando direttamente proprietà ambientali specifiche, come accelerazione, intensità del campo geomagnetico o variazione angolare. I sensori basati su software non sono dispositivi fisici, anche se simulano i sensori basati su hardware. I sensori basati su software ricavano i dati da uno o più sensori basati su hardware e a volte sono chiamati sensori virtuali o sintetici. Il sensore di accelerazione lineare e il sensore di gravità sono esempi di sensori basati su software. La tabella 1 riassume i sensori supportati dalla piattaforma Android.

Pochi dispositivi Android sono dotati di tutti i tipi di sensori. Ad esempio, la maggior parte dei cellulari e dei tablet è dotata di un accelerometro e di un magnetometro, ma un numero inferiore di dispositivi è dotato di barometri o termometri. Inoltre, un dispositivo può avere più di un sensore di un determinato tipo. Ad esempio, un dispositivo può avere due sensori di gravità, ognuno con un intervallo diverso.

Tabella 1. Tipi di sensori supportati dalla piattaforma Android.

Sensore Digitazione Descrizione Utilizzi comuni
TYPE_ACCELEROMETER Hardware Misura la forza di accelerazione in m/s2 applicata a un dispositivo su tutti e tre gli assi fisici (x, y e z), inclusa la forza di gravità. Rilevamento dei movimenti (scossa, inclinazione e così via).
TYPE_AMBIENT_TEMPERATURE Hardware Misura la temperatura ambiente in gradi Celsius (°C). Vedi la nota di seguito. Monitoraggio delle temperature dell'aria.
TYPE_GRAVITY Software o hardware Misura la forza di gravità in m/s2 applicata a un dispositivo su tutti i tre gli assi fisici (x, y, z). Rilevamento dei movimenti (scossa, inclinazione e così via).
TYPE_GYROSCOPE Hardware Misura la velocità di rotazione di un dispositivo in rad/s intorno a ciascuno dei tre assi fisici (x, y e z). Rilevamento della rotazione (giro, svolta e così via).
TYPE_LIGHT Hardware Misura il livello di luce ambientale (illuminazione) in lx. Controllo della luminosità dello schermo.
TYPE_LINEAR_ACCELERATION Software o hardware Misura la forza di accelerazione in m/s2 applicata a un dispositivo su tutti e tre gli assi fisici (x, y e z), escludendo la forza di gravità. Monitoraggio dell'accelerazione lungo un singolo asse.
TYPE_MAGNETIC_FIELD Hardware Misura il campo geomagnetico ambientale per tutti e tre gli assi fisici (x, y, z) in μT. Creazione di una bussola.
TYPE_ORIENTATION Software Misura i gradi di rotazione di un dispositivo intorno a tutti e tre gli assi fisici (x, y, z). A partire dal livello 3 dell'API, puoi ottenere la matrice di inclinazione e la matrice di rotazione per un dispositivo utilizzando il sensore di gravità e il sensore del campo geomagnetico in combinazione con il metodo getRotationMatrix(). Determinazione della posizione del dispositivo.
TYPE_PRESSURE Hardware Misura la pressione dell'aria ambiente in hPa o mbar. Monitoraggio delle variazioni della pressione dell'aria.
TYPE_PROXIMITY Hardware Misura la vicinanza di un oggetto in cm rispetto allo schermo di visualizzazione di un dispositivo. Questo sensore viene in genere utilizzato per determinare se un cellulare viene tenuto vicino all'orecchio di una persona. Posizione dello smartphone durante una chiamata.
TYPE_RELATIVE_HUMIDITY Hardware Misura l'umidità relativa dell'ambiente in percentuale (%). Monitoraggio del punto di rugiada, dell'umidità assoluta e relativa.
TYPE_ROTATION_VECTOR Software o hardware Misura l'orientamento di un dispositivo fornendo i tre elementi del suo vettore di rotazione. Rilevamento dei movimenti e della rotazione.
TYPE_TEMPERATURE Hardware Misura la temperatura del dispositivo in gradi Celsius (°C). L'implementazione di questo sensore varia in base ai dispositivi e questo sensore è stato sostituito con il sensore TYPE_AMBIENT_TEMPERATURE nel livello API 14 Monitoraggio delle temperature.

Framework Sensor

Puoi accedere a questi sensori e acquisire i dati non elaborati dei sensori utilizzando il framework dei sensori Android. Il framework del sensore fa parte del pacchetto android.hardware e include le seguenti classi e interfacce:

SensorManager
Puoi utilizzare questa classe per creare un'istanza del servizio del sensore. Questa classe fornisce vari metodi per accedere ai sensori e elencarli, registrare e annullare la registrazione degli ascoltatori di eventi dei sensori e acquisire informazioni sull'orientamento. Questa classe fornisce anche diverse costanti del sensore che vengono utilizzate per segnalare l'accuratezza del sensore, impostare le frequenze di acquisizione dei dati e calibrare i sensori.
Sensor
Puoi utilizzare questa classe per creare un'istanza di un sensore specifico. Questa classe fornisce vari metodi che consentono di determinare le funzionalità di un sensore.
SensorEvent
Il sistema utilizza questa classe per creare un oggetto evento sensore, che fornisce informazioni su un evento sensore. Un oggetto evento del sensore include le seguenti informazioni: i dati non elaborati del sensore, il tipo di sensore che ha generato l'evento, la precisione dei dati e il timestamp dell'evento.
SensorEventListener
Puoi utilizzare questa interfaccia per creare due metodi di callback che ricevono notifiche (eventi del sensore) quando i valori del sensore cambiano o quando cambia la precisione del sensore.

In un'applicazione tipica, utilizzi queste API relative ai sensori per eseguire due attività di base:

  • Identificazione dei sensori e delle relative funzionalità

    L'identificazione dei sensori e delle relative funzionalità in fase di esecuzione è utile se la tua applicazione ha funzionalità che si basano su tipi o funzionalità di sensori specifici. Ad esempio, potresti voler identificare tutti i sensori presenti su un dispositivo e disattivare le funzionalità dell'applicazione che si basano su sensori non presenti. Analogamente, ti consigliamo di identificare tutti i sensori di un determinato tipo in modo da poter scegliere l'implementazione del sensore con le prestazioni ottimali per la tua applicazione.

  • Monitorare gli eventi dei sensori

    Il monitoraggio degli eventi dei sensori è il modo in cui acquisisci i dati non elaborati dei sensori. Un evento del sensore si verifica ogni volta che un sensore rileva una variazione nei parametri che sta misurando. Un evento del sensore fornisce quattro informazioni: il nome del sensore che ha attivato l'evento, il timestamp dell'evento, la precisione dell'evento e i dati non elaborati del sensore che ha attivato l'evento.

Disponibilità del sensore

La disponibilità dei sensori varia da dispositivo a dispositivo, ma può variare anche in base alle versioni di Android. Questo perché i sensori Android sono stati introdotti nel corso di diverse release della piattaforma. Ad esempio, molti sensori sono stati introdotti in Android 1.5 (livello API 3), ma alcuni non sono stati implementati e non sono stati disponibili per l'utilizzo fino ad Android 2.3 (livello API 9). Analogamente, diversi sensori sono stati introdotti in Android 2.3 (livello API 9) e Android 4.0 (livello API 14). Due sensori sono stati ritirati e sostituiti da sensori più recenti e migliori.

La tabella 2 riassume la disponibilità di ciascun sensore in base alla piattaforma. Sono elencate solo quattro piattaforme perché sono quelle che hanno richiesto modifiche ai sensori. I sensori elencati come ritirati sono ancora disponibili sulle piattaforme successive (a condizione che il sensore sia presente su un dispositivo), in linea con le norme di compatibilità futura di Android.

Tabella 2. Disponibilità dei sensori in base alla piattaforma.

Sensore Android 4.0
(livello API 14)
Android 2.3
(livello API 9)
Android 2.2
(livello API 8)
Android 1.5
(livello API 3)
TYPE_ACCELEROMETER
TYPE_AMBIENT_TEMPERATURE n/a n/d n/a
TYPE_GRAVITY n/a n/a
TYPE_GYROSCOPE n/a1 n/a1
TYPE_LIGHT
TYPE_LINEAR_ACCELERATION n/a n/a
TYPE_MAGNETIC_FIELD
TYPE_ORIENTATION 2 2 2
TYPE_PRESSURE n/a1 n/a1
TYPE_PROXIMITY
TYPE_RELATIVE_HUMIDITY n/a n/d n/a
TYPE_ROTATION_VECTOR n/a n/a
TYPE_TEMPERATURE 2

1 Questo tipo di sensore è stato aggiunto in Android 1.5 (livello API 3), ma non è stato possibile utilizzarlo fino ad Android 2.3 (livello API 9).

2 Questo sensore è disponibile, ma è stato ritirato.

Identificazione dei sensori e delle relative funzionalità

Il framework dei sensori Android fornisce diversi metodi che ti consentono di determinare facilmente in fase di esecuzione quali sensori sono presenti su un dispositivo. L'API fornisce anche metodi che consentono di determinare le funzionalità di ciascun sensore, ad esempio la sua portata massima, la sua risoluzione e i suoi requisiti di alimentazione.

Per identificare i sensori presenti su un dispositivo, devi prima ottenere un riferimento al servizio del sensore. A tal fine, crea un'istanza della classe SensorManager chiamando il metodo getSystemService() e passando l'argomento SENSOR_SERVICE. Ad esempio:

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

Successivamente, puoi ottenere un elenco di tutti i sensori su un dispositivo chiamando il metodo getSensorList() e utilizzando la costante TYPE_ALL. Ad esempio:

Kotlin

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

Java

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

Se vuoi elencare tutti i sensori di un determinato tipo, puoi utilizzare un'altra costante anziché TYPE_ALL, ad esempio TYPE_GYROSCOPE, TYPE_LINEAR_ACCELERATION o TYPE_GRAVITY.

Puoi anche determinare se su un dispositivo esiste un tipo specifico di sensore utilizzando il metodo getDefaultSensor() e passando la costante type per un sensore specifico. Se un dispositivo ha più di un sensore di un determinato tipo, uno dei sensori deve essere designato come sensore predefinito. Se non esiste un sensore predefinito per un determinato tipo di sensore, la chiamata al metodo restituisce null, il che significa che il dispositivo non ha quel tipo di sensore. Ad esempio, il seguente codice controlla se su un dispositivo è presente un magnetometro:

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Nota: Android non richiede ai produttori di dispositivi di integrare tipi specifici di sensori nei loro dispositivi Android, pertanto i dispositivi possono avere un'ampia gamma di configurazioni dei sensori.

Oltre a elencare i sensori presenti su un dispositivo, puoi utilizzare i metodi pubblici della classe Sensor per determinare le funzionalità e gli attributi dei singoli sensori. Questa opzione è utile se vuoi che la tua applicazione si comporti in modo diverso in base ai sensori o alle funzionalità dei sensori disponibili su un dispositivo. Ad esempio, puoi utilizzare i metodi getResolution() e getMaximumRange() per ottenere la risoluzione e l'intervallo di misurazione massimo di un sensore. Puoi anche utilizzare il metodo getPower() per ottenere i requisiti di alimentazione di un sensore.

Due dei metodi pubblici sono particolarmente utili se vuoi ottimizzare la tua applicazione per i sensori di diversi produttori o per versioni diverse di un sensore. Ad esempio, se la tua applicazione deve monitorare i gesti dell'utente, come inclinazione e scuotimento, puoi creare un insieme di regole e ottimizzazioni per il filtro dei dati per i dispositivi più recenti che dispongono di un sensore di gravità di un fornitore specifico e un altro insieme di regole e ottimizzazioni per il filtro dei dati per i dispositivi che non dispongono di un sensore di gravità e dispongono solo di un accelerometro. Il seguente esempio di codice mostra come utilizzare i metodi getVendor() e getVersion() per farlo. In questo esempio, cerchiamo un sensore di gravità che indichi Google LLC come fornitore e abbia un numero di versione pari a 3. Se questo particolare sensore non è presente sul dispositivo, proviamo a utilizzare l'accelerometro.

Kotlin

private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

Java

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

Un altro metodo utile è il metodo getMinDelay(), che restituisce l'intervallo di tempo minimo (in microsecondi) che un sensore può utilizzare per rilevare i dati. Qualsiasi sensore che restituisce un valore diverso da zero per il metodo getMinDelay() è un sensore in streaming. I sensori di streaming rilevano i dati a intervalli regolari e sono stati introdotti in Android 2.3 (livello API 9). Se un sensore restituisce zero quando chiami il metodo getMinDelay(), significa che il sensore non è un sensore in streaming perché registra i dati solo quando si verifica una variazione nei parametri che rileva.

Il metodo getMinDelay() è utile perché consente di determinare la frequenza massima con cui un sensore può acquisire dati. Se determinate funzionalità della tua applicazione richiedono tassi di acquisizione di dati elevati o un sensore in streaming, puoi utilizzare questo metodo per determinare se un sensore soddisfa questi requisiti e attivare o disattivare le funzionalità pertinenti nella tua applicazione di conseguenza.

Attenzione: la frequenza massima di acquisizione dei dati di un sensore non è necessariamente la frequenza con cui il framework del sensore invia i dati del sensore all'applicazione. Il framework del sensore registra i dati tramite eventi del sensore e diversi fattori influiscono sulla frequenza con cui la tua applicazione riceve questi eventi. Per ulteriori informazioni, consulta Monitorare gli eventi dei sensori.

Monitoraggio degli eventi del sensore

Per monitorare i dati non elaborati del sensore, devi implementare due metodi di callback esposti tramite l'interfaccia SensorEventListener: onAccuracyChanged() e onSensorChanged(). Il sistema Android chiama questi metodi ogni volta che si verificano le seguenti condizioni:

Il codice seguente mostra come utilizzare il metodo onSensorChanged() per monitorare i dati del sensore di luce. Questo esempio mostra i dati non elaborati del sensore in un TextView che è definito nel file main.xml come sensor_data.

Kotlin

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

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

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor mLight;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

In questo esempio, il ritardo dei dati predefinito (SENSOR_DELAY_NORMAL) viene specificato quando viene invocato il metodo registerListener(). Il ritardo dei dati (o la frequenza di campionamento) controlla l'intervallo a cui gli eventi del sensore vengono inviati all'applicazione tramite il metodo di callback onSensorChanged(). Il ritardo predefinito dei dati è adatto per monitorare le variazioni dell'orientamento dello schermo e utilizza un ritardo di 200.000 microsecondi. Puoi specificare altri ritardi dei dati, ad esempio SENSOR_DELAY_GAME (ritardo di 20.000 microsecondi), SENSOR_DELAY_UI (ritardo di 60.000 microsecondi) o SENSOR_DELAY_FASTEST (ritardo di 0 microsecondi). A partire da Android 3.0 (livello API 11), puoi anche specificare il ritardo come valore assoluto (in microsecondi).

Il ritardo specificato è solo un ritardo suggerito. Il sistema Android e altre applicazioni possono alterare questo ritardo. Come best practice, devi specificare il ritardo più lungo possibile perché il sistema in genere utilizza un ritardo inferiore a quello specificato (ovvero devi scegliere la frequenza di campionamento più lenta che soddisfa comunque le esigenze della tua applicazione). L'utilizzo di un ritardo maggiore impone un carico inferiore sul processore e quindi consuma meno energia.

Non esiste un metodo pubblico per determinare la frequenza con cui il framework del sensore invia gli eventi del sensore alla tua applicazione. Tuttavia, puoi utilizzare i timestamp associati a ciascun evento del sensore per calcolare la frequenza di campionamento su più eventi. Una volta impostata, non dovresti dover modificare la frequenza di campionamento (ritardo). Se per qualche motivo devi modificare il ritardo, dovrai annullare la registrazione e registrare di nuovo il listener del sensore.

È inoltre importante notare che questo esempio utilizza i metodi di callback onResume() e onPause() per registrare e annullare la registrazione dell'ascoltatore di eventi del sensore. Come best practice, devi sempre disattivare i sensori che non ti servono, soprattutto quando la tua attività è in pausa. In caso contrario, la batteria potrebbe scaricarsi in poche ore perché alcuni sensori hanno requisiti di alimentazione elevati e possono consumare rapidamente la batteria. Il sistema non disattiva automaticamente i sensori quando lo schermo si spegne.

Gestione di configurazioni dei sensori diverse

Android non specifica una configurazione standard dei sensori per i dispositivi, il che significa che i produttori possono incorporare qualsiasi configurazione dei sensori che preferiscono nei propri dispositivi Android. Di conseguenza, i dispositivi possono includere una serie di sensori in una vasta gamma di configurazioni. Se la tua applicazione si basa su un tipo specifico di sensore, devi assicurarti che il sensore sia presente su un dispositivo affinché l'app possa funzionare correttamente.

Hai due opzioni per assicurarti che un determinato sensore sia presente su un dispositivo:

  • Rileva i sensori in fase di esecuzione e attiva o disattiva le funzionalità dell'applicazione in base alle esigenze.
  • Utilizza i filtri di Google Play per scegliere come target i dispositivi con configurazioni di sensori specifiche.

Ogni opzione è descritta nelle sezioni seguenti.

Rilevamento dei sensori in fase di esecuzione

Se la tua applicazione utilizza un tipo specifico di sensore, ma non si basa su di esso, puoi utilizzare il framework del sensore per rilevarlo in fase di esecuzione e disattivare o attivare le funzionalità dell'applicazione come appropriato. Ad esempio, un'applicazione di navigazione potrebbe utilizzare il sensore di temperatura, il sensore di pressione, il sensore GPS e il sensore del campo geomagnetico per visualizzare la temperatura, la pressione barometrica, la posizione e la bussola. Se un dispositivo non dispone di un sensore di pressione, puoi utilizzare il framework del sensore per rilevare l'assenza del sensore di pressione in fase di esecuzione e disattivare la parte dell'interfaccia utente dell'applicazione che mostra la pressione. Ad esempio, il seguente codice controlla se su un dispositivo è presente un sensore di pressione:

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Utilizzare i filtri di Google Play per scegliere come target configurazioni di sensori specifiche

Se pubblichi la tua applicazione su Google Play, puoi utilizzare l'elemento <uses-feature> nel file manifest per filtrare l'applicazione dai dispositivi che non dispongono della configurazione del sensore appropriata per la tua applicazione. L'elemento <uses-feature> ha diversi descrittori hardware che ti consentono di filtrare le applicazioni in base alla presenza di sensori specifici. I sensori che puoi elencare includono: accelerometro, barometro, bussola (campo geomagnetico), giroscopio, luce e prossimità. Di seguito è riportato un esempio di voce manifest che filtra le app che non dispongono di un accelerometro:

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

Se aggiungi questo elemento e descrittore al file manifest della tua applicazione, gli utenti vedranno la tua applicazione su Google Play solo se il loro dispositivo è dotato di un accelerometro.

Devi impostare il descrittore su android:required="true" solo se la tua applicazione si basa interamente su un sensore specifico. Se la tua applicazione utilizza un sensore per alcune funzionalità, ma funziona comunque senza il sensore, devi elencarlo nell'elemento <uses-feature>, ma impostare il descrittore su android:required="false". In questo modo, i dispositivi possono installare la tua app anche se non dispongono di quel determinato sensore. Si tratta anche di una best practice di gestione dei progetti che ti aiuta a tenere traccia delle funzionalità utilizzate dalla tua applicazione. Tieni presente che se la tua applicazione utilizza un determinato sensore, ma funziona comunque senza, devi rilevare il sensore in fase di esecuzione e disattivare o attivare le funzionalità dell'applicazione come opportuno.

Sistema di coordinate del sensore

In generale, il framework del sensore utilizza un sistema di coordinate a tre assi standard per esprimere i valori dei dati. Per la maggior parte dei sensori, il sistema di coordinate è definito in base allo schermo del dispositivo quando il dispositivo è tenuto nell'orientamento predefinito (vedi figura 1). Quando un dispositivo è tenuto nell'orientamento predefinito, l'asse X è orizzontale e punta verso destra, l'asse Y è verticale e punta verso l'alto e l'asse Z punta verso l'esterno della superficie dello schermo. In questo sistema, le coordinate dietro lo schermo hanno valori Z negativi. Questo sistema di coordinate è utilizzato dai seguenti sensori:

Figura 1. Sistema di coordinate (rispetto a un dispositivo) utilizzato dall'API Sensor.

L'aspetto più importante da comprendere su questo sistema di coordinate è che gli assi non vengono scambiati quando cambia l'orientamento dello schermo del dispositivo, ovvero il sistema di coordinate del sensore non cambia mai quando il dispositivo si muove. Questo comportamento è lo stesso del sistema di coordinate OpenGL.

Un altro punto da comprendere è che la tua applicazione non deve presumere che l'orientamento naturale (predefinito) di un dispositivo sia verticale. L'orientamento naturale di molti tablet è orizzontale. Inoltre, il sistema di coordinate del sensore si basa sempre sull'orientamento naturale di un dispositivo.

Infine, se la tua applicazione associa i dati del sensore alla visualizzazione sullo schermo, devi utilizzare il metodo getRotation() per determinare la rotazione dello schermo e poi il metodo remapCoordinateSystem() per mappare le coordinate del sensore alle coordinate dello schermo. Devi farlo anche se il manifest specifica la visualizzazione solo in verticale.

Nota:alcuni sensori e metodi utilizzano un sistema di coordinate relativo al sistema di riferimento mondiale (anziché al sistema di riferimento del dispositivo). Questi metodi e sensori restituiscono dati che rappresentano il movimento o la posizione del dispositivo rispetto alla Terra. Per ulteriori informazioni, consulta il metodo getOrientation(), il metodo getRotationMatrix(), Sensore di orientamento e Sensore di vettore di rotazione.

Limitazione di frequenza del sensore

Per proteggere informazioni potenzialmente sensibili sugli utenti, se la tua app ha come target Android 12 (livello API 31) o versioni successive, il sistema impone un limite alla frequenza di aggiornamento dei dati di determinati sensori di movimento e posizione. Questi dati include i valori registrati dall'accelerometro, dal giroscopio e dal sensore di campo magnetico terrestre del dispositivo.

Il limite di frequenza di aggiornamento dipende da come accedi ai dati dei sensori:

Se la tua app deve raccogliere i dati del sensore di movimento a una frequenza più elevata, devi dichiarare l'autorizzazione HIGH_SAMPLING_RATE_SENSORS, come mostrato nello snippet di codice seguente. In caso contrario, se la tua app tenta di raccogliere i dati del sensore di movimento a una frequenza superiore senza dichiarare questa autorizzazione, si verifica un SecurityException.

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

Best practice per accedere ai sensori e utilizzarli

Durante la progettazione dell'implementazione del sensore, assicurati di seguire le linee guida descritte in questa sezione. Queste linee guida sono best practice consigliate per chiunque utilizzi il framework per i sensori per accedere ai sensori e acquisire i dati dei sensori.

Raccogliere i dati dei sensori solo in primo piano

Sui dispositivi con Android 9 (livello API 28) o versioni successive, le app in esecuzione in background sono soggette alle seguenti limitazioni:

  • I sensori che utilizzano la modalità di generazione di report continuo, come accelerometri e giroscopi, non ricevono eventi.
  • I sensori che utilizzano le modalità di generazione dei report on-change o una tantum non ricevono eventi.

Date queste limitazioni, è meglio rilevare gli eventi dei sensori quando la tua app è in primo piano o all'interno di un servizio in primo piano.

Annullare la registrazione degli ascoltatori del sensore

Assicurati di annullare la registrazione dell'ascoltatore di un sensore quando hai finito di utilizzarlo o quando l'attività del sensore viene messa in pausa. Se un ascoltatore del sensore è registrato e la sua attività è in pausa, il sensore continuerà ad acquisire dati e a utilizzare le risorse della batteria, a meno che non lo annulli. Il codice seguente mostra come utilizzare il metodo onPause() per annullare la registrazione di un listener:

Kotlin

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}

Java

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

Per ulteriori informazioni, vedi unregisterListener(SensorEventListener).

Eseguire il test con l'emulatore Android

L'emulatore Android include un insieme di controlli dei sensori virtuali che ti consentono di testare sensori come accelerometro, temperatura ambiente, magnetometro, prossimità, luce e altro ancora.

L'emulatore utilizza una connessione con un dispositivo Android su cui è in esecuzione l'app SdkControllerSensor. Tieni presente che questa app è disponibile solo su dispositivi con Android 4.0 (livello API 14) o versioni successive. Se il dispositivo è in esecuzione su Android 4.0, deve essere installata la revisione 2. L'app SdkControllerSensor monitora le modifiche ai sensori sul dispositivo e le trasmette all'emulatore. L'emulatore viene poi trasformato in base ai nuovi valori ricevuti dai sensori sul tuo dispositivo.

Puoi visualizzare il codice sorgente dell'app SdkControllerSensor nella seguente posizione:

$ your-android-sdk-directory/tools/apps/SdkController

Per trasferire i dati tra il dispositivo e l'emulatore, segui questi passaggi:

  1. Verifica che il debug USB sia abilitato sul dispositivo.
  2. Collega il dispositivo alla macchina di sviluppo con un cavo USB.
  3. Avvia l'app SdkControllerSensor sul tuo dispositivo.
  4. Nell'app, seleziona i sensori che vuoi emulare.
  5. Esegui questo comando adb:

  6. $ adb forward tcp:1968 tcp:1968
    
  7. Avvia l'emulatore. Ora dovresti essere in grado di applicare trasformazioni all'emulatore muovendo il dispositivo.

Nota: se i movimenti che effettui sul dispositivo fisico non trasformano l'emulatore, prova a eseguire di nuovo il comando adb del passaggio 5.

Per ulteriori informazioni, consulta la guida all'emulatore Android.

Non bloccare il metodo onSensorChanged()

I dati dei sensori possono cambiare a una frequenza elevata, il che significa che il sistema potrebbe chiamare il metodo onSensorChanged(SensorEvent) abbastanza spesso. Come best practice, dovresti fare il meno possibile all'interno del metodo onSensorChanged(SensorEvent) per non bloccarlo. Se la tua applicazione richiede di filtrare o ridurre i dati dei sensori, devi eseguire questa operazione al di fuori del metodo onSensorChanged(SensorEvent).

Evita di utilizzare metodi o tipi di sensori deprecati

Diversi metodi e costanti sono stati ritirati. In particolare, il tipo di sensore TYPE_ORIENTATION è stato ritirato. Per ottenere i dati sull'orientamento, devi utilizzare il metodo getOrientation(). Analogamente, il tipo di sensore TYPE_TEMPERATURE è stato ritirato. Devi utilizzare il tipo di sensore TYPE_AMBIENT_TEMPERATURE sui dispositivi con Android 4.0.

Verifica i sensori prima di utilizzarli

Verifica sempre che un sensore esista su un dispositivo prima di tentare di acquisire dati. Non assumere che un sensore esista semplicemente perché è un sensore di uso frequente. I produttori di dispositivi non sono tenuti a fornire sensori specifici nei loro dispositivi.

Scegli con attenzione i ritardi dei sensori

Quando registri un sensore con il metodo registerListener(), assicurati di scegliere una frequenza di invio adatta alla tua applicazione o al tuo caso d'uso. I sensori possono fornire dati a velocità molto elevate. Se consenti al sistema di inviare dati aggiuntivi che non ti servono, sprechi risorse di sistema e consumi la batteria.