Codelab sull'API Activity Recognition Transition

1. Introduzione

Portiamo con noi gli smartphone ovunque, ma finora è stato difficile per le app adattare la loro esperienza all'ambiente e all'attività in continua evoluzione di un utente.

In passato, gli sviluppatori dedicavano tempo prezioso a combinare vari segnali (posizione, sensore e così via) per determinare l'inizio o la fine di un'attività come camminare o guidare. Ancora peggio, quando le app controllano in modo indipendente e continuo le modifiche all'attività utente, la durata della batteria ne risente.

L'API Activity Recognition Transition risolve questi problemi fornendo un'API semplice che esegue tutta l'elaborazione per te e ti comunica solo ciò che ti interessa davvero: quando l'attività di un utente è cambiata. La tua app si iscrive semplicemente a una transizione nelle attività che ti interessano e l'API ti avvisa delle modifiche

Ad esempio, un'app di messaggistica può chiedere "dimmi quando l'utente è entrato o uscito da un veicolo" per impostare lo stato dell'utente su occupato. Analogamente, un'app di rilevamento del parcheggio può chiedere:"dimmi quando l'utente è uscito da un veicolo e ha iniziato a camminare", per salvare la posizione di parcheggio dell'utente.

In questo codelab imparerai a utilizzare l'API Activity Recognition Transition per determinare quando un utente inizia/interrompe un'attività come camminare o correre.

Prerequisiti

Familiarità con lo sviluppo per Android e con i callback.

Obiettivi didattici

  • Registrazione delle transizioni di attività
  • Elaborazione di questi eventi
  • Annullare la registrazione delle transizioni di attività quando non sono più necessarie

Che cosa ti serve

  • Android Studio Bumblebee
  • Un dispositivo o un emulatore Android

2. Per iniziare

Clona il repository del progetto iniziale

Per aiutarti a iniziare il prima possibile, abbiamo preparato un progetto iniziale su cui puoi basarti. Se hai installato git, puoi semplicemente eseguire il comando riportato di seguito. Puoi verificarlo digitando git --version nel terminale / riga di comando e controllando che venga eseguito correttamente.

 git clone https://github.com/android/codelab-activity_transitionapi

Se non hai git, puoi scaricare il progetto come file ZIP:

Importare il progetto

Avvia Android Studio, seleziona "Apri un progetto Android Studio esistente" dalla schermata di benvenuto e apri la directory del progetto.

Una volta caricato il progetto, potresti anche visualizzare un avviso che indica che Git non sta monitorando tutte le modifiche locali. Puoi fare clic su "Ignora" o sulla "X" in alto a destra. Non verrà eseguito il push di alcuna modifica nel repository Git.

Nell'angolo in alto a sinistra della finestra del progetto, dovresti vedere un'immagine simile a quella riportata di seguito se ti trovi nella visualizzazione Android. Se ti trovi nella visualizzazione Progetto, devi espandere il progetto per visualizzare la stessa cosa.

d2363db913d8e5ad.png

Sono presenti due icone di cartella (base e complete). Ognuna di queste è nota come "modulo".

Tieni presente che Android Studio potrebbe impiegare diversi secondi per compilare il progetto in background per la prima volta. Durante questo periodo, nella barra di stato in fondo ad Android Studio vedrai un indicatore di caricamento:

c9f23d5336be3cfe.png

Ti consigliamo di attendere il completamento dell'operazione prima di apportare modifiche al codice. In questo modo, Android Studio potrà recuperare tutti i componenti necessari.

Inoltre, se viene visualizzato il messaggio "Ricaricare per applicare le modifiche alla lingua?" o un messaggio simile, seleziona "Sì".

Informazioni sul progetto iniziale

Bene, la configurazione è completata e puoi aggiungere il riconoscimento dell'attività. Utilizzeremo il modulo base, che è il punto di partenza di questo codelab. In altre parole, aggiungerai il codice di ogni passaggio a base.

Il modulo complete può essere utilizzato per controllare il tuo lavoro o come riferimento in caso di problemi.

