giovedì 9 gennaio 2014

GPS Tracking e batteria in Android

Sto sviluppando una applicazione per effettuare il tracciamento di escursionisti (a piedi ed in ambiente di montagna) per cui una delle caratteristiche richieste e' la lunga durata della batteria
Normalmente un cellulare Android con batteria completamente carica non riesce a tracciare piu' di 5 ore di percorso, un tempo scarsino per una escursione dato che mediamente di parla di 6-9 ore

Una soluzione che sto valutando e' quello di non tracciare con continuita' ma di accendere l'antenna GPS per un minuto (tempi inferiori non garantiscono che ci sia il fix del punto Gps) e che rimanga spenta un tempo prestabilito (diciamo 4-5 minuti che a piedi con velocita' uguale od inferiore a 5 Km/h corrisponde ad un punto ogni 400 m). In tale modo non si ha la traccia del sentiero ma si ha sempre la posizione  sul percorso
(l'applicazione nella versione definitiva dovrebbe una applicaizone orientata al soccorso)

Una prima prova e' stata effettuata con il programma riportato al termine del post: i punti sono stati acquisiti ogni 4 minuti (durante la prova lo spostamento e' stato effettuato in macchina quindi le acquisizioni sono molto distanziate)
In giallo i punti acquisiti
ed ecco la tabella delle acquisizioni con i tempi



Il programma implementa un Timer (che scatta ogni minuto) ed un Location Manager.
Quando il numero di cicli del timer (variabile contatore) e' un multiplo di 5 viene attivato il Location Manager altrimenti vengono disattivate le update dallo stesso manager (e viene spenta l'antenna)
Semplice ma funzionale
----------------------------------------------------------
package com.test.tempo;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.WindowManager;

public class MainActivity extends Activity {

private Timer t;
private TimerTask task;
private LocationManager mlocManager;
private MyLocationListener mlocListener;
private double contatore;
public String tempo_gps;
public double latitudine;
public double longitudine;
public long old_time;
public boolean gps_fix;
public long tempo;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//mantiene lo schermo attivo 
   getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

contatore = 0;

//GESTIONE DEL GPS
mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
        mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        // se il GPS non e' abilitato richiede l'intervento dell'utente
        if (!mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
        }

//GESTIONE DEL TIMER
        t = new Timer();     
   task = new TimerTask() {  
   @Override  
     public void run() {  
    runOnUiThread(new Runnable() {  
   @Override  
   public void run() {  
    //nella variabile contatore ci sono i minuti trascorsi
    contatore = contatore+1;
    //se i minuti sono divisibili per 5 allora si acquisisce per un minuto la posizione
    //acquisisce anche al primo ciclo per inizializzare il GPS
    if (((contatore % 5) == 0) || (contatore == 0))
    {
    //abilita GPS
       mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
    }
    else
    {
    //disabilita GPS
    mlocManager.removeUpdates(mlocListener);
    }
         
     }  //fine run
    });  
   }  
  };
  //il timer scatta una volta ogni 60 secondi
  t.scheduleAtFixedRate(task, 0, 60000);
  // FINE DELLA GESTIONE DEL TIMER
}

public class MyLocationListener implements LocationListener
    {


@Override
    public void onLocationChanged(Location loc)
    {
    latitudine = loc.getLatitude();
    longitudine = loc.getLongitude();
    tempo = loc.getTime();
    
    // e' considerato di avere il fix gps se non ci sono piu' di 5 secondi
    // tra due letture consecutive
    if ((tempo-old_time < 5000) && (old_time > 0))
    {
            gps_fix = true;
            Date date = new Date(tempo);
            SimpleDateFormat format = new SimpleDateFormat("dd/MM/yy HH:mm:ss zzz a");
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            tempo_gps = format.format(date);
            salva();
    }
    old_time = tempo;
    }


    @Override
    public void onProviderDisabled(String provider)
    {
    gps_fix = false;
    }


    @Override
    public void onProviderEnabled(String provider)
    {
    gps_fix = false;
    }


@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub

}
  }



//all'uscita dall'applicazione spenge il timer ed il GPS
protected void onDetroy()
{
super.onDestroy();
t.cancel();  
   t.purge();  
        mlocManager.removeUpdates(mlocListener);
}


private void salva()
// salva i dati su file
   {
            try {
                   File root = Environment.getExternalStorageDirectory();
                   if (root.canWrite()){
                       File data_file = new File(root, "sart.txt");
                       FileWriter data_file_writer= new FileWriter(data_file,true);
                       BufferedWriter out = new BufferedWriter(data_file_writer);
                            out.write(Double.toString(latitudine)+";"+Double.toString(longitudine)+";"+tempo_gps+"\n");
                            out.close();        
                   }
               } catch (IOException e) {
               }

           
   }


}

-------------------------------------------------------------
Manifest
-------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.tempo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.test.tempo.MainActivity"
            android:label="@string/app_name" 
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


</manifest>