Autore Topic: Utilizzo del sensore contapasso di Android Kitkat  (Letto 3149 volte)

Offline Reinhard

  • Utente junior
  • **
  • Post: 85
  • Respect: +16
    • Google+
    • rspisser
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5 Lollipop 5.1
  • Play Store ID:
    rspisser
  • Sistema operativo:
    Windows 7
Utilizzo del sensore contapasso di Android Kitkat
« il: 31 Gennaio 2014, 14:06:39 CET »
+1

Livello di difficoltà: facile
Target SDK: 19
Min SDK: 19


Una delle novità di Android KitKat 4.4 passata in sordina è l'introduzione delle API per i contapassi.
Google ha sviluppato un hardware dedicato per riconoscere i passi e ha aggiunto delle API in KitKat e sta lavorando con i vari produttori di smartphone affinché questi utilizzino questo hardware sui loro dispositivi.

Ad oggi i device che supportano il contapassi - e quindi includono l'hardware sviluppato da google - sono: Nexus 5, LG G2, Motorola Moto X, Samsung Galaxy S4, Galaxy Note 3, Galaxy Tab Pro 8.4, Galaxy Round.

Le nuove API sono implementate tramite due tipologie di sensori che permettono di rilevare ogni singolo passo (stepdetector) oppure rilevare cambiamenti nel contatore globale degli step (stepcounter).

Le differenze tra i due sensori:
  • stepdetector
    Lo stepdetector chiama il metodo onSensorChanged() ogni volta che viene rilevato un passo. Il calcolo del numero dei passi è a carico del programma.
  • stepcounter
    Lo step counter conta i passi effettuati dal ultimo reboot e chiama il metodo onSensorChanged() ogni volta che c'e' un cambio nel numero di passi. Questo metodo è più preciso dello stepdetector, contiene anche algoritmi per eliminare falsi positivi.

In questo tutorial vedremo come utilizzare lo stepcounter e come calcolare quanti passi vengono fatti giornalmente.

Per prima cosa impostiamo il sdk minimo a 19 (KitKat) nel Manifest:

Codice (XML): [Seleziona]
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />

dichiariamo  l'utilizzo del sensore stepcounter:

Codice (XML): [Seleziona]
<uses-feature android:name="android.hardware.sensor.stepcounter" />
Nella activity registriamo il SensorListener:

Codice (Java): [Seleziona]
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
if (sensor != null) {
        sensorManager.registerListener(mySensorEventListener, sensor,
        SensorManager.SENSOR_DELAY_NORMAL);
} else {
        Log.e("MainActivity", "Not registerered for Stepcounter Sensor");
        Toast.makeText(this, "stepcounter Sensor not found",
        Toast.LENGTH_LONG).show();
        finish();
}
   
e defininiamo un Listener:   
   
Codice (Java): [Seleziona]
private SensorEventListener mySensorEventListener = new SensorEventListener() {

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

@Override
public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {

                // i dati che ci interessano sono passati in event
               
                // timestamp del evento
                Calendar currentTimeStamp = Calendar.getInstance();
                currentTimeStamp.setTimeInMillis(event.timestamp / 1000000);
                                       
                // il numero di passi totali
                int currentStepCount = (int) event.values[0];

                }
        }
}      

abbiamo visto che il SensorEvent ci restituisce il numero di passi totali e il timestamp del ultimo passo.

Per sapere quanti passi sono stati fatti oggi è necessario un po' di logica. Dobbiamo confrontare il timestamp del passo precedente
con quello attuale e se è cambiato giorno, far partire da zero il contatore dei passi. 

Codice (Java): [Seleziona]
if (currentStepCount == 0) {
        todayOffset = 0;
        previousStepTimeStamp = currentTimeStamp.getTimeInMillis();
}

Log.d(TAG, "new stepcount: " + currentStepCount);
/* controlliamo se è cambiato giorno */
Calendar current = Calendar.getInstance();
current.setTime(actualTimeStamp.getTime());
current.set(Calendar.HOUR_OF_DAY, 0);
current.set(Calendar.MINUTE, 0);
current.set(Calendar.SECOND, 0);
current.set(Calendar.MILLISECOND, 0);

Calendar previous = Calendar.getInstance();
previous.setTimeInMillis(previousStepTimeStamp);
previous.set(Calendar.HOUR_OF_DAY, 0);
previous.set(Calendar.MINUTE, 0);
previous.set(Calendar.SECOND, 0);
previous.set(Calendar.MILLISECOND, 0);

if (current.after(previous)) {
        Log.d(TAG, "new day: " + format1.format(current.getTime())
                + "\n" + format1.format(previous.getTime()));

        todayOffset = (int) event.values[0];
        todayStepsCount = 0;

}

todayStepsCount = currentStepCount - todayOffset;
previousStepTimeStamp = actualTimeStamp.getTimeInMillis();

Sorgenti:
AndroidManifest.xml

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="it.spisser.android.contapassi"
   android:versionCode="1"
   android:versionName="0.1" >

    <uses-sdk
       android:minSdkVersion="19"
       android:targetSdkVersion="19" />

    <uses-feature android:name="android.hardware.sensor.stepcounter" />
   
    <application
       android:allowBackup="true"
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >
        <activity
           android:name="it.spisser.android.contapassi.MainActivity"
           android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity.java

Codice (Java): [Seleziona]
package it.spisser.android.contapassi;