Panoramica dei componenti chiave:

  • MainActivity: Contiene tutto il codice necessario per il riconoscimento dell'attività.

Configurazione dell'emulatore

Se hai bisogno di aiuto per configurare un emulatore Android, consulta l'articolo Eseguire l'app.

Esegui il progetto iniziale

Eseguiamo la nostra app.

  • Collega il dispositivo Android al computer o avvia un emulatore.
  • Nella barra degli strumenti, seleziona la configurazione base dal selettore a discesa e fai clic sul triangolo verde (Esegui) accanto:

a640a291ffaf62ad.png

  • Dovresti vedere l'applicazione di seguito:

f58d4bb92ee77f41.png

  • L'app ora non fa altro che stampare un messaggio. Ora aggiungeremo il riconoscimento dell'attività.

Riepilogo

In questo passaggio hai imparato:

  • Configurazione generale per il codelab.
  • Le nozioni di base della nostra app.
  • Come eseguire il deployment dell'app.

3. Esamina la libreria e aggiungi l'autorizzazione al manifest

Per utilizzare l'API Transition nella tua app, devi dichiarare una dipendenza dall'API Google Location and Activity Recognition e specificare l'autorizzazione com.google.android.gms.permission.ACTIVITY_RECOGNITION nel file manifest dell'app.

  1. Cerca TODO: Review play services library required for activity recognition nel file build.gradle. Non è richiesta alcuna azione per questo passaggio (passaggio 1), ma devi esaminare la dipendenza dichiarata che richiediamo. Dovrebbe avere il seguente aspetto:
    // TODO: Review play services library required for activity recognition.
    implementation 'com.google.android.gms:play-services-location:19.0.1'
  1. Nel modulo base, cerca TODO: Add both activity recognition permissions to the manifest in AndroidManifest.xml e aggiungi il codice riportato di seguito all'elemento <manifest>.
<!-- TODO: Add both activity recognition permissions to the manifest. -->
<!-- Required for 28 and below. -->
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

Il codice dovrebbe ora essere simile a questo:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.myapp">
<!-- TODO: Add both activity recognition permissions to the manifest. -->
<!-- Required for 28 and below. -->
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

  ...
</manifest>

Come puoi vedere dai commenti, devi aggiungere una seconda autorizzazione per Android 10. Questo è necessario per l'autorizzazione runtime aggiunta nella versione 29 dell'API.

È tutto. La tua app ora può supportare il riconoscimento dell'attività, dobbiamo solo aggiungere il codice per ottenerlo.

App Corsa

Esegui l'app da Android Studio. Dovrebbe avere esattamente lo stesso aspetto. Non abbiamo ancora aggiunto alcun codice per monitorare le transizioni, lo faremo nella sezione successiva.

4. Controllo/richiesta delle autorizzazioni di runtime in Android

Sebbene la nostra copertura per l'autorizzazione sia valida per la versione 28 e precedenti dell'API, dobbiamo supportare le autorizzazioni di runtime nella versione 29 e successive dell'API:

  • In MainActivity.java, verificheremo se l'utente utilizza Android 10 (29) o versioni successive e, in caso affermativo, controlleremo le autorizzazioni di riconoscimento dell'attività.
  • Se le autorizzazioni non vengono concesse, l'utente verrà indirizzato a una schermata iniziale (PermissionRationalActivity.java) che spiega perché l'app ha bisogno dell'autorizzazione e gli consente di approvarla.

Esaminare il codice per controllare la versione di Android

Nel modulo base, cerca TODO: Review check for devices with Android 10 (29+) in MainActivity.java. Dovresti visualizzare questo snippet di codice.

Tieni presente che non è prevista alcuna azione per questa sezione.

// TODO: Review check for devices with Android 10 (29+).
private boolean runningQOrLater =
    android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;

Come detto in precedenza, devi ottenere l'approvazione per l'autorizzazione runtime android.permission.ACTIVITY_RECOGNITION in Android 10 e versioni successive. Utilizziamo questo semplice controllo per decidere se dobbiamo controllare le autorizzazioni di runtime.

Se necessario, esamina il controllo delle autorizzazioni di runtime per il riconoscimento dell'attività

Nel modulo base, cerca TODO: Review permission check for 29+ in MainActivity.java. Dovresti visualizzare questo snippet di codice.

Tieni presente che non è prevista alcuna azione per questa sezione.

// TODO: Review permission check for 29+.
if (runningQOrLater) {

   return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
           this,
           Manifest.permission.ACTIVITY_RECOGNITION
   );
} else {
   return true;
}

Utilizziamo la variabile creata nel passaggio precedente per verificare se dobbiamo controllare le autorizzazioni di runtime.

Per Android Q e versioni successive, controlliamo e restituiamo il risultato per l'autorizzazione di runtime. Fa parte di un metodo più ampio chiamato activityRecognitionPermissionApproved(), che consente allo sviluppatore di sapere con una semplice chiamata se è necessario richiedere un'autorizzazione o meno.

Richiedere le autorizzazioni di runtime e attivare/disattivare le transizioni di riconoscimento dell'attività

Nel modulo base, cerca TODO: Enable/Disable activity tracking and ask for permissions if needed in MainActivity.java. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Enable/Disable activity tracking and ask for permissions if needed.
if (activityRecognitionPermissionApproved()) {

   if (activityTrackingEnabled) {
      disableActivityTransitions();

   } else {
      enableActivityTransitions();
   }

} else {  
   // Request permission and start activity for result. If the permission is approved, we
   // want to make sure we start activity recognition tracking.
   Intent startIntent = new Intent(this, PermissionRationalActivity.class);
   startActivityForResult(startIntent, 0);

}

Qui chiediamo se il riconoscimento dell'attività è approvato. Se è così e il riconoscimento dell'attività è già attivato, lo disattiviamo. In caso contrario, lo attiviamo.

Nel caso in cui l'autorizzazione non venga approvata, l'utente viene indirizzato alla schermata iniziale che spiega perché abbiamo bisogno dell'autorizzazione e gli consente di attivarla.

Esamina il codice di richiesta di autorizzazione

Nel modulo base, cerca TODO: Review permission request for activity recognition in PermissionRationalActivity.java. Dovresti visualizzare questo snippet di codice.

Tieni presente che non è prevista alcuna azione per questa sezione.

// TODO: Review permission request for activity recognition.
ActivityCompat.requestPermissions(
             this,
             new String[]{Manifest.permission.ACTIVITY_RECOGNITION},
             PERMISSION_REQUEST_ACTIVITY_RECOGNITION)

Questa è la parte più importante dell'attività e quella da esaminare. Il codice attiva la richiesta di autorizzazione quando l'utente la richiede.

Al di fuori di questo, la classe PermissionRationalActivity.java mostra una motivazione per cui l'utente dovrebbe approvare l'autorizzazione di riconoscimento dell'attività (best practice). L'utente può fare clic sul pulsante No, grazie o sul pulsante Continua (che attiva il codice riportato sopra).

Se vuoi saperne di più, puoi consultare il file.

5. Registra/Annulla la registrazione del ricevitore per le transizioni di attività

Prima di configurare il codice di riconoscimento dell'attività, vogliamo assicurarci che la nostra attività possa gestire le azioni di transizione generate dal sistema.

Crea un BroadcastReceiver per la transizione

Nel modulo base, cerca TODO: Create a BroadcastReceiver to listen for activity transitions in MainActivity.java. Incolla lo snippet riportato di seguito.

// TODO: Create a BroadcastReceiver to listen for activity transitions.
// The receiver listens for the PendingIntent above that is triggered by the system when an
// activity transition occurs.
mTransitionsReceiver = new TransitionsReceiver();

Registra un BroadcastReceiver per la transizione

Nel modulo base, cerca TODO: Register a BroadcastReceiver to listen for activity transitions in MainActivity.java. Si trova in onStart(). Incolla lo snippet riportato di seguito.