import java.text.SimpleDateFormat;
import java.util.Calendar;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

        private static final String TAG = "MainActivity";

        private SensorManager sensorManager;
        private Sensor sensor;

        // numero di passi oggi
        private int todayStepsCount = 0;
        // numero di passi fino a mezzanotte
        private int todayOffset = -1;

        private long previousStepTimeStamp = 0;

        private TextView numberOfStepsView;
        private TextView numberOfTotalStepsView;

        SharedPreferences settings;

        @Override
        public void onSaveInstanceState(Bundle savedInstanceState) {

                super.onSaveInstanceState(savedInstanceState);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                setContentView(R.layout.contapassi);

                sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
                sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

                if (sensor != null) {
                        sensorManager.registerListener(mySensorEventListener, sensor,
                                        SensorManager.SENSOR_DELAY_NORMAL);
                        Log.i("MainActivity", "Registerered for stepcounter Sensor");

                } else {
                        Log.e("MainActivity", "Registerered for Stepcounter Sensor");
                        Toast.makeText(this, "stepcounter Sensor not found",
                                        Toast.LENGTH_LONG).show();
                        finish();
                }

                // recuperiamo i dati dalle shared preferences
                settings = getSharedPreferences("myapp", MODE_PRIVATE);
                todayOffset = settings.getInt("todayOffset", -1);
                todayStepsCount = settings.getInt("TodayStepsCount", -1);
                previousStepTimeStamp = settings.getLong("previousStepTimeStamp", -1);

                numberOfStepsView = (TextView) findViewById(R.id.numberOfSteps);
                numberOfTotalStepsView = (TextView) findViewById(R.id.numberTotalSteps);
                numberOfStepsView.setText(" " + todayStepsCount);

        }

        @Override
        protected void onStop() {
                super.onStop();

                SharedPreferences settings = getSharedPreferences("myapp", 0);
                SharedPreferences.Editor editor = settings.edit();

                editor.putInt("todayOffset", todayOffset);
                editor.putInt("todayStepsCount", todayStepsCount);
                editor.putLong("previousStepTimeStamp", previousStepTimeStamp);

                editor.commit();
        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
                if (sensor != null) {
                        sensorManager.unregisterListener(mySensorEventListener);
                }
        }

        private SensorEventListener mySensorEventListener = new SensorEventListener() {

                @Override
                public void onAccuracyChanged(Sensor sensor, int accuracy) {
                }

                @Override
                public void onSensorChanged(SensorEvent event) {

                        SimpleDateFormat format1 = new SimpleDateFormat(
                                        "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                        Calendar actualTimeStamp = Calendar.getInstance();
                        Log.d(TAG, "trigger evento");
                        if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {

                                Calendar currentTimeStamp = Calendar.getInstance();
                                currentTimeStamp.setTimeInMillis(event.timestamp / 1000000);

                                int currentStepCount = (int) event.values[0];

                                if (currentStepCount == 0) {
                                        /*
                                         * abbiamo appena avuto un reboot oppure si parte da 0
                                         */

                                        todayOffset = 0;
                                        previousStepTimeStamp = currentTimeStamp.getTimeInMillis();
                                }

                                Log.d(TAG, "new stepcount: " + currentStepCount);
                                /* controlliamo se è cambiato giorno */
                                Calendar current = Calendar.getInstance();
                                current.setTime(actualTimeStamp.getTime());
                                current.set(Calendar.HOUR_OF_DAY, 0);
                                current.set(Calendar.MINUTE, 0);
                                current.set(Calendar.SECOND, 0);
                                current.set(Calendar.MILLISECOND, 0);

                                Calendar previous = Calendar.getInstance();
                                previous.setTimeInMillis(previousStepTimeStamp);
                                previous.set(Calendar.HOUR_OF_DAY, 0);
                                previous.set(Calendar.MINUTE, 0);
                                previous.set(Calendar.SECOND, 0);
                                previous.set(Calendar.MILLISECOND, 0);

                                todayStepsCount++;
                                if (current.after(previous)) {
                                        Log.d(TAG, "new day: " + format1.format(current.getTime())
                                                        + "\n" + format1.format(previous.getTime()));

                                        todayOffset = (int) event.values[0];
                                        todayStepsCount = 0;

                                }
                                todayStepsCount = currentStepCount - todayOffset;

                                previousStepTimeStamp = actualTimeStamp.getTimeInMillis();

                                numberOfStepsView.setText(" " + todayStepsCount);
                                numberOfTotalStepsView.setText(" " + currentStepCount);

                                /* fine controlliamo se è cambiato giorno */

                        }

                }
        };

}

file layout contapassi.xml:
Codice (XML): [Seleziona]
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:background="@android:color/background_dark"
   android:gravity="fill_horizontal"
   android:orientation="vertical"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context=".MainActivity" >

    <TextView
       android:id="@+id/numberOfSteps"
       style="@style/StepCountTodayValue"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text=""
       android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
       android:id="@+id/numberOfStepsString"
       style="@style/StepCountTodayText"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="@string/todaySteps"
       android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
       android:id="@+id/numberTotalSteps"
       style="@style/StepCountTotalValue"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text=""
       android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
       android:id="@+id/numberTotalSteps"
       style="@style/StepCountTotalText"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="@string/totalSteps"
       android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

Un esempio completo è disponibile su github: https://github.com/rspisser/contapassi


Bibliografia:

Offline robyrocker89

  • Utente junior
  • **
  • Post: 55
  • Respect: +1
    • roberto-tucci
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Sistema operativo:
    Windows
Re:Utilizzo del sensore contapasso di Android Kitkat
« Risposta #1 il: 01 Gennaio 2015, 21:05:48 CET »
0
Grazie mille!! Bel tutorial!  :-)
TimeReport: your time. In your pocket.

Offline Damiani Programmer

Re:Utilizzo del sensore contapasso di Android Kitkat
« Risposta #2 il: 09 Ottobre 2015, 13:55:40 CEST »
0
Funziona anche su Android Lollipop?
DAMIANI PROGRAMMER: TANTE APPLICAZIONI PER ANDROID!

www.facebook.com/damianiprogrammer