// TODO: Register a BroadcastReceiver to listen for activity transitions.
registerReceiver(mTransitionsReceiver, new IntentFilter(TRANSITIONS_RECEIVER_ACTION));

Ora abbiamo un modo per ricevere aggiornamenti quando le transizioni di attività vengono generate tramite PendingIntent.

Unregister BroadcastReceiver

Nel modulo base, cerca Unregister activity transition receiver when user leaves the app in MainActivity.java. (Si trova in onStop()).Incolla lo snippet riportato di seguito.

// TODO: Unregister activity transition receiver when user leaves the app.
unregisterReceiver(mTransitionsReceiver);

La best practice prevede di annullare la registrazione di un destinatario quando Activity si sta spegnendo.

6. Configurare le transizioni di attività e richiedere aggiornamenti

Per iniziare a ricevere aggiornamenti sulla transizione dell'attività, devi implementare:

Crea un elenco di transizioni di attività da seguire

Per creare l'oggetto ActivityTransitionRequest, devi creare un elenco di oggetti ActivityTransition, che rappresentano la transizione che vuoi monitorare. Un oggetto ActivityTransition include i seguenti dati:

  1. Un tipo di attività, rappresentato dalla classe DetectedActivity. L'API Transition supporta le seguenti attività:
  1. Un tipo di transizione, rappresentato dalla classe ActivityTransition. I tipi di transizione sono:

Nel modulo base, cerca TODO: Add activity transitions to track in MainActivity.java. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Add activity transitions to track.
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.WALKING)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.WALKING)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.STILL)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.STILL)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
        .build());

Questo codice aggiunge le transizioni che vogliamo monitorare a un elenco precedentemente vuoto.

Crea un PendingIntent

Come indicato in precedenza, abbiamo bisogno di un PendingIntent se vogliamo ricevere avvisi per eventuali modifiche alla nostra ActivityTransitionRequest, quindi prima di configurare la nostra ActivityTransitionRequest, dobbiamo creare un PendingIntent.

Nel modulo base, cerca TODO: Initialize PendingIntent that will be triggered when a activity transition occurs in MainActivity.java. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Initialize PendingIntent that will be triggered when a activity transition occurs.
Intent intent = new Intent(TRANSITIONS_RECEIVER_ACTION);
mActivityTransitionsPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);

Ora abbiamo un PendingIntent che possiamo attivare quando si verifica una delle ActivityTransition.

Crea una ActivityTransitionRequest e richiedi aggiornamenti

Puoi creare un oggetto ActivityTransitionRequest passando l'elenco di ActivityTransition alla classe ActivityTransitionRequest.

Nel modulo base, cerca Crea richiesta e ascolta le modifiche all'attività in MainActivity.java. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Create request and listen for activity changes.
ActivityTransitionRequest request = new ActivityTransitionRequest(activityTransitionList);

// Register for Transitions Updates.
Task<Void> task =
        ActivityRecognition.getClient(this)
                .requestActivityTransitionUpdates(request, mActivityTransitionsPendingIntent);


task.addOnSuccessListener(
        new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                activityTrackingEnabled = true;
                printToScreen("Transitions Api was successfully registered.");

            }
        });
task.addOnFailureListener(
        new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions Api could NOT be registered: " + e);
                Log.e(TAG, "Transitions Api could NOT be registered: " + e);

            }
        });

Esaminiamo il codice. Innanzitutto, creiamo un ActivityTransitionRequest dal nostro elenco di transizioni di attività.

ActivityTransitionRequest request = new ActivityTransitionRequest(activityTransitionList);

Successivamente, ci registriamo per gli aggiornamenti della transizione di attività passando la tua istanza di ActivityTransitionRequest e il nostro oggetto PendingIntent creato nel passaggio precedente al metodo requestActivityTransitionUpdates(). Il metodo requestActivityTransitionUpdates() restituisce un oggetto Task che puoi controllare per verificare se l'operazione è riuscita o meno, come mostrato nel blocco di codice successivo:

// Register for Transitions Updates.
Task<Void> task =
        ActivityRecognition.getClient(this)
                .requestActivityTransitionUpdates(request, mActivityTransitionsPendingIntent);


task.addOnSuccessListener(
        new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                activityTrackingEnabled = true;
                printToScreen("Transitions Api was successfully registered.");

            }
        });
task.addOnFailureListener(
        new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions Api could NOT be registered: " + e);
                Log.e(TAG, "Transitions Api could NOT be registered: " + e);

            }
        });

Dopo aver eseguito la registrazione per gli aggiornamenti sulla transizione dell'attività, la tua app riceve notifiche nell'intent in attesa registrato. Abbiamo anche impostato una variabile che indica che il monitoraggio dell'attività è attivo, in modo da sapere se disattivarlo/attivarlo se l'utente fa di nuovo clic sul pulsante.

Rimuovere gli aggiornamenti alla chiusura dell'app

È importante rimuovere gli aggiornamenti della transizione quando l'app si chiude.

Nel modulo base, cerca Interrompi l'ascolto delle modifiche all'attività in MainActivity.java. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Stop listening for activity changes.
ActivityRecognition.getClient(this).removeActivityTransitionUpdates(mActivityTransitionsPendingIntent)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                activityTrackingEnabled = false;
                printToScreen("Transitions successfully unregistered.");
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions could not be unregistered: " + e);
                Log.e(TAG,"Transitions could not be unregistered: " + e);
            }
        });

Ora dobbiamo chiamare il metodo contenente il codice precedente quando l'app si chiude

Nel modulo base, cerca TODO: Disable activity transitions when user leaves the app in MainActivity.java in onPause(). Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Disable activity transitions when user leaves the app.
if (activityTrackingEnabled) {
    disableActivityTransitions();
}

Questo è tutto per il monitoraggio delle modifiche alle transizioni di attività. Ora dobbiamo solo elaborare gli aggiornamenti.

7. Eventi di elaborazione

Quando si verifica la transizione di attività richiesta, la tua app riceve un callback Intent. Un oggetto ActivityTransitionResult può essere estratto dall'intent, che include un elenco di oggetti ActivityTransitionEvent. Gli eventi sono ordinati in ordine cronologico. Ad esempio, se un'app richiede il tipo di attività IN_VEHICLE nelle transizioni ACTIVITY_TRANSITION_ENTER e ACTIVITY_TRANSITION_EXIT, riceve un oggetto ActivityTransitionEvent quando l'utente inizia a guidare e un altro quando passa a un'altra attività.

Aggiungiamo il codice per gestire questi eventi.

Nel modulo base, cerca TODO: Extract activity transition information from listener in MainActivity.java in onReceive() di BroadcastReceiver che abbiamo creato in precedenza. Aggiungi il codice riportato di seguito dopo il commento.

// TODO: Extract activity transition information from listener.
if (ActivityTransitionResult.hasResult(intent)) {

    ActivityTransitionResult result = ActivityTransitionResult.extractResult(intent);

    for (ActivityTransitionEvent event : result.getTransitionEvents()) {

        String info = "Transition: " + toActivityString(event.getActivityType()) +
                " (" + toTransitionType(event.getTransitionType()) + ")" + "   " +
                new SimpleDateFormat("HH:mm:ss", Locale.US).format(new Date());

        printToScreen(info);
    }
}

In questo modo le informazioni verranno convertite in un String e stampate sullo schermo.

È tutto, hai finito. Prova a eseguire l'app.

NOTA IMPORTANTE: è difficile riprodurre le modifiche all'attività sull'emulatore, pertanto ti consigliamo di utilizzare un dispositivo fisico.

Dovresti essere in grado di monitorare le modifiche all'attività.

Per risultati ottimali, installa l'app su un dispositivo fisico e cammina. :)

8. Esamina il codice

Hai creato un'app semplice che monitora le transizioni di attività e le elenca sullo schermo.

Non esitare a leggere il codice per intero per rivedere ciò che hai fatto e farti un'idea migliore di come funziona.