PROJECTE FINAL DE CARRERA - arxiv.org

97
PROJECTE FINAL DE CARRERA Design and implementation of an Android application (MobilitApp+) to analyze the mobility patterns of citizens in the Metropolitan Region of Barcelona Estudis: Enginyeria de Telecomunicació Autor: Sergi Casanova Fouce Director/a: Mónica Aguilar Igartua Any: Març 2015

Transcript of PROJECTE FINAL DE CARRERA - arxiv.org

Page 1: PROJECTE FINAL DE CARRERA - arxiv.org

PROJECTE FINAL DE CARRERA

Design and implementation of an Android application (MobilitApp+) to

analyze the mobility patterns of citizens in the Metropolitan Region of Barcelona

Estudis: Enginyeria de Telecomunicació Autor: Sergi Casanova Fouce Director/a: Mónica Aguilar Igartua Any: Març 2015

Page 2: PROJECTE FINAL DE CARRERA - arxiv.org

                                                                           

Page 3: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

1  

RESUM  DEL  PROJECTE    En   el   nostre   projecte   hem   dissenyat   una   aplicació   per   Android   anomenada   MobilitApp  amb   l’objectiu   d’obtenir   dades   de   mobilitat   dels   ciutadans   de   l’Àrea   Metropolitana   de  Barcelona  (AMB).  La  recollida  de  dades  es  realitza  totalment  en  segon  pla  i  s’obtenen,  per  una   banda   amb   localitzacions   periòdiques   de   l’usuari   i,   per   l’altra,   obtenint   el   tipus  d’activitat  que   l’usuari  està  realitzant,  de  manera  síncrona.  Al   final  del  dia,   les  dades  són  processades  i   finalment  són  enviades  al  servidor  on  s’emmagatzemaran  en  arxius  per  tal  d’extreure’n  posteriorment  patrons  de  mobilitat  que  puguin  ajudar  a  millorar   les  actuals  infraestructures  de  transport.  L’aplicació  és  totalment  estable  i  funcional  tot  i  que  la  fiabilitat  dels  resultats  obtinguts  és  millorable  en  alguns  casos.  En  futures  versions  de  l’aplicació  es  redefiniran  els  algoritmes  utilitzant   Machine   Learning.   D’aquesta   manera,   i   mitjançant   l’entrenament   de   dades,  obtindrem  una  millora  notable  en  els  resultats.                                                                    

Page 4: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 2  

RESUMEN  DEL  PROYECTO    En  nuestro  proyecto  hemos  diseñado  una  aplicación  para  Android  llamada  MobilitApp  con  el   objetivo   de   obtener   datos   de  movilidad   de   los   ciudadanos   del   Área  Metropolitana   de  Barcelona   (AMB).     La   recogida  de   los  datos   se   realiza   totalmente  en   segundo  plano  y   se  obtienen  mediante  localizaciones  periódicas  y  la  obtención  del  tipo  de  activad  que  realiza  el  usuario  de  manera  síncrona.  Al  final  del  día,  los  datos  son  procesados  y  finalmente  son  enviados   al   servidor   donde   se   almacenarán   en   archivos   para   posteriormente   poder  extraer    patrones  de  movilidad  que  puedan  ayudar  a  mejorar  las  actuales  infraestructuras  de  transporte.  La  aplicación  es  totalmente  estable  y  funcional  a  pesar  de  que  los  resultados  obtenidos  son  mejorables   en   algunos   casos.   En   futuras   versiones   de   la   aplicación   se   redefinirán   los  algoritmos   utilizando   Machine   Learning.   De   esta   manera,   y   mediante   el   entreno   de   los  datos,  obtendremos  una  mejora  notable  en  los  resultados.                                  

Page 5: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

3  

ABSTRACT    In   our   project   we   have   designed   an   Android   application   to   obtain   mobility   data   of   the  citizens  in  the  metropolitan  area  of  Barcelona.  Our  implementation  synchronously  obtains  in  background  on  the  one  hand,  periodic  location  updates  and,  on  the  other  hand,  the  type  of  activity  citizens  are  doing.  At  the  end  of  the  day,  all  this  data  is  processed  and  sent  to  a  server   where   are   stored   to   obtain   mobility   patterns   from   citizens   that   could   help   to  improve  the  current  transportation  infrastructure.  MobilitApp   is   fully   functional   and   stable   although   the   results   can   be   improved   in   some  situations.   In   future   releases   we   will   implement   machine   learning   technics   to   obtain  significant  improvements,  especially  in  the  activity  recognition  modules.                                                    

Page 6: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 4  

Table  of  Contents  RESUM  DEL  PROJECTE   1  RESUMEN  DEL  PROYECTO   2  ABSTRACT   3  LIST  OF  FIGURES   6  LIST  OF  TABLES   7  

GLOSSARY  OF  ACRONYMS   8  I.   INTRODUCTION   9  I.1.   Introduction   10  

II.   MOBILITAPP  MAIN  DESIGN   11  II.1.  Application  Fundamentals   12  II.1.1.  Activity   12  II.1.2.  Fragment   15  II.1.3.  Service   17  II.1.4.  Localization   19  II.1.5.  Shared  Preferences   21  II.1.6.  Upload  MobilitApp  data  to  a  Cloud  Server   23  

II.2.  API   25  II.2.1.  Location  Services  API   25  II.2.1.1.  Location  Sources  in  Android  devices   25  II.2.1.2.  Android  Location  Tools   27  Fused  Location  Provider   27  Location  Request   28  

II.2.2.  Activity  Recognition  API   29  II.2.2.1.  Activity  Recognition  Sources  in  Android  devices   29  II.2.2.2.  Activity  Recognition's  Tools   29  Activity  Recognition  Result   29  Detected  Activity   29  

II.2.3.  Google  Places  API   30  II.2.3.1.  Places  Requests   30  II.2.3.2.  Places  Response   31  II.2.3.3.  Find  Places  Algorithm   32  

II.2.4.  Google  Directions  API   33  II.2.4.1.  Directions  Requests   33  II.2.4.2.  Directions  Response   34  II.2.4.3.  Find  Bus  or  Tram  Algorithm   36  

III.   MOBILITAPP  ARCHITECTURE   37  III.1.      Location  Service   38  III.1.1.      Starting  Location  Service   38  III.1.2.      Activity  Processing  Algorithm   40  III.1.3.      Location  Processing  Algorithm   42  III.1.3.1.        First  Stage:  GPS  activator  algorithm   42  III.1.3.2.        Second  Stage:  Underground  Recognition   44  III.1.3.3.        Third  Stage:  Mobility  Data  Parameters   44  III.1.3.4.        Fourth  Stage:  Creating  Mobility  Data  Segments   45  

III.2.      Activity  Recognition  Service   47  III.2.1.      Starting  Activity  Recognition  Service   47  III.2.2.      Architecture   47  III.2.3.      Activity  Detection   48  

III.3.      Map   49  

Page 7: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

5  

III.4.      Login/Profile   53  III.4.1.      Log  in  with  Facebook   53  III.4.2.      Log  in  with  Google  (Gmail  account)   54  III.4.3.      Profile  Window   55  

III.5.      History   57  III.5.1.      Structure   57  

III.6  .      Graph   62  III.6.1.      Calories  Burned  Calculation   62  III.6.2.      CO2  Saved  Calculation   63  

III.7  .      Segment  Files   65  III.7.1.      Segment  Class   65  III.7.2.      Writing  JSON  files   65  III.7.3.      JSON  File  Example   67  

IV.   RECOGNITION   68  IV.1.      Transport  Recognition   69  IV.1.1.      Metro  Recognition   69  IV.1.2.      Bus  and  Tram  Recognition   74  IV.1.3.      Train  Recognition   75  

V.   REFERENCES   75  VI.   ANNEXES   78  Annex  A:  Journey  Examples   80  A.1.   Journey  1   81  A.2.   Journey  2   82  A.3.   Journey  3   83  A.4.   Journey  4   84  A.5.   Journey  5   85  

Annex  B:  MobilitApp  User  Guide   86  B.1.  Installation   88  B.2.  Log  in  and  preferences   89  B.3.  General  functions   90  B.3.1.   History   92  B.3.2.   Plot   94  B.3.3.   Profile   95  

       

Page 8: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 6  

LIST  OF  FIGURES    2.1.   Activity  Lifecycle    2.2.   Fragment  Lifecycle    2.3.   Service  Lifecycle    2.4   Resources  Directory    2.5.   Shared  Preferences  Example    2.6. Google  Cloud  Storage  folder      2.7. Folder  Content    2.8. Fused  Location  Provider      3.1.     Marker    3.2.   Info  Window    3.3.   Pop-­‐up  Window    3.4.   Metabolic  Equivalent  Formula      4.1.   Metro  Journey  (Canyelles-­‐Camp  de  l'Arpa)      

Page 9: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

7  

LIST  OF  TABLES    2.1.   Location  Request  priority  modes    3.1.   Equivalent  MET  ratio  for  walking  (two  different  speeds)                                                                                          

Page 10: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 8  

GLOSSARY  OF  ACRONYMS    API  Application  Programming  Interface    SDK  Software  Development  Kit    APK  Android  Application  Package    APP  Application    ATM  Autoritat  del  Transport  Metropolità    AMB  Àrea  Metropolitana  de  Barcelona    GUI  Graphical  User  Interface    GPS  Global  Positioning  System    JSON  JavaScript  Object  Notation    UPC  Universitat  Politècnica  de  Catalunya    Wi-­‐Fi  Wireless  Fidelity    WPS  Wi-­‐Fi-­‐based  Positioning  System    XML  eXtensible  Markup  Language    

Page 11: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

9  

                       

Part  I  Introduction  

                                           

Page 12: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 10  

I.1.   Introduction    In   this  project,  we  are  going   to  develop  an  Android  application   to  obtain  data   regarding  the   mobility   of   citizens   in   Barcelona.   In   collaboration   with   ATM,   this   project’s   main  objective  is  to  use  this  data  to  determine  mobility  patterns  that  could  be  used  to  improve  current  transportation  infrastructure.    Android  Platform  is  used  to  develop  MobilitApp  for  two  main  reasons:    

• Large  Audience:  According  to  [0]  in  Spain  at  December  2014,  83%  of  the  devices  use  Android.    

• Google   APIs:   Google   provides   developers   large   amount   of   APIs   (Application  Programming  Interface)  to  add  different  features  to  Apps.  MobilitApp  uses:  Maps,  Places,  Directions,  Location  and  Activity  Recognition.  

 This   study   is   part   of   the   larger   EMRISCO   [1]   project   and   will   help   ATM   (Autoritat   del  Transport   Metropolità)   providing   mobility   data   to   improve   the   current   transportation  infrastructure.  We  added  new  features,  updated  algorithms,  upgraded  old  interfaces,  made  visual  enhancements  and  much  more.  The   main   problem   was   to   differentiate   between   motor   vehicles   or   between   railway  transports.   We   had   vehicle   activity   returned   in   car,   motorbike   or   bus   and   transport  activity  returned  in  metro,  tram  or  train.    In   this   continuation   project,   we   have   focused   on   improving   these   detection   algorithms  being  able  to  differentiate  between  these  activities.    These  algorithms  can  always  be  improved  with  the  aim  of  reducing  detection  errors.  Using  Google  APis  to  detect  activities  could  produce  certain  detection  errors  because  these  APIs  make  use  of  sensors  and  the  GPS  (Global  Positioning  System).  It  would  be  a  good  idea  to  radically   upgrade   all   the   algorithms   using   machine   learning   instead   these   APIs.   Using  machine  learning  is  a  difficult  task  and  needs  a  huge  amount  of  time  and  data  to  obtain  the  training  set.  Future  releases  of  MobilitApp  could  include  this  improvement.    Once  the  detection  algorithms  are  updated,  we  can  proceed  adding  more  features  in  order  to  make  MobilitApp  more  attractive  to  users.  Some  of   these  features  are:  a  History  to  be  able  to  see  on  the  map  all  the  daily  journeys,  login  and  profile  window  and  a  graph  where  co2  saved  and  calories  burned  are  displayed.    This  document  is  structured  with  three  main  sections  plus  references  and  two  annexes.  The   first   section   is   called   MobilitApp  main   design   criteria   where   we   will   explain   some  Android  fundamentals  such  as  fragments,  services…  and  the  four  Google  APIs  used.  The  second  section  is  called  MobilitApp  architecture  where  all  related  with  the  application  is  explained  with  its  respective  code.  The   third   section   will   explain   all   the   recognition   algorithms   for   the   different   types   of  transportation:  bus,  metro,  train  and  tram.  Finally  we  have  two  annexes,  the  first  one  will  show  five  case  studies,  and  the  last  one  is  the  MobilitApp  user  guide.              

Page 13: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

11  

 

                     

Part  II  MobilitApp  Main  Design  

                                             

Page 14: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 12  

II.1.   Application  Fundamentals    

II.1.1.   Activity    Description    An  activity [2]   is  an  application  component  providing  a  view  users  can   interact  with.  An  application   consists   of   multiple   activities.   The   “main   activity”   is   presented   to   the   user  when   the   application   is   launched   for   the   first   time.   In   our   case,   MobilitApp   chooses  between   two   “main”   activities:   Login   Activity   and   the   Main   Activity.   The   first   one   is  launched  the  first  time  MobilitApp  is  opened  and  the  second  one  the  following  times.  This  Main  Activity  will  start  Location  service  and  Activity  Recognition  service.    Each  activity  can  start  another  activity  in  order  to  perform  different  actions.  Each  time  a  new  activity  starts,  the  previous  activity  is  stopped,  but  the  system  preserves  the  activity  in   a   stack   (i.e.   the   “back   stack”).  When   a   new   activity   starts,   it   is   pushed   onto   the   back  stack  and  takes  user  focus.  When  the  user  is  done  with  the  current  activity  and  presses  the  Back  button,  it  is  popped  from  the  stack  and  destroyed  and  the  previous  activity  resumes.    Activities  must  be  declared  in  the  manifest  file  in  order  to  be  accessible  to  the  system.  This  manifest   file   presents   essential   information   about   the   app   to   the   Android   system.  Information   like:   minimum   SDK   (Software   Development   Kit)   version,   permissions,  activities,  services…    Lifecycle    It   is   crucial   to   manage   the   lifecycle   of   our   activities   in   order   to   develop   a   strong   and  flexible  application.  An  activity  has  three  states:    

• Resumed:  The  activity  is  in  the  foreground  of  the  screen  and  has  user  focus.    

• Paused:  Another  activity  is  in  the  foreground  (visible)  and  has  focus,  but  this  one  is  still  visible.  Paused  activities  are  completely  alive  but  can  be  killed  by  the  system  in  low  memory  situations.  

 • Stopped:  The  activity  is  running  in  the  background  and  is  no  longer  visible  by  the  

user.  Stopped  activities  are  also  alive  and  can  be  killed  by  the  system.      In   order   to   manage   the   lifecycle   of   our   activity,   we   need   to   implement   the   callback  methods.  Callback  methods  can  be  overridden  to  do  the  appropriate  work  when  the  state  of  the  activity  changes.  The  most  important  callback  methods  are:                        

Page 15: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

13  

 public!class!ExampleActivity!extends!Activity!{!!!!!@Override!

!!!!public!void!onCreate(Bundle!savedInstanceState)!{!!!!!!!!!super.onCreate(savedInstanceState);!!!!!!!!!//!The!activity!is!being!created.!

!!!!}!

!!!!@Override!!!!!protected!void!onResume()!{!!!!!!!!!super.onResume();!!!!!!!!!//!The!activity!has!become!visible!(it!is!now!"resumed").!

!!!!}!!!!!@Override!

!!!!protected!void!onPause()!{!!!!!!!!!super.onPause();!!!!!!!!!//!Another!activity!is!taking!focus!(this!activity!is!about!to!be!"paused").!!!!!}!

!!!!@Override!

!!!!protected!void!onDestroy()!{!!!!!!!!!super.onDestroy();!!!!!!!!!//!The!activity!is!about!to!be!destroyed.!

!!!!}!

}!

 onCreate()  method  is  called  when  the  activity  is  created  for  the  first  time.  This  is  where  all  the  set  up  needs  to  be  done  such  as  create  views,  bind  data  to  lists,  and  so  on.    onResume()  method  is  called  just  before  the  activity  starts  interacting  with  the  user.    onPause()  method  is  called  when  the  system  is  about  to  start  resuming  another  activity.    onDestroy()  method  is  called  before  the  activity  is  destroyed.      Figure  2.1  shows  the  activity  lifecycle.    

Page 16: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 14  

 Figure  2.1:  Activity  Lifecycle  

                 

Page 17: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

15  

II.1.2.   Fragment    A  Fragment [3]  represents  a  portion  of  the  user  interface  in  an  Activity.  Multiple  fragments  can  be  combined  in  a  single  activity.  Each  fragment  has  its  own  lifecycle  and  can  be  added  or  removed  while  the  activity  is  running.  MobilitApp  uses  fragments  in  all  the  activities  because  allows  more  dynamic  and  flexible  designs.  There  are  two  ways  we  can  add  a  fragment  to  the  activity  layout:    

• Declaring  the  fragment  inside  the  activity’s  layout  file    In  this  case,  we  can  specify  layout  properties  for  the  fragment  as  if  it  were  a  view.  This  is  how  we  add  the  map  on  the  activity.    <fragment*************android:id="@+id/map"*************android:layout_width="match_parent"*************android:layout_height="match_parent"*************class="com.google.android.gms.maps.MapFragment"*/>*

 • Programmatically  add  the  fragment  to  an  existing  ViewGroup  

 At  any  time  the  activity  is  running,  we  can  add  fragments  to  our  activity  layout.  We  simply  need  to  specify  a  ViewGroup  in  which  to  place  the  fragment.    Adding,  replacing  or  removing  actions  are  called  fragments  transactions  and  we  need  an  instance  of  FragmentTransaction [4]  to  use  methods  such  as:  add,  remove  or  replace.    getSupportFragmentManager().beginTransaction().add(R.id.containerhist,9new999

HistoryFragment()).commit();9

In  this  case,   the  ViewGroup   is  a  FrameLayout  declared   in  the  activity’s   layout   file  and  we  use  the  “id”  as  a  reference.    <FrameLayout,,,,,,android:id="@+id/containerhist",,,,,,android:layout_width="match_parent",,,,,,android:layout_height="wrap_content",,,,,,android:layout_below="@id/toolbar",,,,,,android:visibility="gone",>,</FrameLayout>,

 The   fragment   can   access   to   its   activity   instance   (and   use   activity   methods)   using  getActivity()    Lifecycle    The  most  important  callback  methods  are  the  same  as  with  Activity  plus  one  more:    onCreateView()  method  is  called  when  it  is  time  for  the  fragment  to  draw  its  user  interface  for  the  first  time.    

Page 18: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 16  

   

Figure  2.2:  Fragment  Lifecycle  

Page 19: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

17  

II.1.3.   Service    A  Service [5]  is  an  application  component  that  can  perform  long-­‐running  operations  in  the  background  and  does  not  provide  a  user  interface.  A  service  can  take  two  forms:    

• Started:   A   service   is   started   when   an   activity   or   a   fragment   starts   it   by   calling  startService()   method.   Once   started,   a   service   can   run   in   the   background  indefinitely,  even  if  the  activity  or  fragment  is  destroyed.  This  is  the  form  used  by  MobilitApp  for  Location  Service  and  Activity  Recognition  Service.  

 • Bound:  A  service  is  “bound”  when  an  activity  or  a  fragment  binds  to  it  by  calling  

bindService()  method.  A  bound  service  offers  a  client-­‐server   interface   that  allows  activities/fragments   to   interact   with   the   service.   This   form   is   not   used   by  MobilitApp.  

   There  are  two  types  of  service:  the  normal  (i.e.  Service)  and  the  IntentService.    The  main  difference  between  the  two  is  that  Service  uses  the  application’s  main  thread  so  it  could  slow  the  performance  of  any  running  activity.  IntentService  uses  a  worker  thread  to  handle  all  start  requests,  one  at  a  time.  This  work  queue  passes  on   intent  at  a  time  to  our  onHandleIntent()  callback  method.    Lifecycle    The  most  important  callback  methods  are:    onStartCommand()   method   is   called   every   time   the   service   is   started   by   calling  startService()    onHandleIntent()  method   is   called   to   process   intents   in   the   worker   thread.   When   all  requests  have  been  handled  stops  itself.                                            

Page 20: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 18  

                                                                                                 

Figure  2.3:  Service  Lifecycle  

Page 21: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

19  

II.1.4.   Localization    Supporting  different  languages    It   is   always  a  good  practice   to  present   the  application  with  more   languages;   thereby  we  can   reach   more   users   in   Barcelona.   MobilitApp [6]   is   available   in   three   languages   (i.e.  Spanish,   Catalan   and   English)   depending   on   the   language   their   mobile   phone   is   set.   It  cannot  be  changed,  so  if  the  user’s  phone  is  in  Catalan,  MobilitApp  dialog  and  text  will  be  in  Catalan  too.  If  user’s  language  is  neither  Spanish  nor  Catalan,  the  default  language  is  set  (i.e.  English).      To  make  this  possible [6]  we  need  to  create  locale  directories  and  string  files.  Within  res/  directory  are  subdirectories  for  various  resource  types  (e.g.  Layout  resources  are  saved  in  res/layout,   Drawable   resources   are   saved   in   res/drawable…).   String   Resources   define  strings  and  string  arrays  and  are  saved  in  res/values.  This  is  the  default  directory,  so  if  we  don’t   have   any   additional   values   directory   this   will   be   the   one   Android   would   use.   An  example  of  a  bad  practice  is  the  following:  all  the  strings  in  values  directory  are  written  in  Spanish   but   user’s   mobile   locale   are   set   in   English.   In   this   situation   user   does   not  understand   anything   because  MobilitApp   dialogs   and   text   are   in   Spanish   and   user   only  understands  English.  To  solve  this,  we  need  to  create  additional  values  directories.    These  additional  values  directories  are  followed  by  a  hyphen  and  the  ISO  language  code.  If  the   language   is   spoken   in   different   countries   we   add   another   hyphen   and   the   region  (preceded   by   lowercase   “r”.   Figure   2.4   shows   how   Resources   directory   is   structured   in  Android.                  

• Spanish  values  directory:  values-­‐es-­‐rES  • Catalan  values  directory:  values-­‐ca  

                 Now  we   can   create   a   strings.xml   file   in   each   directory  with   its   respective   language   and  then  add  string  values  for  each  locale  into  the  appropriate  file.  At  runtime,  the  Android  system  uses  the  appropriate  set  of  string  resources  based  on  the  locale  currently  set  for  the  user’s  device.                

 Figure  1.4:  Resources  Directory  

Page 22: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 20  

For  example,  the  following  are  some  different  string  resources  for  different  languages.    

<string(name="acep">Aceptar</string>(<string(name="cancel">Cancelar</string>(

<string(name="acep">Acceptar</string>(<string(name="cancel">Cancel·lar</string>(

<string(name="acep">Accept</string>(<string(name="cancel">Cancel</string>(

 Finally,  we  can  reference  our  string  resources  in  the  code  using  the  resource  name  defined  by  the  string  element’s  name  attribute.    For  example:    When  we  only  need  to  supply  the  string  resource  to  a  method  that  requires  a  string.    builder.setNegativeButton(R.string.cancel,5null);5

Or,  when  we  need  the  string  itself  (i.e.  the  text)  and  not  the  resource.    value[0])=)getActivity().getResources().getString(R.string.calorie);)

                                         

     

Page 23: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

21  

II.1.5.   Shared  Preferences    Android   provides   several   options   to   save   persistent   application   data [7].   Choosing  between  these  options  depends  on  our  specific  needs,  such  as  whether  the  data  should  be  private  or  accessible  to  other  applications  and  how  much  space  our  data  requires.  Android  provides  5  options  to  store  data:    

• Shared  Preferences:  Store  private  primitive  data  in  key-­‐value  pairs.  • Internal  Storage:  Store  private  data  on  the  device  memory.  • External  Storage:  Store  public  data  on  the  shared  external  storage.  • SQLite  Databases:  Store  structured  data  in  a  private  database.  • Network  Connection:    Store  data  on  the  web  with  your  own  network  server.    

 MobilitApp  use  three  of  these  five  options:    

• Shared  Preferences:  Store  simple  data  such  as  profile  information.  • External   Storage:   Store   JSON   (JavaScript   Object   Notation)   files   in   Downloads/  

device  directory.  • Network  Connection:  Store  JSON  files  using  Google  Cloud  Storage.  

 External   Storage   is   explained   in   Segment   section   and   Network   Connection   in   Upload  Section.   So   now,  we   need   to   explain   the   other   store   option   used   by  MobilitApp:   Shared  Preferences.    The  SharedPreferences  class [8]  provides  a  general  framework  that  allows  us  to  save  and  retrieve  persistent  key-­‐value  pairs  of  primitive  data  types.  We  can  use  SharedPreferences  to  save  any  primitive  data:  Booleans,   floats,   ints,   longs  and  strings.  This  data  will  persist  across  user  sessions,  even  if  the  application  is  closed  or  killed.    To  get  a  SharedPreferences  object   for  our  applications  we  use  the  following  method  with  two   parameters:   the   name   (i.e.   filename)   and   the   operating   mode   by   default   (i.e.  MODE_PRIVATE).    prefsGoogle*=*getSharedPreferences("google_login",*Context.MODE_PRIVATE);*

If  the  files  does  not  exist  it  will  be  created  with  the  filename  indicated.  In   Private   Mode   the   created   file   can   only   be   accessed   by   the   calling   application   (i.e.  MobilitApp).    Writing  or  Modification  Values    

1. Call  edit()  to  get  a  SharedPreferences.Editor [7].    SharedPreferences.Editor1editorG1=1prefsGoogle.edit();1

 2. Add  values  with  methods  such  as  putBoolean()  or  putString().  The  first  parameter  

is  the  key  and  the  second  is  the  value.    editorG.putString("birthday",5p.getBirthday());5

 

Page 24: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 22  

 3. Commit  the  new  values  with  commit().  

 editorG.commit();.

 Reading  Values    

1. We   only   need   to   use   methods   such   as   getBoolean()   or   getString().   The   first  parameter  is  the  key  and  the  second  is  the  default  value  that  will  be  returned  when  the  key  does  not  exist.  

 prefsGoogle.getString("nombre",4"User");4

 Output  File  Example                                                                

   

  Figure  2.5:  Shared  Preferences  Example  

Page 25: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

23  

II.1.6.   Upload  MobilitApp  data  to  a  Cloud  Server    MobilitApp  stores  the  data  locally  (in  our  smartphone)  so,  it  mush  implement  a  feature  to  upload  data  to  a  centralised  storage  server  This   is   particularly   important   if  we  want   to  make   this   data   available   for   future   analysis  both  at  UPC  (Universitat  Politècnica  de  Catalunya)  and  at  ATM.  At  the  same  time,  in  future  releases  we  might  want  to  provide  the  users  with  an  historical  of  their  journeys  and  some  aggregated  statistics.  Once  this  mobility  data  have  been  uploaded,  ATM  will  be  able  to  analyse  and  process  it.  We  are  going  to  use  Google  Cloud  Storage [9]  as  a  first  approximation  of  a  real  server.  In  the   near   future,   MobilitApp   data   will   be   stored   in   a   real   server   with   its   own   web  application  to  interact  with  the  stored  data.    All   the   information   is   uploaded   anonymously   even   if   the   user   is   logged   with   Gmail   or  Facebook.  The  first  time  MobilitApp  is  installed  generates  a  256  bits  code  represented  in  hexadecimal  (length  64)  to  be  able  to  use  it  as  an  id.  This  will  be  the  user  id  until  the  user  uninstalls   the   App.   In   the   Cloud   Server   each   user   has   its   own   folder   with   his   id   as   the  folder  name  and  inside  this  folder  all  the  user  data  is  stored  daily.      Figure  2.6  shows  an  example  of  a  folder  with  its  name  coded  with  SHA-­‐256:        

 Figure  2.6:  Google  Cloud  Storage  folder  

   Inside  this  folder  we  have  all  the  mobility  files  (one  per  day)  stored  in  JSON  format.  Figure  2.7  shows  the  contents  of  the  above  folder.      

 Figure  2.7:  Folder  Content  

Page 26: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 24  

To  be   sure   the   collision  probability   is  quite   low   (same  user   id   for  different  users)  when  generating   the   user   id   with   the   256-­‐bit   hash   function   the   following   method   is  implemented:  Our  session  id  consists  of  the  hash  value  of  a  random  string.  The  random  string  is [10]:    • The  current  time  (generated  with  the  Java  function  currentTimeMillis()).  • A  random  number  between  0  and  1  (generated  with  the  Java  function  random).  • The  process   id  number  of   the   app   (also  basically   a   random  number  generated  with  

the  Java  function  myPid).  • A  256-­‐bit  key  using  an  AES  key  generator.    And  finally  we  create  the  hash  of  this  concatenated  string  using  SHA-­‐256    private!String!getSessionID()!{!!! String!s;!! KeyGenerator!keyGenerator!=!null;!! SecretKey!key;!!! //!Generate!a!256<bit!key!! final!int!outputKeyLength!=!256;!! SecureRandom!secureRandom!=!new!SecureRandom();!! try!{!! ! keyGenerator!=!KeyGenerator.getInstance("AES");!! }!catch!(NoSuchAlgorithmException!e)!{!! ! e.printStackTrace();!! }!! keyGenerator.init(outputKeyLength,!secureRandom);!! key!=!keyGenerator.generateKey();!!! s!=!Long.toString(System.currentTimeMillis())!+!Double.toString(Math.random())!! ! ! +!Integer.toString(Process.myPid())!+!key.toString();!! return!s;!}!

getSessionID()   method   generates   the   random   string   using   the   four   steps   previously  mentioned.    private!String!hash(String!s)!{!! try!{!! ! //!Create!SHA3256!Hash!! ! MessageDigest!digest!=!java.security.MessageDigest.getInstance("SHA3256");!! ! digest.update(s.getBytes());!! ! byte!messageDigest[]!=!digest.digest();!! ! //!Create!Hex!String!! ! StringBuffer!hexString!=!new!StringBuffer();!! ! for!(int!i!=!0;!i!<!messageDigest.length;!i++)!! ! ! hexString.append(Integer.toHexString(0xFF!&!messageDigest[i]));!! ! return!hexString.toString();!! }!catch!(NoSuchAlgorithmException!e)!{!! ! e.printStackTrace();!! }!! return!"";!}!

hash()  method  generates  the  user  id  with  the  SHA-­‐256  hash.  

Page 27: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

25  

II.2.   API  

II.2.1.   Location  Services  API  

II.2.1.1.   Location  Sources  in  Android  devices    The  selection  of  location  sources  is  directly  related  to  meet,  on  the  one  side,  the  low  power  consumption  criterion,  and  on  the  other  side,  the  specified  requirements  for  mobility  data.  There   are   at   least   four   location   sources   available   in   almost   every   Android   device:   GPS,  WPS  (Wi-­‐Fi-­‐based  Positioning  System),  Cell  ID  and  sensors.  Each  one  of  these  sources  has  its   own   features   regarding   average   power   consumption,   accuracy   and   coverage   which  basically   depends   on   how   location   data   is   obtained   as   well   as   the   minimum   optimal  update  intervals  to  achieve  with  an  acceptable  level  in  quality  of  data.    Unfortunately,   Android   platform   is   not   well   documented   regarding   detailed   profiles   of  average  power  consumption  of  each  one  of   the   location  sources.  For   that  reason,  we  are  going   to   use   approximations   of   their   power   usage   profiles   in   order   to   select   those   that  could  meet  our  low  power  consumption  criterion.      Global  Positioning  System    GPS   consists   of   up   to   24   or   more   satellites   broadcasting   radio   signals   providing   their  locations,  status  and  timestamp.  The  GPS  receiver  in  the  Android  device  can  calculate  the  time  difference  between  broadcast   time  and   the   time   radio   signal   is   received.  When   the  device  knows   its  distance   from  at   least   four  different  satellite  signals,   it   can  calculate   its  geographical  position.    

• Average   Power   consumption:  GPS   receiver  works   as   an   independent-­‐powered  component   in   the  Android  platform  with   the   unique   objective   to   obtain   location  samples.   Therefore,   all   the   battery   power   consumed  by  GPS   is   consequence   of   a  user  positioning  operation.  According  to  several  references,  we  can  estimate  that  the  average  power  consumption  of  an  active  GPS  with  a   location  update   interval  between  5  and  15  seconds  is  approximately  125  to  145  mA.    

• Coverage:  GPS  location  coverage  is  probably  the  most  limited  of  all  four  available  sources.   Although   is   a   source   that   cover   the  whole   globe,   it   only   provides   good  performance   in   outdoor   scenarios,   because   it   requires   satellites'   visibility.   GPS  does  not  work  in  indoor  locations  (may  provide  some  location  data  in  very  few  of  them  if  it  has  some  kind  of  visibility  of  satellites,  but  with  very  poor  performance)  like   buildings   or   undergrounds.   Even   in   outdoor   environments,   GPS   may   suffer  from   poor   performance,   especially   in   cities,   because   objects   like   buildings,   trees  and  other  obstacles  can  overshadow  visible  satellites,  decreasing  its  performance.  Therefore,   GPS   range   of   coverage   can   be   quite   limited   in   a  metropolitan   region,  compared  to  other  sources,  specifically  if  we  want  a  continuous  position  tracking  of  the  citizens.  

 • Accuracy:  In  outdoor  scenarios  with  good  satellite  visibility,  GPS  is  the  positioning  

system  that  can  provide  the  most  accurate  location  of  all  four  existing  sources.  In  perfect  conditions  GPS  can  achieve  a  precision  higher  than  3  meters,  but  in  optimal  conditions   the   range   is   between  3   and  10  meters.   In   non-­‐optimal   conditions,   i.e.  lower  visibility  on   the   satellites,  GPS  accuracy   range   is   typically  between  30  and  100  meters.   GPS   is   also   capable   to   provide   an   estimation   of   altitude   and   speed  along  with  location.  

Page 28: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 26  

Wi-­‐Fi-­‐based  Positioning  System    WPS   sends   a   location   request   to   Google   location   server   with   a   list   of   MAC   that   are  currently  visible  by  the  device,  then  the  server  compares  this  list  with  a  list  of  known  MAC  addresses   of   the   device   itself,   and   identifies   associated   geocoded   locations.   After   that,  Google  server  uses  these  locations  to  triangulate  the  approximate  location  of  the  user.    

• Average  Power  consumption:  Wi-­‐Fi  receiver  works  as  an  independent-­‐powered  component   in   the   Android   platform   but   multiple-­‐purpose   that   is   not   restricted  only   to   obtain   location   samples,   as   happens   with   GPS   receiver.   Average   power  consumption  of  WPS  represents  only  a  small  part  of  power  usage  of  Wi-­‐Fi  services.  According  to  multiple  references,  we  are  going  to  estimate  that  the  average  power  consumption  of  an  active  WPS  with  a  location  update  interval  around  20  seconds  is  approximately  25  mA.    

• Coverage:  WPS  location  coverage  is  less  broad  than  GPS  but  is  more  versatile.  Its  coverage   it   is   not   global   but   block   level,   because   it   has   to   be   in   the   range   of   a  wireless  signal  to  be  able  to  provide  location  updates.  However,  within  this  range,  it   can   provide   good   performance   both   outdoor   and   indoor   scenarios.   Therefore,  WPS   range   of   coverage   can   be   very   useful   when   tracking   continuous   locations  within  cities  and  towns.  

 • Accuracy:  In  indoor  scenarios,  WPS  is  the  positioning  system  that  can  provide  the  

most  accurate  location  of  all  four  existing  sources.  In  normal  conditions,  WPS  can  achieve   a   precision   between   3   and   10  meters.   In   outdoors,   the   accuracy   of   GPS  decreases  significantly  being  able  to  provide  a  range  between  25  and  150  meters,  depending  on  the  external  conditions  of  the  environment  and  the  signal  strength.  

 Cell-­‐ID  based  localization    Cell-­‐ID   based   localization   uses   both   the   Location   Area   Code   and   Cell-­‐ID   that   the   Base  Transceiver   Station   broadcasts.   Android   devices   are   always   receiving   these   broadcast  messages,  which  means  that  they  always  know  their  Cell-­‐ID  at  any  time.  Knowing  this,   it  can  obtain  an  approximation  of   its   actual   location  using   the  geographical   coordinates  of  the  corresponding  Base  Station.    

• Average  Power  consumption:  Since  Android  devices  always  know  their  Cell-­‐ID;  the   average   power   consumption   consequence   of   this   positioning   system   is  extremely  low.    

• Coverage:  Cell-­‐ID  location  coverage  is  global,  as  happens  with  GPS,  and  versatile,  as  happens  with  WPS,  which  implies  that  has  the  best  coverage  of  all  four  existing  location   sources.   Therefore,   cell-­‐ID   has   an   adequate   coverage   range   to  continuously  track  location  of  citizens  in  the  metropolitan  region.  

 • Accuracy:   Cell-­‐ID   based   location   system   accuracy   depends   on   cells   size   in   the  

network  that  are  connected  with  user's  Android  device.  This  means  that   in  those  regions   with   smaller   cells   (typically   in   cities   and   metropolitan   regions),   cell-­‐ID  location  will  provide  good  performance  achieving  an  accuracy  range  between  50  and  200  meters.  Moreover,   in   regions  with   bigger   cells   (typically   in   rural   areas)  performance  will  significantly  decrease,  and  cell-­‐ID  will  only  achieve  an  accuracy  range  between  1000  meters  and  several  kilometers.  

   

Page 29: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

27  

Sensors    

• Average   Power   consumption:   Android   devices   have   usually   several   built-­‐in  sensors.  However,  not  all  of  them  can  be  used  for  positioning  processes,  being  only  accelerometer,  magnetic  field,  orientation,  and  gyroscope  that  one  that  can  be  used  for   such  purpose.  Based  on   their   specifications,   the  power   consumption  of   these  sensors  are  the  following:  

 o Accelerometer  -­‐  0.23  mA  o Magnetic  Field  -­‐  6.8  mA  o Orientation  -­‐  13.13  mA  o Gyroscope  -­‐  6.1  mA  

 If  all  sensors  were  used  together  at  the  same  time  to  obtain  locations  updates,  we  would  have  an  average  power  consumption  of  26.26  mA.    

• Coverage:   Sensors   have   a   wide   coverage   because   they   can   process   multiple  different   types   of   data.   From   acceleration,   that   covers   an   individual   range,   to  magnetic   field,   that   covers   a   global   range,   sensors   can   provide   data   to   improve  location  samples  in  almost  any  scenario.  

 • Accuracy:   It   depends   on   the   type   of   sensor   and   how   is   used,  which  means   it   is  

infeasible  to  provide  real  accuracy  values.  However,  according  to  Google,  sensors  improve  the  accuracy  obtained  with  just  simple  WPS  and  Cell-­‐ID.  

 

II.2.1.2.   Android  Location  Tools  

Fused  Location  Provider    This  API  considers  all  hardware  components  as  single   location  sources   layer   that  can  be  used  according  to  predetermined  criteria  implemented  on  it.  It  offers  four  main  features:    

• Simple  API:  We  can  specify  high-­‐level  needs  like  “high  accuracy”  or  “low  power”,  instead  of  having  to  worry  about  location  providers.  

• Immediately   available:   Gives   immediate   access   to   the   best   and   most   recent  location.  

• Power-­‐efficiency:  Minimizes  app’s  use  of  power.  Based  on  all   incoming   location  requests  and  available  sensors,  fused  location  provider  chooses  the  most  efficient  way  to  meet  those  needs.  

• Versatility:  Meets  a  wide  range  of  needs,   from  foreground  uses   that  need  highly  accurate   location   to   background   uses   that   need   periodic   location   updates   with  negligible  power  impact.  

                     

Figure  2.8:  Fused  Location  Provider  

Page 30: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 28  

Location  Request    Location   Request [11]   is   a   data   object   that   contains   quality   of   service   parameters   for  requests  to  the  Fused  Google  Provider.  The  main  parameters  are:      

• Desired  interval  time:  This  parameter  establishes  the  ideal  interval  time  between  location  updates.  However,   it   is  not  an  exact   interval,  which  means  that   locations  can   be   obtained   in   lower   or   higher   interval   times,   depending   on   external  conditions.   According   to   our   design   criteria  we   should   set   this   parameter   to   20  seconds.    

• Fastest   interval   time:   This   parameter   establishes   the   minimum   interval   time  between   location   updates.   Unlike   desired   interval   time,   this   is   an   exact   interval,  which  means  that  location  updates  will  not  be  obtained  in  lower  intervals  of  time  than  set  by  this  parameter.  According  to  our  design  criteria  we  should  also  set  this  parameter  to  20  seconds.  

 • Priority   mode:   This   parameter   establishes   the   priority   of   the   location   requests  

based   on   the   location   sources   that  we  want   to   use   and   the   accuracy   of   location  samples  we  require.  There  are  the  following  modes:  

 o High   Accuracy:   This   is   the   highest   priority   mode.   Using   this   mode  

Location  Client  will  obtain  the  best  location  available  using  all  the  location  sources   available   together.   This   is   also   the   mode   with   higher   average  power  consumption  because  it  is  the  only  one  that  actually  uses  the  GPS.  

 o Balanced   Power   Accuracy:   This   mode   has   lower   priority   than   High  

Accuracy  mode.   This  mode   only   uses  WPS,   cell-­‐ID   and   sensors   to   obtain  location   updates   with   a   "block"   level   accuracy   while   keeping   average  power  consumption  very  low.  

 o Low   Power:   This   mode   has   a   lower   priority   than   Balanced   Power  

Accuracy  mode.   This  mode   only   uses  WPS,   cell-­‐ID   and   sensors   to   obtain  location  updates  with  a  "city"  level  accuracy  (10km)  while  keeping  average  power  consumption  extremely  low.  

 o No  Power:  This   is   the   lowest  priority  mode.  This  mode  does  not  use  any  

location   source   to   obtain   location   updates.   Instead,   obtains   location  updates   requested   by   other   third   party   applications   in   the   Android  platform.   In   this   way   the   average   power   consumption   is   the   lowest  possible.  

                           

 

Table  2.1:  Location  Request  priority  modes  

Page 31: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

29  

II.2.2.   Activity  Recognition  API    

II.2.2.1.  Activity  Recognition  Sources  in  Android  devices    In  opposition  of  what  happens  with  location,  there  is  basically  one  main  source  to  detect  user's  activity   type:  device  sensors.  Therefore,   there   is  no  real  alternative   to   this  source,  and   currently   is   the   only   possible   option   if   we   want   to   recognize   activities.   As   we  explained,   there   are   four  major   sensors   that   are   used   to   improve   location   updates,   and  although  all  of  them  can  be  somehow  used  for  this  purpose,  in  reality  the  main  sensor  that  we  are  going  to  use  is  the  accelerometer.  Accelerometer  has   the   lowest  power  consumption  of  all  sensors,  but   is  also   the  one  that  requires  more  processing  of  samples  to  provide  accurate  results.    

II.2.2.2.  Activity  Recognition's  Tools    Android   platform   provide   developers   with   multiple   tools,   including   services,   libraries,  classes  and  methods  to  implement  and  develop  their  application.  However,  these  tools  are  limited   to   obtain   raw   sensor   data.   Process   raw   sensor   data   in   order   to   detect   user's  activity  with  good  accuracy  is  too  complex  to  be  designed  and  implemented  to  this  project  at  the  time  of  writing.  Instead  of  that,  we  are  going  to  use  Google  Activity  Recognition  API.  These  API  provides  a  low  power  mechanism  that  can  provide  periodic  updates  of  detected  activity   types   by   using   low   power   sensors   (basically   accelerometer).   We   are   going   to  process   these   samples   in  order   to   increase   accuracy   and  efficiency.  The  most   important  classes  that  we  are  going  to  use  from  this  API  are  presented  below.    

Activity  Recognition  Result    This   class   [12]   returns   a   list  with   all   probable   activities.   It   also   provides   a  method   that  directly   returns   the   most   probable   activity   along   with   its   confidence   level   called  getMostProbableActivity().    

Detected  Activity    This   class   [13]   returns   an   integer   that   indicates  which   activity   type  has  bee  detected  by  Activity  Recognition  API.                            

Page 32: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 30  

II.2.3.   Google  Places  API    The  Google  Places  API  [14]   is  a  service  that  returns  information  about  Places  using  HTTP  requests.  This  API  is  the  one  used  to  find  the  nearest  metro  station  so  our  desired  Place  is  the  metro.  HTTP   response   can   be   either   in   JSON   format   or   in   XML   (eXtensible  Markup   Language)  format,  but  Google  recommends  JSON  format.  Unlike  Google  Directions  API,  this  API  uses  an  API  key  to  identify  our  application.  This  is  due  to  the  fact  that  this  API  has  a  limit  amount  of  requests.  The  quota  is  100.000  requests  per  24  hours  period.    

II.2.3.1.  Places  Requests    First,  we  need  to  construct  the  URL  using  the  parameters  provided  by  Google.  Three  parameters  are  required  while  others  are  optional;  these  parameters  are  separated  using  the  ampersand  character.  These  three  required  parameters  are:  

• key:  The  key  used  to  identify  our  application  for  purposes  of  quota  management.    

• location:  Latitude/longitude  around  which  to  retrieve  place  information.  • radius:  Defines  the  distance  (in  meters)  within  which  to  return  place  results.  

 MobilitApp  also  uses  one  optional  parameter:    

• types:  Restricts  the  results  to  places  matching  at  least  one  of  the  specified  types.  o types=subway_station:  Used  to  search  for  metro  stations.  

 

private!String!makeUrl(double!latitude,!double!longitude,!String!place)!{!! StringBuilder!urlString!=!new!StringBuilder(!! ! "https://maps.googleapis.com/maps/api/place/search/json?");!!! urlString.append("&location=");!! urlString.append(Double.toString(latitude));!! urlString.append(",");!! urlString.append(Double.toString(longitude));!! urlStrig.append("&radius=150");!! urlString.append("&types="!+!place);!! urlString.append("&key="!+!API_KEY);!!! return!urlString.toString();!}!

Now,   we   need   to   connect   to   this   URL   using   URLConnection   class.   This   class   will   be  explained  in  the  next  chapter:  Directions  API.                  

Page 33: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

31  

II.2.3.2.  Places  Response    If   there   is   a  metro   station  within   a   radius  of   150  meters,  we  will   receive   a   JSON   format  response.   This   response   contains   several   fields   but   we   need   only   one:   the   name   of   the  metro  station.  When  there  are  two  or  more  metro  stations  within  this  radius  our  algorithm  only  gets  the  name  of  the  first  one  (i.e.  the  nearest  one).    The  following  response  will  show  the  nearest  metro  station  within  150  meters  given  one  location  

 

 

 

             

{""""""html_attributions"":"[],""""""results"":"[""""""""

{"""""""""""""geometry"":"{"""""""""""""""" "location"":"{""""""""""""""""""" "" "lat"":"41.384434,"""""""""""""""""" " "lng"":"2.11167"""""""""""""""" }"""""""""""},""""""""""""icon"":""http://maps.gstatic.com/mapfiles/place_api/icons/generic_businessE71.png","""""""""""""id"":""377f10e5b229e754b2ed5cdda54ccf8394fe1bad",""""""""""""name"":""Zona"Universitària",""""""""""""photos"":"["""""""""""""""" {"""""""""""""""""" ""height"":"2048,""""""""""""""""""" "html_attributions"":"[""De"un"usuario"de"Google""],""""""""""""""""""" "photo_reference"":"""",""""""""""""""""""" "width"":"1536"""""""""""""""" }""""""""""""""""""""""""],""""""""""""place_id"":""ChIJwYRtilaYpBIRgr0jGR0kkIk",""""""""""""reference"":"""",""""""""""""scope"":""GOOGLE",""""""""""""types"":"[""subway_station",""train_station",""transit_station",""establishment""],"""""""""""""vicinity"":""Spain"""""""""}"""""

"""""""""""],""""""""""""""""status"":""OK"""}"

Page 34: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 32  

II.2.3.3.  Find  Places  Algorithm    Given   two   locations   (origin  and  destination),   this  algorithm  will   return  a  dimension   two  ArrayList  if  both  origin  and  destination  responses  have  “OK”  station  (i.e.  its  nearest  metro  station  is  found).  If  only  one  response  is  “OK”  the  returned  ArrayList  will  be  dimension  one  and   finally   if   neither   origin   nor   destination   responses   have   “OK”   status   null   array   is  retuned.  

jsonToPlace()   static  method   loops   through   the   JSON   response   and   returns   the   field  with  the  name  of  the  metro  station.    

public!static!Place!jsonToPlace(JSONObject!point)!{!! try!{!! ! Place!result!=!new!Place();!! ! JSONObject!geometry!=!(JSONObject)!point.get("geometry");!! ! JSONObject!location!=!(JSONObject)!geometry.get("location");!! ! result.setLatitude((Double)!location.get("lat"));!! ! result.setLongitude((Double)!location.get("lng"));!! ! result.setName(point.getString("name"));!! ! return!result;!! }!catch!(JSONException!e)!{!! ! e.printStackTrace();!! }!! return!null;!}!

           

public!ArrayList<String>!findPlaces(double!latitude,!double!longitude,!double!latitude2,!double!!!! ! longitude2,!String!placeSpacification)!{!

! String!urlString!=!makeUrl(latitude,!longitude,!placeSpacification);!

! String!urlString2!=!makeUrl(latitude2,!longitude2,!placeSpacification);!! ArrayList<String>!arrayList!=!new!ArrayList<String>();!! try!{!! ! JSONObject!object!=!new!JSONObject(getJSON(urlString));!! ! JSONArray!array!=!object.getJSONArray("results");!

! ! JSONObject!object2!=!new!JSONObject(getJSON(urlString2));!! ! JSONArray!array2!=!object2.getJSONArray("results");!

! ! try!{!! ! ! Place!place!=!Place.jsonToPlace((JSONObject)!array.get(0));!! ! ! Place!place2!=!Place.jsonToPlace((JSONObject)!array2.get(0));!! ! ! if!(place!!=!null)!!{!arrayList.add(place.getName());!}!! ! ! if!(place2!!=!null)!{!arrayList.add(place2.getName());!}!! ! }!catch!(Exception!e)!{!! ! }!

! ! return!arrayList;!! }!catch!(JSONException!e)!{!! }!

! return!null;!}!

Page 35: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

33  

II.2.4.   Google  Directions  API    The   Google   Directions   API   [15]   is   a   service   that   calculates   directions   between   location  points  using  an  HTTP   request.  MobilitApp  uses   this  API   to   search   for  directions   for   two  modes   of   transportations   (i.e.   Bus   and   Tram)   and   can   return   multiple   routes   between  origin  and  destination.    HTTP  response  can  be  either   in   JSON   format  or   in  XML   format,  but  Google   recommends  JSON  format.    

II.2.4.1.  Directions  Requests    First,  we  need  to  construct  the  URL  using  the  parameters  provided  by  Google.  Two  parameters  are  required  while  others  are  optional;   these  parameters  are  separated  using  the  ampersand  character.  These  two  required  parameters  are:  

• origin:   Latitude/longitude   value   from   which   we   wish   to   calculate   directions.    

• destination:  Latitude/longitude  value  to  which  we  wish  to  calculate  directions.    

MobilitApp  also  uses  other  optional  parameters:    

• departure_time:  Specifies  the  desired  time  of  departure.  • mode:  Specifies  the  mode  of  transport  to  use  when  calculating  directions.  

o mode=transit:  Requests  directions  via  public  transit  routes.  • alternatives:  If  set  to  true,  specifies  that  the  Directions  service  may  provide  more  

than  one  route  alternative  o alternatives=true  

 private!String!makeUrl(double!latitude,!double!longitude,!double!latitude2,!double!!!!! longitude2,!long!departure_time)!{!!! StringBuilder!urlString!=!new!!!

!! StringBuilder("https://maps.googleapis.com/maps/api/directions/json?");!!! urlString.append("&origin=");!! urlString.append(Double.toString(latitude));!! urlString.append(",");!! urlString.append(Double.toString(longitude));!! urlString.append("&destination=");!! urlString.append(Double.toString(latitude2));!! urlString.append(",");!! urlString.append(Double.toString(longitude2));!! urlString.append("&mode=transit");!! urlString.append("&departure_time=");!! urlString.append(Long.toString(departure_time));!! urlString.append("&alternatives=true");!!! return!urlString.toString();!}!

Now  that  we  have  constructed  the  URL  it  is  time  to  make  the  connection.  For  this  purpose  exists  the  URLConnection  class  and  to  receive  the  response  a  buffer  is  implemented.      

Page 36: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 34  

The  following  code  will  show  the  connection:    private!String!getUrlContents(String!theUrl)!{!! StringBuilder!content!=!new!StringBuilder();!! try!{!! ! URL!url!=!new!URL(theUrl);!! ! URLConnection!urlConnection!=!url.openConnection();!! ! BufferedReader!bufferedReader!=!new!BufferedReader(new!!!! ! ! InputStreamReader(urlConnection.getInputStream()));!! ! String!line;!! ! while!((line!=!bufferedReader.readLine())!!=!null)!{!! ! ! content.append(line!+!"\n");!! ! }!! ! bufferedReader.close();!! }!catch!(Exception!e)!{!! ! e.printStackTrace();!! }!! return!content.toString();!}!

 

II.2.4.2.  Directions  Response    JSON   responses   are   very   long   so,   we   are   going   to   explain   the   response   fields   used   by  MobilitApp   with   the   definition   and   at   the   end   a   piece   of   the   JSON   response   of   the  transit_details  field.    

• routes:  Contains  an  array  of  routes  from  the  origin  to  the  destination.    Each  route  within  the  routes  field  may  contain  the  following  important  field:    

• legs[]:   Contains   different   ways   to   make   the   journey   from   the   origin   to   the  destination.  

 Each  leg  may  contain  the  following  important  field:    

• steps:  Contains  an  array  of  steps  denoting  information  about  each  separate  step  of  the  leg.  

   The  important  field  in  the  steps  array  is  the  following:    

• transit_details:  Contains  transit  specific  information  and  it  is  only  returned  when  travel  mode  is  set  to  transit.    

 Here  we  have  two  important  fields:    

• departure_time:  Contains  the  departure  time  for  this  leg  of  the  journey.  • line:  Contains  information  about  the  transit  line  used  in  this  step.  

 Line  field  contains  the  most  important  field  for  us:    

• vehicle:   Is   the   array   that   contains   the   field   type,   this   file   contains   the   type   of  vehicle  used  on  this  line.  

 

Page 37: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

35  

The   algorithm   uses   only   these   two   fields:   departure_time   and   type.   Our   mission   is   to  search  for  these  two  parameters  in  the  ArrayList  [16]  and  check  if  Bus  or  Tram  is  written  or  not  as  long  as  our  departure  time  (time  of  the  first  location  in  a  vehicle  sample)  is  next  to  departure_time  field.    "transit_details",:,{,,,,,,,,,,,,,,,,,,,,,,,,,

"arrival_stop",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "location",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "lat",:,41.4306046,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "lng",:,2.1449129,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, },,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "name",:,"Montbau",,,,,,,,,,,,,,,,,,,,,,,,,,},,,,,,,,,,,,,,,,,,,,,,,,,,,"arrival_time",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "text",:,"21:52",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "time_zone",:,"Europe/Madrid",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "value",:,1423774348,,,,,,,,,,,,,,,,,,,,,,,,,,},,,,,,,,,,,,,,,,,,,,,,,,,,,"departure_stop",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "location",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , ,"lat",:,41.4417677,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "lng",:,2.1658515,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, },,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "name",:,"Canyelles",,,,,,,,,,,,,,,,,,,,,,,,,,},,,,,,,,,,,,,,,,,,,,,,,,,,,"departure_time",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "text",:,"21:47",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "time_zone",:,"Europe/Madrid",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "value",:,1423774067,,,,,,,,,,,,,,,,,,,,,,,,,,},,,,,,,,,,,,,,,,,,,,,,,,,,,"headsign",:,"Zona,Universitària",,,,,,,,,,,,,,,,,,,,,,,,,,,"headway",:,420,,,,,,,,,,,,,,,,,,,,,,,,,,"line",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "agencies",:,[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , , "name",:,"TMB",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , , "phone",:,"011,34,902,07,50,27",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , , "url",:,"http://www.tmb.cat/",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , },,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "color",:,"#1eb53a",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "name",:,"Zona,Universitària,U,Trinitat,Nova",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "short_name",:,"L3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "text_color",:,"#ffffff",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "url",:,"http://www.tmb.cat/ca/detallUliniaUmetro/U/linia/L3",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "vehicle",:,{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "icon",:,"//maps.gstatic.com/mapfiles/transit/iw/6/subway.png",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "local_icon",:,"//maps.gstatic.com/mapfiles/transit/iw/6/esUmetro.png",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "name",:,"Metro",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, , "type",:,"SUBWAY",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, },,,,,,,,,,,,,,,,,,,,,,,,,,},,,,,,,,,,,,,,,,,,,,,,,,,,,"num_stops",:,3,,,,,,,,,,,,,,,,,,,,,,

,},

   

Page 38: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 36  

II.2.4.3.  Find  Bus  or  Tram  Algorithm    public!String!findBusorTram()!{!! String!urlString!=!makeUrl(lat,!lon,!lat2,!lon2,!departure_time);!! long!jsondeparture,!resta1,!jsonarrival,!resta2;!! String!type!=!"none";!! try!{!! ! String!json!=!getJSON(urlString);!! ! JSONObject!object!=!new!JSONObject(json);!! ! JSONArray!array!=!object.getJSONArray("routes");!! ! for!(int!i!=!0;!i!<!array.length();!i++)!{!! ! ! JSONObject!obj!=!array.getJSONObject(i);!! ! ! JSONArray!legs!=!obj.getJSONArray("legs");!! ! ! JSONArray!steps!=!legs.getJSONObject(0).getJSONArray("steps");!!! ! ! for!(int!j!=!0;!j!<!steps.length();!j++)!{!! ! ! ! if!(steps.getJSONObject(j).has("transit_details"))!{!! ! ! ! ! type!=!!steps.getJSONObject(j)!!!!! ! ! ! ! ! .getJSONObject("transit_details")!!! ! ! ! ! .getJSONObject("line")!! ! ! ! ! ! .getJSONObject("vehicle")!!!!!!!! ! ! ! ! ! .getString("type");!!! ! ! ! ! if!(type.equalsIgnoreCase("BUS")!||!!!!! ! ! ! ! ! type.equalsIgnoreCase("TRAM"))!{!! ! ! ! ! ! jsondeparture!=!steps.getJSONObject(j)!!!! ! ! ! ! ! ! .getJSONObject("transit_details")!! ! ! ! ! ! ! .getJSONObject("departure_time")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! .getLong("value");!!! ! ! ! ! ! jsonarrival!=!steps.getJSONObject(j)!!!! ! ! ! ! ! ! .getJSONObject("transit_details")!! ! ! ! ! ! ! .getJSONObject("arrival_time")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! .getLong("value");!!! ! ! ! ! ! resta1!=!jsondeparture!U!departure_time;!!! ! ! ! ! ! resta2!=!jsonarrival!U!arrival_time;!! ! ! ! ! ! if!(resta1!<!0)!! ! ! ! ! ! ! resta1!=!Uresta1;!00 0 0 0 0 0 if!(resta2!<!0)!! ! ! ! ! ! ! resta2!=!Uresta2;!!! ! ! ! ! ! //!error!margin=!5!min!at!departure!! ! ! ! ! ! //!error!margin=!3!min!at!arrival!! ! ! ! ! ! if!(resta1!<!(5!*!60)!&&!resta2!<!(3!*!60)))!!! ! ! ! ! ! ! return!type;!! ! }! }! }! }!! }!catch!(JSONException!e)!{!e.printStackTrace();!}!! return!"none";!}!

The  algorithm  returns  a  variable  string  depending  on   the   field   type,   if   “BUS”  or   “TRAM”  does  not  appear  in  this  field,  “none”  is  returned.    We   have   an   error   margin   with   the   departure   time   because   the   bus/tram   stops   at   the  bus/tram  stop  and  then  accelerates  slowly.  In  this  situation  the  detected  activity  could  be  still  or  on_foot  and  not   the  desired  one:  vehicle.  Giving  an  error  margin  of  5  minutes   for  departure   and   3   minutes   for   arrival   assures   we   do   not   take   into   account   these   wrong  samples.  

Page 39: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

37  

                       

Part  III  MobilitApp  Architecture    

Page 40: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 38  

III.1.   Location  Service    In  this  chapter  we  are  going  to  explain  in  detail  the  most  important  part  of  our  MobilitApp  application,  the  location  service.  It’s  important  because  all  the  recognition  algorithms  are  implemented  here  as  well  as  the  upload  part  and  the  post  processing.    

III.1.1.  Starting  Location  Service    Location   service   is   initiated   the   first   time  we  open  MobilitApp  by   instantiating   the   class  Requester  and  using  the  method  requestUpdates(…)  in  our  MainActivity  fragment.  Requester  class  is  instantiated  inside  the  method  onActivityCreated(…)          

getActivity()  is  used  in  order  to  get  the  Context  inside  a  fragment.    Once  we  have  checked  Google  Play  Services  are  installed  in  the  device  we  can  proceed  to  request  location  updates  with:    

With  these  parameters  we  request  location  updates  and  GPS  is  set  to  false.      Requester  is  used  for  both  Location  updates  and  Activity  Recognition  updates  depending  on   the   first   parameter   in   requestUpdates().   If   “LOC”   is   written   Location   updates   are  initialized  and  Activity  updates  if  “AR”  is  written.    To   be   able   to   get   Location   Updates   a   Google   API   Client   is   needed   and   then   request   a  connection  to  it.  This  client  is  generated  by  instantiating  the  builder  of  the  GoogleApiClient  class  [17]  adding  the  two  APIs  we  are  going  to  use  and  registering  the  two  mandatory  callbacks:    

Once   the   client   [18]   is   created   we   need   to   call   the   connect()   method   so,   when   the  connection  is  done  a  call-­‐back  is  generated  in  our  onConnected()  method.  Here  we  can  set  the  updates  and  finally  disconnect  the  client.    

 

mrequesterLOC+=+new+Requester(getActivity());+

mrequesterLOC.requestUpdates("LOC",3false);3

myClient)=)new)GoogleApiClient.Builder(mContext).addApi(ActivityRecognition.API))) .addApi(LocationServices.API).addConnectionCallbacks(this))

.addOnConnectionFailedListener(this).build();)

if#(type.equalsIgnoreCase("AR"))#{#ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(getClient(),AppUtils.#UPDATE_INTERVAL_ACTIVITY,#createRequestPendingIntent(type));#

}#else#{#LocationServices.FusedLocationApi.requestLocationUpdates(getClient(),####createLR(mgps),createRequestPendingIntent(type));#

# }#//#Disconnect#the#client#requestDisconnection();#

Page 41: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

39  

The   best   way   requesting   updates   in   background   is   using   PendingIntent   [19].   This  PendingIntent   is   created   in   createRequestPendingIntent()   method.   This  method   has   only  one  parameter  in  order  to  differentiate  between  the  two  APIs.    private!PendingIntent!createRequestPendingIntent(String!type)!{!

PendingIntent!pendingIntent;!! ! //!If!the!PendingIntent!already!exists!! if!(null!!=!getRequestPendingIntent())!{!! ! //!Return!the!existing!intent!! ! return!mActivityRecognitionPendingIntent;!! ! //!If!no!PendingIntent!exists!! }!else!{!! ! if!(type.equalsIgnoreCase("AR"))!{!! ! ! Intent!intent!=!new!Intent(mContext,!!ActivityRecognitionService.class);!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! pendingIntent!=!PendingIntent.getService(mContext,!1,!intent,!!!!!!!!!

!! ! ! PendingIntent.FLAG_UPDATE_CURRENT);!! ! ! setRequestPendingIntent(pendingIntent);!! ! }!else!{!!

!!!!!!!!!!!!! Intent!intent!=!new!Intent(mContext,!LocationService.class);! !!!!!!!!!!!!!!!! pendingIntent!=!PendingIntent.getService(mContext,!0,!intent,!!!!!! ! PendingIntent.FLAG_UPDATE_CURRENT);!

! ! ! setRequestPendingIntent(pendingIntent);!! ! }!! ! return!pendingIntent;!! }!}!

First,   we   need   to   create   an   intent   to   one   of   our   two   Services   (Activity   Recognition   or  Location)  and  then  pass  that  intent  to  the  pending  intent  generated  from  the  static  method  getService().  So,  to  summarize,  every  time  we  call  requestUpdates  PendingIntents  are  generated  to  its  service.    But,  How  frequently  are  these  PendingIntents  generated?      In   Location   ones   there   are   two   possible   intervals   according   to   our   design   criteria,   the  normal  interval:  20  seconds  and  the  GPS  interval:  5  seconds.  We  are  going  to  configure  these  intervals  in  createLR()  method:    

Just   to  remember,   this  LocationRequest   is  used  as  a  parameter  when  requesting   location  updates.  

private!LocationRequest!createLR(boolean!gps)!{!LocationRequest!locationRequest!=!null;!

! if!(!gps)!{!! ! locationRequest!=LocationRequest.create()!

!!!!!!!!!!!!!!!!!!!!!! .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)!! ! ! .setInterval(AppUtils.UPDATE_INTERVAL_LOCATION)!! ! ! .setFastestInterval(AppUtils.FASTEST_INTERVAL_LOCATION);!! }!else!{!! ! if!(isGPSEnabled)!! ! ! locationRequest!=!LocationRequest.create()!!! ! ! ! .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)!! ! ! ! .setInterval(AppUtils.UPDATE_INTERVAL_GPS);! ! !

}!! ! return!locationRequest;!}!

Page 42: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 40  

Now,  we  have  successfully  set  up  our  Location  Updates.  Every  5  or  20  seconds  (depending  if   we   need   or   not   GPS)   the   onStartCommand()  method   of   our   Location   Service   will   be  called.  This  call  is  accompanied  by  an  intent  that  contains  the  current  location  as  an  object  of  the  class  Location  

III.1.2.  Activity  Processing  Algorithm    In   order   to   receive   and   process   activity   recognition   updates   three   methods   are  implemented.  The  first  one  is  a  broadcast  receiver  that  obtains  activity  updates  sent  by  the  Activity  Recognition  Services  every  5  seconds.    private!final!BroadcastReceiver!activityReceiver!=!new!BroadcastReceiver()!{!

@Override!! public!void!onReceive(Context!context,!Intent!intent)!{!

!! activityProcessing(intent.getStringExtra("activity"));!! }!};!

 The  second  one  is  the  method  used  to  count  all  the  activity  updates.  Every  time  the  sample  is   received   we   make   a   call   to   activityProcessing()   method   in   order   to   count   all   the  consecutive  activity  updates  during  the  segment  interval  time  (2  minutes).    The   last   one   is   used   to   return   the  most   probable   activity   and   it’s   called   just   after   the   2  minutes  have  passed.    

private!void!activityProcessing(String!_activity)!{!!! switch!(_activity)!{!!! ! case!"vehicle":!! ! ! vehicle_count++;!! ! ! break;!! ! case!"bicycle":!! ! ! bicycle_count++;!! ! ! break;!! ! case!"on_foot":!! ! ! on_foot_count++;!! ! ! break;!! ! case!"still":!! ! ! still_count++;!! ! ! break;!! ! case!"unknown":!! ! ! unknown_count++;!! ! ! break;!! }!}!

@Override(public(int(onStartCommand(Intent(intent,(int(flags,(int(startId)({(

location=intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);(( locationChanged(location);(( return(START_NOT_STICKY;(}(

Page 43: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

41  

private!String!activityEstimation(int!_isOnfoot,!int!_isBicycle,!int!_isStill,!int!_isVehicle,!int!_isUnknown)!{!!! ArrayList<Integer>!max!=!new!ArrayList<Integer>(5);!! !//!arraylist!with!size!equal!to!the!number!of!max!

max!=!findMax(_isOnfoot,!_isBicycle,!_isStill,!_isVehicle,!_isUnknown);!! switch!(max.size())!{!! case!1:!! ! return!(toActivity(max.get(0)));!!!! case!2:!! !!!!if!(max.get(0)!==!3!||!max.get(1)!==!3)!{!//if!vehicle!is!inside!the!arrayV>return!vehicle!! ! ! return!toActivity(3);!! ! }!else!if!(max.get(0)!==!1!||!max.get(1)!==!1)!{!//same!but!for!bicycle!! ! ! return!toActivity(1);!! ! }!else!if!(max.get(0)!==!0!||!max.get(1)!==!0)!{!//same!but!for!on_foot!! ! ! return!toActivity(0);!! ! }!else!{!! ! ! return!toActivity(2);!//!else!return!V>!still!! ! }!! case!3:!! ! if!(max.get(0)!==!3!||!max.get(1)!==!3!||!max.get(2)!==!3)!{!! ! ! return!toActivity(3);!! ! }!else!if!(max.get(0)!==!1!||!max.get(1)!==!1!||!max.get(2)!==!1)!{!! ! ! return!toActivity(1);!! ! }!else!{!! ! ! return!toActivity(0);!! ! }!! case!4:!! ! if!(max.get(0)!==!3!||!max.get(1)!==!3!||!max.get(2)!==!3!||!max.get(3)!==!3)!{!! ! ! return!toActivity(3);!! ! }!else!{!! ! ! return!toActivity(1);!! ! }!! case!5:!! ! return!toActivity(2);!//!if!all!samples!equal!0!V>!return!still!! ! }!! return!"still";!}!

This  method  returns   the  activity  with  more  number  of  samples.   If  we  have   two  or  more  activities   with   the   same   number   of   maximum   samples   we   have   established   a   simple  algorithm  that  only  returns  one.  This  algorithm  provides  a  priority  order  where  vehicle  has  the  maximum  priority.  If  there  are  no  vehicle  samples,   the  priority  order  goes:  bicycle,  on_foot  and  finally  still.  Let’s  see  some  examples  of  this  algorithm:    

   The   algorithm   will   return   on_foot   because   is   the   activity   with   more  samples.        

 Now   we   have   three   activities   with   the   same   number   of   maximum  samples.  Vehicle  has   the  maximum  priority   so   the  algorithm  will   return  vehicle.  

Vehicle:  1  On_foot:  5  Bicycle:  0  Still:  2  Unknown:  1  

Vehicle:  5  On_foot:  5  Bicycle:  0  Still:  5  Unknown:  1  

Page 44: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 42  

Also,  we  have   implemented  toActivity()  method  (used   in  previous  code)  to  avoid  making  writing  mistakes  when  returning  the  activity.    private!String!toActivity(int!index)!{!!! switch!(index)!{!! case!0:!! ! return!"on_foot";!! case!1:!! ! return!"bicycle";!! case!2:!! ! return!"still";!! case!3:!! ! return!"vehicle";!! case!4:!! ! return!"unknown";!! }!! return!"";!}!

 

III.1.3.   Location  Processing  Algorithm    As   we   have   already   mentioned,   we   receive   location   updates   every   20   seconds  approximately.  Every  time  this  update  arrives  at  onStartCommand()  method,  another  one  is  called:  locationChanged().  This  is  the  most  important  method  in  MobilitApp  so  we  will  explain  it  in  detail.  As  it  is  large  method  it  would  be  better  to  divide  it  in  four  stages.  

III.1.3.1.   First  Stage:  GPS  activator  algorithm    Sometimes  GPS  is  needed  because  we  are  in  a  non-­‐Wi-­‐Fi  zone  or  with  bad  Wi-­‐Fi  coverage.  GPS   uses   so   much   battery   power   so   it   may   impact   in   battery   life   when   used   in   long-­‐running   applications   like  MobilitApp.   For   this   reason,   GPS  will   only   be   activated   during  two  segment  cycles  (a  maximum  time  of  four  minutes).    MobilitApp   uses   Google   Fused   Location   Provider   (as   explained   before),   and   its   normal  behaviour   is   to  only  use   cell   towers   and  Wi-­‐Fi   access  points.  When   these   two  providers  fail,  GPS  is  needed  but  how  can  we  notice  it?  There  are  two  possibilities:    First,  when  there   is  no  near  Wi-­‐Fi  (e.g.  highway,   isolated  towns)  but  we  can  still  use  cell  towers   locations.   In   this   situation   we   receive   location   updates   with   little   accuracy   (i.e.  ~700-­‐1000  meters).   So,  when   location  accuracy   is  higher   than  1000  meters  GPS  will   be  activated.  But  if  the  accuracy  is  much  higher  than  1000  meters  (that  means  we  are  inside  an  underground),  so  there  is  no  point  enabling  the  GPS.    And  second  when  we  cannot  get  any   location  during   the  20  seconds   interval.  When   this  happens,  it  sends  repeatedly  the  last  known  location  until  a  good  one  is  received.  So,  if  the  same  location  is  repeating  GPS  will  be  enabled.            

Page 45: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

43  

The  following  code  shows  this  algorithm:    if!(location.getAccuracy()!<!200)!{!

tempLocationArrayList.add(location);!//!Checks!whether!the!loc!is!the!same!as!the!previous!BB>!Enable!GPS!!if!(!gpsON)!

! ! if!(tempLocationArrayList.size()!!=!1)!! ! !!!!if!(tempLocationArrayList.get(tempLocationArrayList.size()!B!1).getLatitude()!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!==!tempLocationArrayList.get(tempLocationArrayList.size()!B!2).getLatitude()!! ! !!!&&!tempLocationArrayList.get(tempLocationArrayList.size()!B!1).getLongitude()!!!!!!!

!!!!!!!!!!!!!!!==!tempLocationArrayList.get(tempLocationArrayList.size()!B!2).getLongitude())!!!!!!!!!!!!!!!!!{!

! ! ! reploc++;!! ! ! ! if!(reploc!>!2)!{!! ! ! ! ! if!(vehicle_count!>!1!||!on_foot_count!>!2)!{!! ! ! ! ! ! needGPS(true);!! ! ! ! ! ! cada2min!=!0;!! ! ! ! ! ! Log.v("aki",!"aki_GPSON");!! ! ! ! ! ! gpsON!=!true;!! ! ! ! ! }!! ! ! ! }!! ! }!else!{!! ! ! reploc!=!0;!! ! }!}!else!{!//!loc!>!200!!!!!!!!if!(location.getAccuracy()!<!1000!&&!wifi.isWifiEnabled())!//GPS!enabled!when!200<loc<1000!! if!(!gpsON)!{!! ! needGPS(true);!! ! cada2min!=!0;!! ! Log.v("aki",!"aki_GPSON");!! ! gpsON!=!true;!! }!!}!

First  part  of  the  code  enables  GPS  when  we  receive  repeated  locations  and  only  when  the  detected  activity  is  on_foot  or  vehicle,  thereby  avoid  wasting  battery  power  when  still.  Second  part  enables  GPS  when  the  accuracy  is  between  200  and  1000  meters.    To   be   able   to   enable   or   disable   the   GPS   MobilitApp   uses   needGPS()   method.   When   its  parameter  is  true  GPS  will  be  enabled  and  vice  versa.    private!void!needGPS(boolean!value)!{!! if!(hasGPS)!{!! ! Log.v("aki",!"aki_needGPS");!!! ! Requester!req!=!new!Requester(this);!!! ! req.requestUpdates("LOC",!value);!

}!}!

As  said  before,  Requester  class  is  used  in  order  to  request  new  updates.          

Page 46: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 44  

III.1.3.2.   Second  Stage:  Underground  Recognition    This  stage  will  be  explained  in  Transport  Recognition  section.      

III.1.3.3.   Third  Stage:  Mobility  Data  Parameters    In  this  stage  we  use  the  location  samples  stored  in  the  ArrayList  to  obtain  four  important  parameters:  total  and  block  distance,  total  duration  and  average  speed.    All  these  parameters  are  computed  right  after  the  segment  time  (2  minutes).    Total  distance  is  calculated  from  the  latitudes  and  longitudes  using  the  following  formula:    //Distance*between*two*locations,*in*meters*public*static*double*distanceCalculation(double*firstLatitude,*double*firstLongitude,*double*lastLatitude,double*lastLongitude)*{*** double*distance*=*0;** firstLatitude*=*Math.toRadians(firstLatitude);** firstLongitude*=*Math.toRadians(firstLongitude);** lastLatitude*=*Math.toRadians(lastLatitude);** lastLongitude*=*Math.toRadians(lastLongitude);*** double*x*=*(lastLongitude*B*firstLongitude)***Math.cos((firstLatitude*+*lastLatitude)*/*2);** double*y*=*(firstLatitude*B*lastLatitude);*** distance*=*Math.sqrt(x***x*+*y***y)***AppUtils.EARTH_RADIUS;** return*distance;*}*

The   difference   between   total   and   block   distance   is   that   total   distance   is   calculated  between  all   the   consecutive   locations   and   the  block  one   is   only   computed  with   the   first  and  last  location.    Block  distance  is  used  to  consider  still  activity  even  the  detected  activity  is  on_foot  when  that  distance  is  lower  than  the  block  size  (e.g.  movement  inside  our  home,  at  work…).  

//"Total"Duration"segment_total_duration"="(tempLocationArrayList.get(size"<"1).getTime()"<"tempLocationArrayList.get(0).getTime())"/"AppUtils.MILLISECONDS_PER_SECOND;"//"Block"distance"(not"counting"intermediate"points)"to"compare"with"block"size)"block_distance"="AppUtils.distanceCalculation(tempLocationArrayList.get(0).getLatitude(),"tempLocationArrayList.get(0).getLongitude(),"tempLocationArrayList.get(size"<"1).getLatitude(),"tempLocationArrayList.get(size"<"1).getLongitude());"//"Total"distance"for"(int"j"="0;"j"<"size"<"1;"j++)"{"

//"Distance"between"consecutive"locations,"in"meters""" segment_delta_distance"="AppUtils.distanceCalculation("

tempLocationArrayList.get(j).getLatitude(),"" tempLocationArrayList.get(j).getLongitude(),"" tempLocationArrayList.get(j"+"1).getLatitude(),""

tempLocationArrayList.get(j"+"1).getLongitude());"//"Sum"of"all"distance_deltas"of"the"segment"

" total_segment_delta_distance"+="segment_delta_distance;"}"average_segment_speed"="(total_segment_delta_distance"*"3.6)"/"segment_total_duration;"

Page 47: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

45  

III.1.3.4.   Fourth  Stage:  Creating  Mobility  Data  Segments    In   this   last   stage   we   are   going   to   create   the   mobility   data   segments.   These   segments  include   location  points,   activity   type,   distance,   duration,   speed   and  date   of   first   and   last  location  point.  Segment  is  a  class  created  to  store  all  mobility  data  in  a  way  that  can  be  easily  processed,  stored  and  parsed.    It   is   important  to  check  whether  the  detected  activity  corresponds  to  what  we  are  doing  (e.g.  detected  activity   is  on_foot  and  the  speed  calculated   is  40  km/h  à  wrong).  For  this  reason  a  switch-­‐case  followed  with  else-­‐if  are  implemented  in  this  part  of  the  code.  Switch  will   select   the   current   detected   activity   and   with   else-­‐if   the   previous   activity   will   be  selected.    We  have  5  possible  activities  and  for  each  one  5  more  depending  on  the  previous  one.  It  makes  a  total  of  25  blocks  of  code  similar  to  each  other.  Let’s  see  only  one  example  to  not  fill  too  many  pages  with  similar  code.    Detected  Activity:  Vehicle  Previous  Activity:  On  Foot    We  get  the  size  of  location  ArrayList  in  order  to  know  how  many  location  samples  we  have,  then  we  create  an  empty  or  not  segment  to  start  setting  all  its  fields  with  mobility  data.  If  previous  and  current  activity  is  the  same,  there  is  no  need  to  create  a  new  segment  but  to  update   the   previous   segment   adding   the   new   location   samples   and  updating   the   rest   of  parameters.  To  do  that,  temporally  variables  are  created  to  store  previous  parameters  (i.e.  temp_speed,  temp_duration  and  temp_distance).    This  segment   is  added  to  a  global  ArrayList  where  all  obtained  segments  are  going  to  be  stored.    

 

case!"vehicle":!//!segment!vehicle!followed!by!on_foot,!it's!on_foot!+!vehicle!if!(lastActivitiesArrayList.get(0).equals("on_foot"))!{!! if!(average_segment_speed!>!AppUtils.MAX_ON_FOOT_SPEED)!{! ! !! !! lastActivitiesArrayList.clear();!! ! lastActivitiesArrayList.add("vehicle");!!!! ! int!segment_size!=!tempLocationArrayList.size();!!! ! //!create!new!segment!to!store!the!new!values!!! !!!!!!!!!!!!!!!!segment!=!new!Segment();!! ! segment.setFirstLocation(tempLocationArrayList.get(0));!! ! segment.setLastLocation(tempLocationArrayList.get(segment_size!M!1));!! ! segment.setTotalDistance(total_segment_delta_distance);! ! !! !!!!!! ! segment.setTotalDuration(segment_total_duration);!! ! segment.setTotalAverageSpeed(average_segment_speed);!! ! segment.setActivity("vehicle");!! ! segment.updateLocationPoints(tempLocationArrayList);!!! ! //!add!current!segment!! ! segmentArrayList.add(segment);!! ! //!new!values!to!temp_variables!! ! temp_duration!=!segment_total_duration;!! ! temp_distance!=!total_segment_delta_distance;!! ! temp_speed!=!average_segment_speed;!!! ! tmpLastLocation!=!tempLocationArrayList.get(segment_size!M!1);!

Page 48: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 46  

}"else"{"" " if"(block_distance">"AppUtils.BLOCK_RADIUS)"{"" " " lastActivitiesArrayList.clear();"" " " lastActivitiesArrayList.add("on_foot");""" " " int"segment_size"="tempLocationArrayList.size();""" " " //"update"variables"of"current"segment"on_foot"" " " temp_duration"+="segment_total_duration;"" " " temp_distance"+="total_segment_delta_distance;"" " " temp_speed"="(temp_speed"+"average_segment_speed)"/"2;""" " " //"update"segment"data""" " " segment.setTotalDistance(temp_distance);"" " " segment.setTotalDuration(temp_duration);"" " " segment.setTotalAverageSpeed(temp_speed);"" " " segment.setLastLocation(tempLocationArrayList.get(segment_size"J"1));"" " " segment.setActivity("on_foot");"" " " segment.updateLocationPoints(tempLocationArrayList);""" " " //"update"current"segment"" " " segmentArrayList.set(segmentArrayList.size()"J"1,"segment);""" " " tmpLastLocation"="tempLocationArrayList.get(segment_size"J"1);"" " }"else"{"" " " lastActivitiesArrayList.clear();"" " " lastActivitiesArrayList.add("still");"" " " int"segment_size"="tempLocationArrayList.size();"" " " segment"="new"Segment();"

")) if"(segment_size">"1)"{"

" " " tempPlace"="tempLocationArrayList.get(0);"" " for"(int"j"="0;"j"<"segment_size;"j++)"{"" " """""""""""""if"(tempPlace.getAccuracy()">"tempLocationArrayList.get(j).getAccuracy())"" " " " tempPlace"="tempLocationArrayList.get(j);"" " """""""""""""}"" """"""""""""""""}""" "" segment.setFirstLocation(tempLocationArrayList.get(0));"" " segment.setLastLocation(tempLocationArrayList.get(segment_size"J"1));"" " segment.setTotalDistance(0);"" " segment.setTotalDuration(segment_total_duration);"" " segment.setTotalAverageSpeed(0);"" " segment.setActivity("still");"" " segment.addSingleLocationPoint(tempPlace);""" " //"new"values"to"temp_variables"" " temp_duration"="segment_total_duration;"" " temp_distance"="0;"" " temp_speed"="0;""" " segmentArrayList.add(segment);""" " tmpLastLocation"="tempLocationArrayList.get(segment_size"J"1);"" }"""""""""}"}"

As   can   be   appreciated,   average   speed   and   block   distance   are   checked   before  we   can   be  sure  it  is  on_foot,  vehicle  or  still.  In  still  activity  we  are  going  to  add  only  the  most  accurate  location  sample  and  distance  and  speed  will  be  set  to  zero.        

Page 49: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

47  

III.2.   Activity  Recognition  Service    Activity  Recognition  Service  objective  is  to  detect  user’s  activity  and  send  the  result  every  5  seconds  back  to  the  Location  Service  for  further  processing.    

III.2.1.  Starting  Activity  Recognition  Service    This  service  is  initialized  right  after  the  Location  Service  in  the  same  way  as  this  service,  but  instead  of  writing  “LOC”  we  write  “AR”.    mrequesterAR.requestUpdates("AR",2false);2

With   this   line   of   code,   a   pending   intent   is   launched   every   5   seconds   to   our   Activity  Recognition   class   implemented   as   an   IntentService.   Google   recommends   using  IntentService   instead   of   Service   but   its   performance   will   remain   the   same.   The   main  difference   is   that   in   IntentService   all   the   activity   is   handled   in   another   thread   and   stops  itself  when  finished.    

III.2.2.  Architecture    Every   5   seconds   onHandleIntent()   method   is   called,   here   we   can   extract   and   list   all  possible  detected  activities  and  finally  get  the  most  probable  one.    @Override(protected(void(onHandleIntent(Intent(intent)({((( //(If(the(incoming(intent(contains(an(update(( if((ActivityRecognitionResult.hasResult(intent))({((( //(Get(the(update(( ActivityRecognitionResult(result(=(ActivityRecognitionResult.extractResult(intent);(( ( ( (( //(Get(the(most(probable(activity(( DetectedActivity(mostProbableActivity(=(result.getMostProbableActivity();((( //(Get(an(integer(describing(the(type(of(activity((( activityType(=(mostProbableActivity.getType();(( activityName(=(getNameFromType(activityType);((( /*(( (*(At(this(point,(you(have(retrieved(all(the(information(for(the(( (*(current(update.(You(can(display(this(information(to(the(user(in(a(( (*(notification,(or(send(it(to(an(Activity(or(Service(in(a(broadcast(( (*(Intent.(( (*/(( Intent(intentActivity(=(new(Intent("activityRecognition");(( sendActivityLocationBroadcast(intentActivity,(activityName);((( }(}(

 

Page 50: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 48  

III.2.3.  Activity  Detection    Since   the   activity   type   is   in   integer   format,   we   use   a   switch-­‐case   method   called  getNameFromType()   that   returns  a  string  with   the  detected  activity  name.  These  are   the  activity  types  can  be  detected:    

• on_foot:  Activity  type  returned  if  the  citizen  is  either  walking  or  running.    

• bicycle:  Activity  type  returned  if  the  citizen  is  on  a  bicycle.    

• vehicle:   Activity   type   returned   if   the   citizen   is   on   a   motor   vehicle   (e.g.   car,  motorbike,  bus,…).  

 • still:  Activity  type  returned  if  the  citizen  is  not  moving.  

 • unknown:   Activity   type   returned   if   Activity   Recognition   API   is   not   capable   to  

estimate  the  actual  activity.    private!String!getNameFromType(int!activityType)!{!! switch!(activityType)!{!! case!DetectedActivity.IN_VEHICLE:!! ! return!"vehicle";!! case!DetectedActivity.ON_BICYCLE:!! ! return!"bicycle";!! case!DetectedActivity.ON_FOOT:!! ! return!"on_foot";!! case!DetectedActivity.STILL:!! ! return!"still";!! case!DetectedActivity.UNKNOWN:!! ! return!"unknown";!! case!DetectedActivity.TILTING:!! ! //!tilting!changed!to!still!! ! return!"still";!! ! }!! return!"null";!}!

Finally,   we   need   to   broadcast   the   activity   detected   to   the   Location   Service   using  sendBroadcast()  method.    

private!void!sendActivityLocationBroadcast(Intent!_intent,!String!_activity)!{!! ! !! _intent.putExtra("activity",!_activity);!! sendBroadcast(_intent);!}!

                   

Page 51: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

49  

III.3.  Map    Map  needs  to  be  added  as  a   fragment.  There  are  two  ways  to  add  a   fragment  within  our  Activity   (i.e.  window):  dynamically  or  by   code.   In  our   case,   the  map   is   added  by   code  as  follows:  We  add  a  fragment  element  to  the  activity’s  layout  file  to  define  a  Fragment  object.  The  following  code  will  attach  a  MapFragment  [20]  to  the  activity.    

<fragment*************android:id="@+id/map"*************android:layout_width="match_parent"*************android:layout_height="match_parent"*************class="com.google.android.gms.maps.MapFragment"*/>*

To  work  with  the  map,  we  will  need  to  implement  the  OnMapReadyCallback  interface  and  set  an  instance  of  the  callback  on  the  MapFragment  using  getMapAsync()  method.    

MapFragment+mapFragment+=+(MapFragment)+getActivity().getFragmentManager()+++ + + .findFragmentById(R.id.map);+

mapFragment.getMapAsync(this);+

The   callback   is   triggered   when   the   map   is   ready   to   be   used   and   provides   a   non-­‐null  instance  of  GoogleMap [21].  We  can  use  this  GoogleMap  object  to  set  the  view  options  for  the  map  and  add  markers.  The  following  code  will  show  the  first  part  of  the  callback  method  onMapReady().    

@Override(public(void(onMapReady(GoogleMap(googleMap)({(( (

googleMap.setMyLocationEnabled(true);(( googleMap.getUiSettings().setCompassEnabled(true);(( googleMap.getUiSettings().setMapToolbarEnabled(false);((…)(}(

The   Maps   API   offers   different   UI   controls   that   can   be   set   visible   or   invisible.   With   the  above  code  we  activate  two  controls  and  deactivate  one.    First,  we  activate  the  My  Location  button;  this  button  appears  in  the  top  right  corner  of  the  screen.  When  a  user  clicks  the  button,  the  camera  animates  to  focus  on  the  user’s  current  location.  Second  we  activate  the  compass;  this  compass  appears  in  the  top  left  corner.    Finally,   we   deactivate   the   map   toolbar;   this   toolbar   gives   the   user   quick   access   to   the  Google  Maps  application  and  MobilitApp  does  not  need  this  behaviour.    In  the  second  part  of  the  code  we  will  set  up  MobilitApp  behaviour  when  clicking  the  map  or  clicking  an  info  window.  Clicking  an  info  window  will  bring  up  a  window  showing  the  mobility  data  (i.e.  speed,  distance,  duration,  activity,  co2  saved  and  calories  burned).  Info  window  will  appear  when  the  user  clicks  one  of  the  different  markers  and  shows  the  activity  detected  with   the   start  and  end   time.  When   the  map   is   clicked   this  window  will  disappear.    In  the  following  page,  we  will  see  an  example  of  a  marker,  an  info  window  and  the  pop  up  window  and  then,  the  code  that  makes  it  possible.    

Page 52: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 50  

         

       Before  continuing  with  the  above  code,  it’s  important  to  know  how  the  markers  and  lines  are   drawn.  When   the   user  wants   to   display   their  mobility   data   on   the  map,  MobilitApp  loops  through  the  file  with  the  segment  array  with  the  method  readLocation()  (explained  in  History  section)  and  in  each  loop  drawLocation()  is  called.  

Figure  3.2:    Info  Window  Figure  3.3:  Pop-­‐up  Window  

Figure  3.1:  Marker  

public!void!drawLocation(ArrayList<LatLng>!_latlng,!String!_first_time,!String!_last_time,!String!!!! ! _activity,String!_line,!double!_distance,!long!_duration,!double!_speed,!int!index)!!

.. throws!IOException!{!! Marker!marker;!

! int!size!=!_latlng.size();!! if!(!_latlng.isEmpty())!{!! ! if!(first_location_history)!{!! ! ! first_location_history!=!false;!!! ! ! marker!=!googleMap.addMarker(new!MarkerOptions()!!! ! ! ! .position(_latlng.get(0))!

!!! ! ! ! .title(_activity).snippet(_first_time!+!"!N!"!+!_last_time)!

!! ! !!!!!!!!!!!!!.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_still)));!!! ! ! segment!=!new!Segment();!! ! ! segment.setActivity(_activity);!

! ! ! segment.setTotalDistance(_distance);!

! ! ! if!(_line!!=!null)!{!! ! ! ! segment.setLine(_line);!

! ! ! }!

! ! ! segment.setTotalDuration(_duration);!

! ! ! segment.setTotalAverageSpeed(_speed);!

! ! ! segmentArray.add(index,!segment);!

! ! ! hmap.put(marker,!segment);!

! ! }!else!{!! ! ! if!(_activity.equalsIgnoreCase("metro"))!{!! ! ! ! googleMap.addPolyline(new!PolylineOptions().addAll(_latlng)!!! ! ! ! ! .width(10).color(getMetroColor(_line)));!

! ! ! }!else!{!! ! ! ! googleMap.addPolyline(new!PolylineOptions().addAll(_latlng)!!! ! ! ! ! .width(10).color(getColor(_activity)));!! ! ! }!

! ! ! if!(_activity.equals("still"))!{!! ! ! ! marker!=!googleMap.addMarker(new!MarkerOptions()!!! ! ! ! ! .position(_latlng.get(size!N!1)).title(_activity)!

!! ! ! ! ! .snippet(_first_time!+!"!N!"!+!_last_time)!

! ! ! ! ! .icon(BitmapDescriptorFactory!

!! ! ! ! ! .fromResource(R.drawable.ic_still)));!!! ! ! ! segment!=!new!Segment();!! ! ! ! segment.setActivity(_activity);!

! ! ! ! segment.setTotalDistance(_distance);!

! ! ! ! segment.setTotalDuration(_duration);!

! ! ! ! segment.setTotalAverageSpeed(_speed);!

! ! ! ! segmentArray.add(index,!segment);!

! ! ! ! hmap.put(marker,!segment);! ! ! !

Page 53: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

51  

!! ! ! }!else!{!! ! ! ! marker!=!googleMap.addMarker(new!MarkerOptions()!

!! ! ! ! .position(_latlng.get((size!:!1)!/!2)).title(_activity)!! ! ! ! ! .snippet(_first_time!+!"!:!"!+!_last_time)!!! ! ! ! ! .icon(getActivityIcon(_activity)));!

!! ! ! segment!=!new!Segment();!! ! ! ! segment.setActivity(_activity);!! ! ! ! segment.setTotalDistance(_distance);!! ! ! ! segment.setTotalDuration(_duration);!! ! ! ! if!(_line!!=!null)!{!! ! ! ! ! segment.setLine(_line);!! ! ! ! }!! ! ! ! segment.setTotalAverageSpeed(_speed);!! ! ! ! segmentArray.add(index,!segment);!! ! ! ! hmap.put(marker,!segment);!}! }! }! }!

Taking  advantage  of  the  fact  we  have  the  class  Segment,  we  are  going  to  use  it  to  store  the  mobility  parameters  for  later  display  when  user  clicks  the  info  window.  To   be   able   to   know   which   information   is   shown   when   the   user   clicks   in   the   different  markers  displayed  on  the  map  a  HashMap [22]   is  created.  A  HashMap   is  a  data  structure  consisting  of  a  set  of  keys  and  values  in  which  each  key  is  mapped  to  a  single  value.  In  our  case,  the  marker  is  the  key  and  its  value  is  the  segment.  So,  when  the  user  clicks  in  one  of  the  markers  on  the  map,  the  corresponding  value  (i.e.  segment)  will  be  selected.      Every   segment  has   its  own  marker;   these  markers  are   situated   just   in   the  middle  of   the  route  and  contain  the  snippet  (i.e.  the  info  window)  and  its  corresponding  icon  depending  on  the  activity  detected.    Lines   following   the   route   are   easily   done   with   the   method   addPolyline().   We   need  locations   in   a   specific   format   (i.e.   using   LatLng   [23]   class)   and   using   ArrayList.  Furthermore,  we  can  set  its  width  an  colour.    Now  that  we  know  of  the  existence  of  the  HashMap,  we  can  continue  with  the  code  in  the  onMapReady()   method.   This   second   part   of   the   code   will   show   how   to   implement   the  action   to   view   the   mobility   data   when   clicking   the   info   window   and   how   to   make   it  invisible.  The  view  with  all   the  mobility  data   is  always   there  but   it   is   invisible  and  only  when   the  user   clicks   the   info  window   becomes   visible.  When  we  want   to  make   it   invisible   again,  user  only  needs  to  click  anywhere  on  the  map.      First  we  need  to  get  and  convert  the  data  into  a  more  readable  way:  meters  to  kilometres  and  seconds  to  hours,  minutes  and  seconds.  Once  we  have  all  the  data,  we  can  fill  the  two  GridView [24]  using  a  custom  adapter.    

googleMap.setOnInfoWindowClickListener(new9OnInfoWindowClickListener()9{999 @Override99 public9void9onInfoWindowClick(Marker9marker)9{9999 //9Here9we9can9get9the9mobility9data,9set9the9adapters9and9make9the9view9VISIBLE99

}9};9

Page 54: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 52  

As  we  can  see,  we  have  a  reference  of   the  marker   in  onInfoWindowClick()  so,   in  order  to  get   the  mobility   data  we   have   to   use   the  HashMap   and   use   this  marker   as   the   key.   For  example:    double!speed!=!hmap.get(marker).getAverageSpeed();!

We  use  the  same  custom  adapter  as  in  the  Profile  fragment;  the  only  difference  is  that  now  the  TextView [25]  are  in  vertical  rather  than  horizontal.    We  have   two  GridView  so  we  need  two  adapters,  the   first   is  used   for   the  speed,  distance  and  duration  and  the  second  is  used  only  when  the  activity  is  on_foot  (for  calories  burned)  and  bus,  metro  and  train  (for  co2  saved).    

hlv.setAdapter(new.AnotherAdapter(MainActivity.c,.R.layout.dostv,.valors,.oho));.hlv2.setAdapter(new.AnotherAdapter(MainActivity.c,.R.layout.dostv,.valors2,.oho2));.

Finally,  we  need  to  make  visible  the  first  GridView  regardless  of  the  activity  detected,  and  the  second  one  only  when  the  activity  is  suitable  with  co2  saved  and  calories  burned  (i.e.  on_foot,   bus,  metro   and   train).   These   two  GridView   are   inside   a  LinearLayout [26]   to   be  displayed  correctly,  so  this  one  also  needs  to  be  set  to  visible.    

ll.setVisibility(View.VISIBLE);.hlv.setVisibility(View.VISIBLE);.

To   add   the   second  GridView   is   necessary   to  move  up   the   first   one   a   little   bit,   so  we   are  going  to  use  margins.    ViewGroup.MarginLayoutParams5params5=5(MarginLayoutParams)5hlv.getLayoutParams();5int5dens5=5MainActivity.c.getResources().getDisplayMetrics().densityDpi;5if5(hmap.get(marker).getActivity().equalsIgnoreCase("on_foot")5

||5hmap.get(marker).getActivity().equalsIgnoreCase("metro")55 ||5hmap.get(marker).getActivity().equalsIgnoreCase("bus")55 ||5hmap.get(marker).getActivity().equalsIgnoreCase("renfe"))5{555 555555555555params.setMargins(155*5dens5/5160,575*5dens5/5160,5155*5dens5/5160,5155*5dens5/5160);55 555555555555hlv.setLayoutParams(params);55555555555555 555555555555hlv2.setVisibility(View.VISIBLE);5}5else5{55 555555555params.setMargins(155*5dens5/5160,5155*5dens5/5160,5155*5dens5/5160,5155*5dens5/5160);55 555555555hlv.setLayoutParams(params);55 555555555hlv2.setVisibility(View.GONE);5}5

Finally  we  need  to  set  up  the  action  of  making  invisible  this  information  when  user  clicks  on  the  map.  For  this  purpose,  we  will  use  the  setOnMapClickListener()  method.  

googleMap.setOnMapClickListener(new4OnMapClickListener()4{444 @Override44 public4void4onMapClick(LatLng4point)4{444 4 ll.setVisibility(View.GONE);44 4 hlv.setVisibility(View.INVISIBLE);4 4 4 4 4 44 44 hlv2.setVisibility(View.INVISIBLE);44 }4});4

Page 55: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

53  

III.4.   Login/Profile    MobilitApp   lets  user   log   in  using  Facebook  or  Gmail   but   it   is  not  necessary   since   all   the  user’s  data  is  used  locally  and  any  information  is  used  outside.  The  reason  for   logging   in   is   just   to  know  the  username  to  address  him  when  MobilitApp  needs  user  interaction.  Whenever   user   is   logged   in,   profile   window   will   appear   where   all   user   information   is  displayed.  User   information   is  gathered  when  user  clicks   the   login  button  and   finally  stored   locally  using  SharedPreferences  class.  Profile  window  provides  the  user  the  possibility  of  logging  out  by  clicking  the  Log  Out  button.    Login  and  Profile  are  two  different  fragments  and  only  one  is  shown  depending  if  the  user  is  logged  or  not.    if!(nombre.equalsIgnoreCase("noname"))!{!! getSupportFragmentManager().beginTransaction()!! ! ! ! ! .add(R.id.container_loginandperf,!new!LoginFragment(),!!!!!! ! ! ! ! ! "login").commit();!}!else!{!! getSupportFragmentManager().beginTransaction()!! ! ! ! ! .add(R.id.container_loginandperf,!new!PerfilFragment(),!!!! ! ! ! ! ! "perfil").commit();! ! !}!

Nombre  is  the  string  where  the  username  is  stored,  if  the  string  is  equal  to  “noname”  then  login  fragment  is  added  if  not,  profile  fragment  is  the  one  added.    

III.4.1.   Log  in  with  Facebook    When  user   clicks  Facebook  button   [27]   a   callback   is  generated  and  received   in   the   login  fragment:    private!Session.StatusCallback!callback!=!new!Session.StatusCallback()!{!!

@Override!! public!void!call(Session!session,!SessionState!state,!Exception!exception)!{!!! ! onSessionStateChange(session,!state,!exception);!! }!};!

Now  we  need  to  gather  user  information  to  be  later  used  in  profile  window,  to  be  able  to  obtain  this  user  information,  we  need  read  permissions.    authButton.setReadPermissions(Arrays.asList("public_profile",<"email",<"user_birthday"));<

With  these  permissions  we  are  able  to  obtain  the  following  information:  name,  surname,  gender,  birthday  and  the  e-­‐mail.  Once   the   information   is   gathered   and   stored   locally   the   session   is   closed   and   login  fragment  is  finished.      

Page 56: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 54  

private!void!onSessionStateChange(Session!session,!SessionState!state,!Exception!exception)!{!!if!(state.isOpened())!{!! Request.newMeRequest(session,!new!Request.GraphUserCallback()!{!!! ! @Override!! ! public!void!onCompleted(GraphUser!user,!Response!response)!{!! ! ! if!(response!!=!null)!{!! ! ! ! SharedPreferences.Editor!edi!=!prefsFace.edit();!! ! ! ! if!(user.getBirthday()!!=!null)!! ! ! ! ! edi.putString("birthday",!user.getBirthday());!! ! ! ! edi.putString("email",!!user.asMap().get("email").toString());!! ! ! ! edi.putString("nombre",!user.getFirstName());!! ! ! ! edi.putString("apellidos",!user.getLastName());!! ! ! ! edi.putString("genero",!user.asMap().get("gender").toString());!! ! ! ! edi.commit();!! ! ! }!!! ! }!! }).executeAsync();!! ! try!{!! ! ! Thread.sleep(200);!! ! }!catch!(InterruptedException!e)!{!! ! ! ! e.printStackTrace();!! ! }!! ! Intent!i!=!new!Intent();!! ! getActivity().setResult(Activity.RESULT_OK,!i);!! ! getActivity().finish();!!! }!else!if!(state.isClosed())!{!! ! session.closeAndClearTokenInformation();!}!}!

 

III.4.2.   Log  in  with  Google  (Gmail  account)    We  need  to  create  a  Google  client   [28]   to  be  able   to   log   in  with  Google,   the   login   is  done  with  Google  Plus  using  Plus  API.  Furthermore,  we  need  permissions  (also  called  scopes)  to  access  different  sections  of  user  information.    

mPlusClient+=+new+GoogleApiClient.Builder(getActivity(),+this,+this).addApi(Plus.API)++ .addScope(Plus.SCOPE_PLUS_LOGIN).build();+

Once   the  Plus  client   is  built  we  need  a   connection   to  gather  all   the   information,   store   it,  close  session  and  finally  finish  login  fragment.  Connection  is  done  with  connect()  method  and  if  the  connection  is  successful  onConnected()  method  is  called.    With  Scope  Plus   login  permission  we  can  obtain   the  same   information  as  before:  e-­‐mail,  birthday,  name,  surname  and  gender.    

Page 57: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

55  

@Override(public(void(onConnected(Bundle(connectionHint)({((( mConnectionProgressDialog.dismiss();((( p(=(Plus.PeopleApi.getCurrentPerson(mPlusClient);(( acc(=(Plus.AccountApi.getAccountName(mPlusClient);(( editorG(=(prefsGoogle.edit();((( editorG.putString("correo",(acc);(( editorG.putString("birthday",(p.getBirthday());(( editorG.putString("nombre",(p.getName().getGivenName());(( editorG.putString("apellidos",(p.getName().getFamilyName());(( editorG.putInt("genero",(p.getGender());(( editorG.commit();(( signOut();(( Intent(i(=(new(Intent();(( getActivity().setResult(Activity.RESULT_OK,(i);(( getActivity().finish();(}(

signOut()  method  clears  the  default  account  and  disconnects  the  client:    public!void!signOut()!{!! if!(mPlusClient.isConnected())!{!! ! Plus.AccountApi.clearDefaultAccount(mPlusClient);!! ! mPlusClient.disconnect();!! }!}!

 

III.4.3.  Profile  Window    All  the  information  gathered  from  login  plus  the  weight  obtained  in  preferences  windows  is  shown  in  this  window.  The  information  is  displayed  using  a  GridView  generated  in  the  layout   xml   file   with   only   one   column.   GridView   needs   an   adapter   to   display   the  information;  again,  we  will  use  a  custom  one  so  we  can  use  two  text  views  instead  of  one.  In  the  first  text  view  we  will  have  the  information  name  (i.e.  name,  surname,  gender,  age,  weight  and  e-­‐mail).  And  in  the  second  one  its  corresponding  information  stored  locally.      titulo[0])=)getActivity().getResources().getString(R.string.name))+)") ) ";)titulo[1])=)getActivity().getResources().getString(R.string.surname))+)") ) ";)titulo[2])=)getActivity().getResources().getString(R.string.gender))+)") ) ";)titulo[3])=)getActivity().getResources().getString(R.string.age))+)")) ))))))))))))))))";)titulo[4])=)getActivity().getResources().getString(R.string.weight))+)") ) ";)titulo[5])=)getActivity().getResources().getString(R.string.mail))+)") ) ";)

Thanks  to  the  Resources  we  can  set  the  information  name  in  other  languages  (i.e.  English,  Spanish  and  Catalan).    Creating   a   custom   adapter   is   easy:   First  we   need   to   extend   the  ArrayAdapter [29]  class,  next  we   create   the   constructor   to  pass   the   information   and   finally   it   is   time   to   override  getView()  method.  In  this  method  we  set  these  two  text  views  with  the  information  passed  in  the  constructor  and  we  can  change  the  typeface  if  we  want.  

Page 58: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 56  

@Override(public(View(getView(int(position,(View(convertView,(ViewGroup(parent)({(( View(row(=(convertView;(( Typeface(mFontreg(=(Typeface.createFromAsset(this.getContext().getAssets(),(((((( ( "fonts/MontserratGRegular.ttf");(( Typeface(mFontbold(=(Typeface.createFromAsset(this.getContext().getAssets(),(((( ( "fonts/MontserratGBold.ttf");(( if((row(==(null)({(( ( LayoutInflater(inflater(=((LayoutInflater)(((( ( ( context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);(( ( row(=(inflater.inflate(layoutResourceId,(parent,(false);(( }(( TextView(tv(=((TextView)(row.findViewById(R.id.text1);(( tv.setTypeface(mFontbold);(( TextView(tv2(=((TextView)(row.findViewById(R.id.text2);(( tv.setTypeface(mFontreg);(( tv.setText(files[position]);(( tv2.setText(files2[position]);(( return(row;(}(

Finally,  we  add  this  custom  adapter  to  the  GridView:    gvprof.setAdapter(new/AnotherAdapter(getActivity(),/R.layout.dostvh,/titulo,/valores));/

The  layout  passed  as  a  parameter  is  the  xml  containing  the  two  TextView.                                                                  

Page 59: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

57  

III.5.   History    History   is   used   to   show   users   all   generated   files   containing   their   mobility   data.   This  mobility  data  is  in  list  form  and  each  row  is  named  by  its  corresponding  date  (e.g.  10-­‐02-­‐2015).  Mobility  data  stored  can  be  seen  on  the  map  as  routes  with  different  colours  depending  on  the  type  of  activity  also,  can  be  deleted  locally.  

III.5.1.  Structure    History  window  is  created  with  a  single  fragment  in  which  we  can  place  our  list  of  mobility  data  ordered  by  date.  If  the  number  of  files  containing  that  data  is  high,  adding  fragment  normally   could   produce   lag  when   clicking   navigation   drawer   (left  menu).   To   solve   that,  fragment  will  be  added  100ms  after  using  AsyncTask [30].  We  need  a  handler  to  perform  the  populate  action  after  100ms.  This  handler  is  created  is  onCreate()  method  of  History  class.    h"="new"Handler();"" " "h.postDelayed(new"Runnable()"{"" @Override"" public"void"run()"{"" " new"Populate().execute();"

}"},"100);"

Populate()  class  adds  history  fragment  in  the  current  window.    public!class!Populate!extends!AsyncTask<Void,!Void,!Void>!{!!! @Override!! protected!Void!doInBackground(Void...!params)!{!! ! ! ! !!

!! getSupportFragmentManager().beginTransaction().add(R.id.containerhist,!new!!!!! ! HistoryFragment()).commit();!

! ! return!null;!! }!}!

The  view  of  the  fragment  is  generated  from  an  Android  View  called  RecyclerView  [31]  and  it  is  the  flexible  version  of  ListView [32].  This  widget  is  a  container  for  displaying  large  data  sets  that  can  be  scrolled  very  efficiently  by  maintaining  a  limited  number  of  views.  The   main   difference   between   other   views   is   that   as   soon   as   a   user   scrolls   a   currently  visible  item  out  of  view,  this  item’s  view  can  be  recycled  and  reused  whenever  a  new  item  comes  into  view.    RecyclerView   needs   to   be   set.   The   most   important   parameters   are   the   adapter   and   the  layout  manager.  The  adapter  provides  access  to  the  data  items  and  the  layout  manager  is  responsible  for  measuring  and  positioning  item  views  within  the  RecyclerView.    RecyclerView   is   set   in   onActivityCreated()   method,   this   method   is   called   when   the  fragment’s  activity  has  been  created.    The  following  code  shows  how  it  is  done:  

Page 60: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 58  

@Override(public(void(onActivityCreated(Bundle(savedInstanceState)({(

super.onActivityCreated(savedInstanceState);(( ( (( readFolder();(( ( (( rV(=((RecyclerView)(getActivity().findViewById(R.id.recicler);(( rV.setHasFixedSize(true);(( rV.setAdapter(new(HistoryAdapter(getActivity(),(files,(R.layout.customadap));(( rV.setLayoutManager(new(LinearLayoutManager(getActivity()));(( rV.addItemDecoration(new(DividerItemDecoration(getActivity(),((((

(( DividerItemDecoration.VERTICAL_LIST));(}(

ReadFolder()  is  the  method  used  to  read  the  folder  where  all  mobility  data  files  are  stored.  Instead  of  using  a  premade  adapter  like  ArrayAdapter,  MobilitApp  uses  a  custom  adapter  named  HistoryAdapter.  Using  a   custom  adapter   adds   flexibility   to  our  adapter;   therefore  we  can  add  a  button  used  to  delete  files.  This  button  will  be  visible  when  long-­‐clicking  the  desired  row.    When  using  RecyclerView  is  mandatory  to  use  a  ViewHolder  [33]  where  all   the  row  items  will   be   initialized,   in   our   case:   the  TextView  where   the   date   is   shown   and   the   button   to  delete.    public!static!class!ViewHolder!extends!RecyclerView.ViewHolder!{!! public!Button!b;!! public!TextView!tv;!!! public!ViewHolder(View!itemView)!{!! ! super(itemView);!! ! !! ! tv!=!(TextView)!itemView.findViewById(R.id.tvfiles);!! ! b!=!(Button)!itemView.findViewById(R.id.bDelete);! ! !! }!}!

 As   commented  previously,   the   key   of  RecyclerView   class   is   that  View   can   be   recycled   so  initialization   is   done   only   once.   This   ViewHolder   is   needed   in   onCreateViewHolder()  method  because   it   is   called  when  RecyclerView   needs   a  new  ViewHolder  to   represent   an  item.    @Override(public(ViewHolder(onCreateViewHolder(ViewGroup(parent,(int(i)({(( builder(=(new(AlertDialog.Builder(context);(( View(itemLayoutView(=(LayoutInflater.from(parent.getContext()).inflate((( ( ( idlay,(parent,(false);(( ViewHolder(viewHolder(=(new(ViewHolder(itemLayoutView);(( return(viewHolder;(}(

 OnBindViewHolder()  method  is  called  by  RecyclerView   to  display  the  data  at  the  specified  position.  This  method  should  update  the  contents  of  the  View   (above  code)  to  reflect  the  item   at   the   given   position.   Here  we   have   the   three   listeners   for   the   click   and   long-­‐click  

Page 61: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

59  

events.  When  clicking  we  go  back  to  the  map  and  show  the  corresponding  data  and  when  long-­‐clicking  the  delete  button  will  be  shown.      @Override(public(void(onBindViewHolder(final(ViewHolder(vh,(final(int(position)({(( ( (( vh.tv.setText("("+"("+"("+data.get(position));(( vh.b.setVisibility(Button.INVISIBLE);((( vh.itemView.setOnClickListener(new(OnClickListener()({(

(( @Override(( ( public(void(onClick(View(v)({(( ( ( Intent(i(=(new(Intent(context,(MainActivity.class);(( ( ( i.putExtra("archivo",(data.get(position));(( ( ( ((Activity)(context).setResult(Activity.RESULT_OK,(i);(( ( ( ((Activity)(context).finish();((( ( }(( });(( vh.itemView.setOnLongClickListener(new(OnLongClickListener()({(( ( @Override(( ( public(boolean(onLongClick(View(v)({(( ( ( if((antbot(!=(null)(( ( ( ( antbot.setVisibility(Button.INVISIBLE);(( ( ( antbot(=(vh.b;(( ( ( vh.b.setVisibility(Button.VISIBLE);(( ( ( return(true;(( ( ( }(( ( });(

vh.b.setOnClickListener(new(OnClickListener()({(( ( @Override(( ( public(void(onClick(View(v)({(

22 2 final(File(f(=(new(File(ruta,(data.get(position)(( ( ( ( ( ( +("location_segment.json");((( ( ( if((System.currentTimeMillis()(U(f.lastModified()(>(259200000)({(( ( ( ( builder.setMessage(R.string.segur)(( ( ( ( ( .setTitle(R.string.borrar);((( ( ( ( builder.setPositiveButton(R.string.acep,(( ( ( ( ( new(DialogInterface.OnClickListener()({(( ( ( ( @Override(( ( ( ((((((((((((((((public(void(onClick(DialogInterface(dialog,(int(which)({(( ( ( ( ( f.delete();(( ( ( ( ( data.remove(position);(( ( ( ( ( notifyItemRemoved(position);(( ( ( ( }(( ( ( });(

( ( ( builder.setNegativeButton(R.string.cancel,(null);(( ( ( ( builder.create();(( ( ( ( builder.show();(( ( ( }(else({(( ( ( ( builder.setMessage(R.string.rec).setTitle(R.string.borrar);(( ( ( ( ( builder.create().show();(( ( ( }(( ( }(( });(} (

MobilitApp  sends  the  mobility  data  user  wants  to  display  to  the  map,  which  is  in  another  window.  To  do  this,  Intent  is  created  with  the  date  of  the  file  as  an  extra.  Then,  in  the  map  window,  Intent  is  read  and  can  be  properly  shown  to  the  user.  

Page 62: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 60  

 History   window   is   launched   when   clicking   the   left   menu   in   main   window   with  startActivityforResult()  and  with  request  code  12.  Therefore,  when  an   intent   is  sent   from  History  window  onActivityResult()  method  catches  it.    @Override(protected(void(onActivityResult(int(requestCode,(int(resultCode,(Intent(data)({(( (( switch((requestCode)({((( case(12:(( ( if((resultCode(==(Activity.RESULT_OK)({(( ( ( frag.drawRoutes(data.getStringExtra("archivo"));(( ( }(( ( break;(( }(}(

Finally,  we  need  to  call  drawRoutes()  method,  which  is  situated  in  the  fragment,  with  the  extra  data  included  in  the  intent.    public!void!drawRoutes(String!path)!{!!! googleMap.clear();!! readLocation(Environment.getExternalStorageDirectory().getAbsolutePath()!+!!!!! ! "/Download/MobilitApp/"!+!path+!"location_segment.json");!}!

ReadLocation()  method  parses  the  JSON  file  and  loops  through  the  JSONArray [34]  to  draw  one  by  one  every  route.  

JSONObject*jsonObj*=*new*JSONObject(jsonStr);*//*Getting*JSON*Array*node*segmentsData*=*jsonObj.getJSONArray("segments");*for*(int*i*=*0;*i*<*segmentsData.length();*i++)*{** JSONObject*segment*=*segmentsData.getJSONObject(i);** _first_time*=*segment.getString("first*time");** last_time*=*segment.getString("last*time");** _activity*=*segment.getString("activity");** _distance*=*segment.getDouble("distance*(m)");** if*(_activity.equalsIgnoreCase("metro"))*{** * _line*=*segment.getString("line");** }** _duration*=*segment.getLong("duration*(s)");** _speed*=*segment.getDouble("speed*(Km/h)");** _latlngList*=*new*ArrayList<LatLng>();** if*(_latlng*!=*null)*{** * _latlngList.add(_latlng);** }** JSONArray*location_points*=*segment.getJSONArray("location");** for*(int*j*=*0;*j*<*location_points.length();)*{** ***********_latlng*=*new*LatLng(location_points.optDouble(j),*location_points.optDouble(j*+*1));** ***********_latlngList.add(_latlng);** *************j*=*j*+*3;** }***********drawLocation(_latlngList,*_first_time,*_last_time,*_activity,*_line,*_distance,*_duration,*_speed,*i);*}*

Page 63: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

61  

Location  parameters  are  used  to  draw  the  routes  and  the  rest  of  parameters  are  used  to  display  the  information  about  the  journey  (i.e.  speed,  duration,  distance…).    In   order   to   draw   the   journeys,   lines   tracing   the   route   are   used.   Android   uses   the   class  Polyline [35]  to  draw   these   lines  between   location  points.   In   the  Map   section   everything  related  to  the  Map  will  be  explained.    if!(_activity.equalsIgnoreCase("metro"))!{!! googleMap.addPolyline(new&PolylineOptions().addAll(_latlng).width(10)!!!!!!!! ! .color(getMetroColor(_line)));!}!else!{!! googleMap.addPolyline(new&PolylineOptions().addAll(_latlng).width(10)!

!! .color(getColor(_activity)));!} !

                                                                       

Page 64: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 62  

III.6.   Graph    Nowadays   citizens   are   becoming   increasingly   aware   about   the   environment   and   their  health   condition.   Therefore,   calculating   the   calories   burned   by   physical   activity   and   the  amount  of  CO2  emissions  saved  might  be  a  good  to  idea.  Formulas  used  are  very  simple  and  will  be  improved  in  future  releases  of  MobilitApp.  All   the   calculations   are  done   in  post   processing   section   (right   before  uploading   the   file)  and  stored  locally  using  SharedPreferences  class.  

III.6.1.  Calories  Burned  Calculation    MobilitApp   uses   the   metabolic   equivalent   formula   to   estimate   the   number   of   calories  burned.      

 

 Now  that  we  know  the  ratios  for  walking  activity,  estimate  the  number  of  calories  burned  is  easy.  First  we  need  to  loop  through  the  JSONArray   looking  for  all  on_foot  activities  and  get   its  distance  and  speed  parameters.  Finally  apply   the   formula  and   repeat   the  process  until  the  end  of  the  JSONArray.    

private!void!calperday(String!day)!{!!! int!jsonsize;!! float!totcal!=!0;!! if!(!segmentArrayList.isEmpty())!{!! ! jsonsize!=!segmentArrayList.size();!! ! for!(int!i!=!0;!i!<!jsonsize;!i++)!! ! ! if!(segmentArrayList.get(i).getActivity().equalsIgnoreCase("on_foot"))!! ! ! ! totcal!+=!calories(segmentArrayList.get(i).getTotalDuration(),!!!!!! ! ! ! ! segmentArrayList.get(i).getAverageSpeed());!! ! calo.edit().putFloat(day,!totcal).commit();!!! }!}!

The  formula  is  used  in  calories()  method:      

private!double!calories(long!duration,!double!speed)!{!!! double!hours!=!duration!/!3600.0;!! double!parameter;!! if!(speed!<!2.7)!{!! ! parameter!=!2.3;!! }!else!{!! ! parameter!=!2.9;!! }!! return!parameter!*!Integer.parseInt(peso.getString("peso",!"0"))!*!hours;!}!

Table  3.1:  Equivalent  MET  ratio  for  walking  (two  different  speeds)  

Figure  3.1:  Metabolic  Equivalent  Formula  

Page 65: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

63  

III.6.2.  CO2  Saved  Calculation    The  average  CO2  emissions  from  car  are  140  gr/km.  As  before,  we  need  to   loop  through  the   JSONArray   looking   for   all   transport   activities   and   get   its   distance   parameter.   Finally  apply  the  formula  and  repeat  the  process  until  the  end  of  the  JSONArray.    

private!void!co2perday(String!day)!{!!! int!jsonsize;!! double!totco2!=!0;!!! if!(!segmentArrayList.isEmpty())!{!! ! jsonsize!=!segmentArrayList.size();!!! ! for!(int!i!=!0;!i!<!jsonsize;!i++)!! ! ! if!(segmentArrayList.get(i).getActivity().equalsIgnoreCase("metro")!! ! ! ||!segmentArrayList.get(i).getActivity().equalsIgnoreCase("bus")!! ! ! ||!segmentArrayList.get(i).getActivity().equalsIgnoreCase("tram")!! ! ! ||!segmentArrayList.get(i).getActivity().equalsIgnoreCase("renfe"))!!! ! ! ! totco2!+=!co2calc(segmentArrayList.get(i).getTotalDistance());!!! ! co2.edit().putFloat(day,!(float)!totco2).commit();!! }!}!

And  co2cal()  method  applies  the  simple  formula:    

private!double!co2calc(double!distance)!{!!! double!dist!=!distance!/!1000.0;!! return!140!*!dist;!}!

 1.1. Creating  the  graph  

 The  graph  has  been  created  using  a   library  made  by  Jonas  Gehring [36].  MobilitApp  uses  this  library  since  it  is  very  flexible  and  easy  to  understand  and  implement.  The  graph  style  used  is  the  linear  one:    GraphView*graphView*=*new*LineGraphView(this,*getResources().getString(R.string.graphtext));*

We  have  two  datasets,  one  for  the  calories  burned  and  the  other  for  the  CO2  saved.  Each  dataset  will  be  shown  in  different  series  with  different  colour.  The  information  to  fill  the  dataset  is  stored  locally  as  a  shared  preference.    

for!(int!i!=!0;!i!<!size;!i++)!! for!(int!j!=!0;!j!<!size;!j++)!{!!! ! if!(label_calo.toArray()[j].toString().contains(labels[i]))!{!! ! !! datacal[i]!=!new!GraphViewData(i,!calo.getFloat((String)!!!!! ! ! ! label_calo.toArray()[j],!0));!! ! ! dataco2[i]!=!new!GraphViewData(i,!co2.getFloat((String)!!!!! ! ! ! label_calo.toArray()[j],!0));!! ! }!! }!

Page 66: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 64  

Now,  we  need  to  add  these  two  series  to  the  GraphView:    

graphView.addSeries(new/GraphViewSeries("Calorías/(kcal)",/new//// GraphViewSeriesStyle(Color.GREEN,/3),/datacal));/graphView.addSeries(new/GraphViewSeries("Co2/(gr)",/new/GraphViewSeriesStyle(Color.RED,/3),///// dataco2));/

We  can  also  make  some  extra  customizations  like:  adding  the  legend,  select  the  view  port  (i.e.  the  visible  part)  and  make  graph  scrollable  and  scalable:    graphView.setShowLegend(true);5graphView.setLegendAlign(LegendAlign.MIDDLE);5graphView.getGraphViewStyle().setLegendWidth(300);55graphView.setViewPort(0,57);5graphView.setScrollable(true);5graphView.setScalable(true);5

Finally,  it  is  time  to  add  the  GraphView  generated  to  the  current  window:    

LinearLayout+layout+=+(LinearLayout)+findViewById(R.id.gl);+layout.addView(graphView);+

                                                           

Page 67: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

65  

III.7.   Segment  Files    In  this  chapter  we  are  going  to  explain  how  it  is  structured  the  Segment  class,  how  to  write  segments  into  a  JSON  file  and  finally  an  example  of  a  JSON  file.  

III.7.1.  Segment  Class    Segment  class  has  the  following  variables:    private!Location!_first_location;!private!Location!_last_location;!private!double!_total_distance;!private!long!_total_duration;!private!double!_total_average_speed;!private!String!_activity,!_line;!private!ArrayList<Location>!_location_points!=!new!ArrayList<Location>();!

Then  we   have   all   the   get   and   put  method   to   obtain   or  modify   the   above   variables.   For  example:    //getting'Last'Location'public'Location'getLastLocation()'{'' return'this._last_location;'}'//setting'Last'Location'public'void'setLastLocation(Location'last_location)'{'' this._last_location'='last_location;'}'//getting'Location'points'public'ArrayList<Location>'getLocationPoints()'{'' return'this._location_points;'}'//updating'Location'points'public'void'updateLocationPoints(ArrayList<Location>'location_points)'{'' this._location_points.addAll(location_points);'}'//update'single'Location'point'public'void'addSingleLocationPoint(Location'location)'{'' this._location_points.add(location);'}'public'Location'getSingleLocationPoint()'{'' return'this._location_points.get(0);'}'

 

III.7.2.  Writing  JSON  files    Mobility  data  is  stored  in  an  ArrayList  of  Segments  and  every  time  the  segment  is  filled  (i.e.  every  2  minutes)  this  ArrayList  is  stored  in  external  storage.  File  is  not  in  “append  mode”  because  we  write  the  whole  ArrayList  instead  of  each  segment  (one  below  the  other).  This  is   because  we  want   to   store   a   single   activity  when  we   have   two   identical   activities.   So,  instead   of   having   “vehicle-­‐vehicle”   we   will   have   only   one   “vehicle”   with   updated  parameters.    

Page 68: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 66  

WriteSegment()  is  the  method  that  allow  us  to  write  JSON  files.    public!void!writeSegment(String!_filename,!ArrayList<Segment>!_segmentList)!{!! try!{!! ! JSONArray!segments!=!new!JSONArray();!! ! for!(int!k!=!0;!k!<!_segmentList.size();!k++)!{!! ! ! //!create!the!objects!that!will!be!in!each!spot!of!the!segment!array!! ! ! JSONObject!single_segment!=!new!JSONObject();!! ! ! single_segment.put("activity",!_segmentList.get(k).getActivity());!! ! ! single_segment.put("distance!(m)",!_segmentList.get(k)!!! ! ! ! .getTotalDistance());!! ! ! single_segment.put("duration!(s)",!_segmentList.get(k)!!! ! ! ! .getTotalDuration());!!! ! ! if!(_segmentList.get(k).getActivity().equalsIgnoreCase("metro"))!! ! ! ! single_segment.put("line",!_segmentList.get(k).getLine());!!! ! ! single_segment.put("speed!(Km/h)",!_segmentList.get(k)!!! ! ! ! .getAverageSpeed());!! ! ! single_segment.put("first!time",!AppUtils.getTime(_segmentList.get(k)!!! ! ! ! .getFirstLocation().getTime()));!! ! ! single_segment.put("last!time",!AppUtils.getTime(_segmentList.get(k)!!! ! ! ! .getLastLocation().getTime()));!! ! ! //!create!an!array!inside!the!object!for!each!spot!of!the!segment!array!! ! ! JSONArray!location_points!=!new!JSONArray();!!! ! ! for!(int!j!=!0;!j!<!_segmentList.get(k).getLocationPoints().size();!j++)!{!! ! ! ! location_points.put(_segmentList.get(k)!!! ! ! ! ! .getLocationPoints().get(j).getLatitude());!! ! ! ! location_points.put(_segmentList.get(k)!!! ! ! ! ! .getLocationPoints().get(j).getLongitude());!! ! ! ! location_points.put(AppUtils.getTime(_segmentList.get(k)!!! ! ! ! ! .getLocationPoints().get(j).getTime()));!! ! ! }!! ! ! single_segment.put("location",!location_points);!! ! ! segments.put(k,!single_segment);!! ! }!! ! JSONObject!json!=!new!JSONObject();!! ! json.put("segments",!segments);!! ! try!{!! ! ! File!directory!=!new!File(ruta);!! ! ! if!(!directory.exists())!{!! ! ! ! directory.mkdir();!! ! ! }!! ! ! FileWriter!fw!=!new!FileWriter(_filename,!false);!! ! ! fw.append(json.toString(1));!! ! ! fw.flush();!! ! ! fw.close();!! ! }!catch!(IOException!e)!{!! ! ! e.printStackTrace();!! ! }!!! }!catch!(JSONException!e)!{!! ! e.printStackTrace();!! }!}!

   

Page 69: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

67  

In  JSON,  we  can  use  two  different  classes,   JSONObject [37]  and   JSONArray.  A  JSONObject  a  modifiable  set  of  name/value  pairs  while  a  JSONArray  is  an  indexed  sequence  of  values.  In  both   cases,   these   values   may   be   any   mix   of   JSONObject,   JSONArray,   Strings,   Booleans,  Integers,  Longs,  Doubles  and  null.  Our   JSON   files   will   be   written   following   the   structure   of   the   Segment   class   we   have  designed.    First,  we  have   to   loop   through   the  ArrayList   of   Segments   and  using   all   the  put  methods  (seen  before),  put  field  by  field  all  information  of  each  segment  into  a  JSONObject.  The   location   field  contains  an  array  of  multiple   location  samples  with   format  of   latitude,  longitude  and  time.  For  this  reason,  location  will  be  stored  using  a  JSONArray.  Finally,   we   will   put   all   JSONObject,   each   one   of   them  with   mobility   data   from   different  segments,   into  another  JSONArray.  This  array  will  contain  all  the  obtained  segments  and,  at  the  same  time,  it  will  facilitate  its  further  parsing  and  processing.    Once  we  have  all  the  data  stored  in  the  array,  we  proceed  to  write  it  to  a  file.  To  write  a  file  in  Android  we  just  need  to  use  the  FileWriter [38]  class  and  use  its  methods:  append,  flush  and  close.  This  writeSegment()  method  is  going  to  be  used  in  Location  Service.    

III.7.3.   JSON  File  Example      

                                                                   

   

{"""segments":"["""{"""""activity":""on_foot","""""distance"(m)":"49.69776445992602,"""""duration"(s)":"142,"""""speed"(Km\/h)":"1.2599432,"""""first"time":""09:46:44","""""last"time":""09:49:07","""""location":"["""""41.441145,"""""2.1659081,""""""09:46:44","""""41.4410568,"""""2.1660705,""""""09:47:11","""""41.441012,"""""2.1661082,""""""09:47:32","""""41.4409738,"""""2.1661926,""""""09:48:13","""""41.440959,"""""2.1662142,""""""09:48:34","""""41.4410113,"""""2.1663986,""""""09:49:07"""""]"""},"""(…)""]""}"

Page 70: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 68  

                       

Part  IV  Recognition  Algorithms  

                                         

Page 71: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

69  

IV.1.  Transport  Recognition    In   this   section   we   are   going   to   explain   how   MobilitApp   recognizes   the   type   of   public  transport  citizen  is  using.  MobilitApp  can  distinguish  between:  metro,  bus,  tram  and  train.  For  this  purpose  two  Google  APIs  will  be  used:  Directions  API  and  Places  API.  These  two  APIs  are  explained  in  its  respective  section  but  to  summarize,  Places  API  is  a  service  that  returns   information   about   places   (e.g.   establishments,   metro   stations…)   using   HTTP  requests  and  Directions  API  can  search  for  directions  for  several  modes  of  transportation.    Recognition  part  is  implemented  inside  Location  Service.  Metro  recognition  is  done  at  the  same  time  we  receive   location  updates,   the  rest  of  modes  of   transportations  are  done   in  post  processing  section.  This  section  is  done  right  before  the  file  is  uploaded  to  the  server.    Apart  from  these  two  Google  APIs,  MobilitApp  uses  a  database  of  train  and  metro  stations  to   complement   the  algorithms.  These   two  databases  are   in   JSON   format  and  contain   the  name  of  the  stations,  their  location,  etc.  Let’s  see  an  example  of  these  two  databases  that  will  be  explained  later.  

   

IV.1.1.  Metro  Recognition    Metro  Recognition  algorithm  uses  Places  API  to  find  the  nearest  station.  Before  explaining  the   algorithm,   it   is   important   to   know   that   inside   the   metro,   location   accuracy   will   be  higher  than  1000  meters  because  there  is  neither  Wi-­‐Fi  spots  nor  sky  visibility.  This   simple   algorithm  works   as   follows:  when   citizen   enters   a  metro   station   Places  API  will   find   the   nearest   station.   Once   the   metro   journey   is   done   and   citizen   comes   to   the  surface,   Places   will   find   again   the   nearest   station.   Now  we   have   origin   and   destination  stations,  we  can  trace  the  route  following  the  metro  line.  This  algorithm  also  allows  up  to  two  metro  transfers.      

"metro":[))))){)))))))"id":"433",)))))))"line":"L5",)))))))"name":"Cornellà)Centre",)))))))"connections":"T1;T2;T3;R.1;R4",)))))))"lat":"41.357315951168",)))))))"lon":"2.07044325855937")))))},))))){)))))))"id":"432",)))))))"line":"L5",)))))))"name":"Gavarra",)))))))"connections":"",)))))))"lat":"41.3580221811863",)))))))"lon":"2.07929676467967")))))},)…)

"renfe":[((((({((((((("line":"R16",((((((("lat":"40.5958608323863",((((((("lon":"0.449509090610943"(((((},((((({((((((("line":"R16",((((((("lat":"40.8071840875766",((((((("lon":"0.522786433876677"(((((},((((({((((((("line":"R16",((((((("lat":"40.7590269187727",((((((("lon":"0.556463577981504"(((((},((…(

Page 72: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 70  

if!(wifi.isWifiEnabled()!&&!location.getAccuracy()!>!1000)!//!loc!accuracy!>!1000!>>>!Underground!badloc++;!

 Whenever   location   accuracy   is   higher   than   1000  meters   and  Wi-­‐Fi   is   activated   a   global  variable  named  badloc  is  increased  by  one.      if!(badloc!>!4!&&!goodloc!!=!null!&&!!afterbad)!{!! write!=!false;!! loc1!=!goodloc;!! afterbad!=!true;!! block!=!false;!}!

Once  the  segment  block  time  has  passed,  badloc  variable  is  checked  and  if  it  is  greater  than  4  the  following  variables  are  set:  First,  we  set  write  to  false  so  all  the  activity  processing  is  not  done.  Second,  the  last  good  location  (before  the  bad  ones)  is  stored.  Third,  we  set  block  to   false.  Block  variable   is  used  to  avoid  getting  bad   locations  as  good  ones.    Finally  afterbad  variable  is  set  to  true  to  activate  the  following  code:    

if!(afterbad)!{!! locgood.add(goodloc);!

! if!(locgood.size()!>!1)!//!checks!whether!after!bad!locs!good!ones!are!received!but!!!!!!! ! ! !!!!!!!!!//!repeated,!if!this!happens!we!continue!as!before!!! ! if!(locgood.get(locgood.size()!@!1).getLatitude()!==!locgood.get(locgood.size()!@!!!!!!! ! ! 2).getLatitude()&&!locgood.get(locgood.size()!@!1).getLongitude()!==!!

!! ! ! locgood.get(locgood.size()!@!2).getLongitude())!{!! ! ! locgood.remove(locgood.size()!@!1);!

! ! }!

! if!(locgood.size()!>!2)!{!! ! avoid!=!true;!! ! loc2!=!locgood.get(0);!

! ! badloc!=!0;!

! ! afterbad!=!false;!! ! tempLocationArrayList.clear();!

! ! for!(int!index!=!0;!index!<!locgood.size();!index++)!! ! ! tempLocationArrayList.add(locgood.get(index));!//!clear!previous!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! ! ! ! //locations!and!add!new!ones!! ! locgood.clear();!

! ! try!{!! ! ! new!GetPlaces("subway_station").execute(!! ! ! ! new!Double[]!{!loc1.getLatitude(),!loc1.getLongitude(),!!!!!! ! ! ! ! loc2.getLatitude(),!loc2.getLongitude()!}).get();!!

!! ! }!catch!(InterruptedException!|!ExecutionException!e)!{!! ! ! //!TODO!Auto@generated!catch!block!! ! ! e.printStackTrace();!

! ! }!

! }!

}!

It  is  important  to  always  check  if  we  are  receiving  repeated  locations  because  it  is  common  in  bad  location  areas  so,   first  part  of  the  code  checks  that.  In  the  second  part  of  the  code  we  are  receiving  good  locations  after  bad  ones  so,  it  is  supposed  we  have  left  the  metro.    

Page 73: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

71  

In   this   situation,  we  have  origin   and  destination   location   and  Places  API  will   be  used   in  GetPlaces()  class.    Places   API   does   HTTP   requests   to   obtain   places   so   it   is   mandatory   to   extend   the   class  AsyncTask  to  our  GetPlaces  class.  AsyncTask  allows  to  perform  background  operations  and  publish  results  on  the  UI  thread.      The  following  code  will  show  how  this  class  is  implemented:  private!class!GetPlaces!extends!AsyncTask<Double,!Void,!Void>!{!

private!String!places;!! public!GetPlaces(String!places)!{!! ! this.places!=!places;!! }!! @Override!! protected!Void!doInBackground(Double...!loc)!{!! ! PlacesService!service!=!new!PlacesService(API);!! ! ArrayList<String>!result!=!service.findPlaces(loc[0],!loc[1],!loc[2],!loc[3],!places);!! ! if!(result!!=!null)!{!! ! ! if!(result.size()!==!2)!{!! ! ! ! orig!=!result.get(0);!! ! ! ! dest!=!result.get(1);!! ! ! ! if!(!orig.equalsIgnoreCase(dest))!{!! ! ! ! ! getDistance(orig,!dest);!! ! ! ! }!else!{!! ! ! ! ! falsepositive!=!true;!! ! ! ! }!! ! ! }!else!{!! ! ! ! falsepositive!=!true;!! ! ! }!! ! }!else!{!! ! ! falsepositive!=!true;!! ! }!! ! return!null;!! }!}!

FindPlaces()  is  the  method  that  uses  Places  API  (this  method  is  explained  in  its  respective  section).   It   makes   two   http   requests   and   depending   on   the   replies   may   return   three  different  results.    The  first  one  is  that  the  two  requests  return  non-­‐null  result,  it  means  Places  API  has  found  origin  and  destination  station  and  returns  the  name  of  this  two  stations.  The  second  one  is  that  only  one  reply  contains  a  string  with  the  name  of  the  station  and  the  third  one  is  that  any  reply  contains  a  string.  When  we  obtain  the  last  two  results  falsepositive  variable  is  set  to  true  to  leave  this  “metro”  state.    Recognition  is  done  when  we  obtain  two  different  strings  indicating  origin  and  destination  stations  in  that  case,  we  can  proceed  finding  the  route  with  getDistance()  method.  This  method  loops  through  the  stations  database  and  trace  the  route  between  origin  and  destination.   The   used   algorithm   can   process   up   to   one   metro   transfer.   To   differentiate  different   lines   another   parameter   is   added   in   the   segment,   this   parameter   is   the  metro  line.  Doing  that,  we  will  be  able  to  change  the  line  colour  when  tracing  the  route.    There  is  another  database  implemented  as  a  String  Array  that  only  contains  the  name  of  the  stations  in  the  corresponding  order  the  metro  follows.  This  database  of  names  will  be  used  to  search  in  the  other  database  and  find  its  corresponding  location.    

Page 74: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 72  

The  algorithm  used  in  getDistance()  works  as  follows:  we  proceed  from  the  fact  we  have  origin   and   destination   stations   so   the   first   thing   we   should   do   is   to   check   if   the   two  stations  are  on  the  same  line.  If  so,  the  next  step  is  to  find  the  name  of  the  origin  station  in  the   JSON   database   and   get   its   corresponding   location   points.   Then,   loop   through   the  second  database  to  get  the  name  of  the  following  station  and  repeat  the  process  until  we  reach  the  destination  station.    The  following  example  shows  how  it  works  in  a  short  metro  journey.    Metro  L3  journey:    

• Origin-­‐>  Canyelles    • Destination-­‐>  Montbau  

 

                                 

               

                 

{""""""""id":"387",""""""""line":"L3",""""""""name":"Canyelles",""""""""connections":"",""""""""lat":"41.4417702469479",""""""""lon":"2.16633743592508""},"…"{""""""""id":"386",""""""""line":"L3",""""""""name":"Valldaura",""""""""connections":"",""""""""lat":"41.4380515005838",""""""""lon":"2.15693039004997""},"…"{""""""""id":"385",""""""""line":"L3",""""""""name":"Mundet",""""""""connections":"",""""""""lat":"41.4357688982928",""""""""lon":"2.14859090896243""},"…"{""""""""id":"365",""""""""line":"L3",""""""""name":"Montbau",""""""""connections":"",""""""""lat":"41.4306544208465",""""""""lon":"2.14505193131497""},"…"

Page 75: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

73  

However,  if  origin  and  destination  are  not  on  the  same  line  we  should  apply  the  algorithm  twice  as  follows.  Metro   journey   between   Canyelles   (L3)   and   Camp   de   l’Arpa   (L5),   there   are   different  ways/combinations   to   do   this   journey  but   the   algorithm   calculates   all   the   combinations  and  return  the  shortest  one,  just  as  the  citizen  would.  So,  first  the  algorithm  is  used  between  Canyelles  and  Vall  d’Hebrón  and  finally  between  Vall  d’Hebrón  and  Camp  de  l’Arpa.    Figure  4.1  shows  this  journey                                                                                                                

Figure  4.1:  Metro  Journey  (Canyelles-­‐Camp  de  l'Arpa)  

Page 76: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 74  

IV.1.2.  Bus  and  Tram  Recognition    Bus   and   Tram   recognition   use   Google   Directions   API.     Recognition   is   done   right   before  uploading  the  file  to  the  server.  Recognition  algorithm  seeks  for  vehicle  activities  and  using  Directions  API  tries  to  find  bus  or  tram  routes  between  beginning  and  end  points  taking  into  account  departure  time.  So,  maybe  route  between  these  two  points  exists  but  bus/tram  departure  time  did  not  match  start  time  of  the  vehicle  sample.    

for!(int!i!=!0;!i!<!siz;!i++)!{!//!BUS/TRAM!detection!String!t;!

! if!(segmentArrayList.get(i).getActivity().equalsIgnoreCase("vehicle"))!{!! ! if!(segmentArrayList.get(i!J!1).getActivity().equalsIgnoreCase("still"))!{!!!! ! ! //!if!the!previous!sample!is!still!we!get!the!first!vehicle!sample! ! !

!! ! o!=!segmentArrayList.get(i).getFirstLocation();!

! ! }!else!{!!! ! //!else!we!get!this!last!sample!instead!of!the!following!as!the!beginning!sample!

! ! ! o!=!segmentArrayList.get(i!J!1).getFirstLocation();!!

! ! }!

! ! d!=!segmentArrayList.get(i).getLastLocation();!!

! ! try!{!! ! ! t!=!new!GetBusorTram((o.getTime())!/!1000,!((d.getTime())!/!!!

!! ! ! 1000).execute(new!Double[]!{!o.getLatitude(),!o.getLongitude(),!!!!!! ! ! ! d.getLatitude(),!!!d.getLongitude()!}).get();!

!

! ! ! if!(t.equalsIgnoreCase("BUS"))!{!! ! ! ! segmentArrayList.get(i).setActivity("bus");!

! ! ! ! ! continue;!! ! ! }!else!if!(t.equalsIgnoreCase("TRAM"))!{!! ! ! ! segmentArrayList.get(i).setActivity("tram");!! ! ! ! continue;!!! ! ! }!

! ! }!catch!(InterruptedException!|!ExecutionException!e)!{!! ! ! e.printStackTrace();!

! ! }! ! !

! }!

}!

Bus  or  Tram  accelerates  slowly  so  maybe  the  previous  activity  is  not  still  (we  are  waiting).  If  so,  we  consider  this  last  activity  (normally  is  on_foot)  as  the  first  sample  or  origin  of  the  bus   journey.  With   this   consideration   we   can   now   call   the   method   GetBusorTram()   that  uses   the   Directions   API.   Directions   API   also   makes   http   requests   so   it   is   mandatory   to  extend  AsyncTask  class.  

Page 77: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

75  

This   class   is   explained   in   Directions   API   section,   but   to   summarize   it  may   return   three  strings:   “none”,   ”BUS”   or   “TRAM”.   If   it   is   bus   or   tram   we   simply   need   to   change   the  segment  activity  name  with  setActivity().    

IV.1.3.  Train  Recognition    Train  Recognition   is  done   right   after  Bus/Tram  recognition   if   “none”   is   returned.  Places  API   does   not   return   information   about   train   stations   so   the   algorithm  does   not   use   any  Google  API.  The  algorithm  finds  the  nearest  station  for  both  origin  and  destination;  if  that  distance  is  below  50  meters  and  both  stations  belong  the  same  line  vehicle  activity  is  changed  to  train  activity.  This  is  a  simple  algorithm  that  will  be  modified  in  future  releases.  

getRenfeLocs  ()  method  loads  the  trains  station  database  previously  commented.

private!class!GetBusorTram!extends!AsyncTask<Double,!Void,!String>!{!! long!departure_time,!arrival_time;!!! public!GetBusorTram(long!departure_time)!{!! ! this.departure_time!=!departure_time;!33 3 this.arrival_time!=!arrival_time;!! }!! @Override!! protected!String!doInBackground(Double...!params)!{!!! ! DirectionsService!ds!=!new!DirectionsService(params[0],!params[1],!params[2],!params[3],!departure_time,!arrival_time);!! ! return!ds.findBusorTram();!! }!}!

private!boolean!nearstation(double!lat,!double!longi)!{!!! double!min!=!100000;!! double!dist;!! int!min_index!=!0;!! twopositionarray!=!new!ArrayList<>(2);!!!! getRenfeLocs();!!! for!(int!i!=!0;!i!<!arrayrenfe.size();!i++)!{!! ! dist!=!AppUtils.distanceCalculation(arrayrenfe.get(i).latitude,!!!!!! ! ! arrayrenfe.get(i).longitude,!lat,!longi);!! ! if!(dist!<!min)!{!! ! ! min!=!dist;!! ! ! min_index!=!i;!! ! }!! }!! if!(min!<!100)!{!! ! !

!! twopositionarray.add(arrayrenfeline.get(min_index));!! ! return!true;!! }!else!{!! ! return!false;!! }!}!

Page 78: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 76  

                       

Part  V  References  

                                             

Page 79: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

77  

References  [0]  

             [1]  

Kantar  Worldpanel.  Smartphone  OS  market  share.  http://www.kantarworldpanel.com/global/smartphone-­‐os-­‐market-­‐share/    Adrian  Latorre  and  Marc  Llahona.  Project  CICYT  "RESPUESTA  A  EMERGENCIAS  EN  COMUNIDADES  INTELIGENTES  (EMRISCO)".  TEC2013-­‐47665-­‐C4-­‐1-­‐R.  http://sertel.upc.edu/~maguilar/simulators.html    

[2]  Android  Developers.  Activities.  http://developer.android.com/guide/components/activities.html  

[3]  Android  Developers.  Fragments.  http://developer.android.com/guide/components/fragments.html  

[4]  Android  Developers.  FragmentTransaction.  http://developer.android.com/reference/android/app/FragmentTransaction.html  

[5]  Android  Developers.  Services.  http://developer.android.com/guide/components/services.html  

[6]  Android  Developers.  Supporting  Different  Languages.  http://developer.android.com/training/basics/supporting-­‐devices/languages.html  

[7]  Android  Developers.  Storage  Options.  http://developer.android.com/guide/topics/data/data-­‐storage.html  

[8]  Android  Developers.  SharedPreferences.  http://developer.android.com/reference/android/content/SharedPreferences.html  

[9]  Google.  Google  Cloud  Storage.  https://cloud.google.com/storage/?hl=en  [10]  RailsGuides.  Session  ID.  http://guides.rubyonrails.org/security.html#session-­‐id  [11]  Android  Developers.  Location  Request.    

https://developer.android.com/reference/com/google/android/gms/location/LocationRequest.html  

[12]  Android  Developers.  ActivityRecognitionResult.  http://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionResult.html  

[13]  Android  Developers.  DetectedActivity.  http://developer.android.com/reference/com/google/android/gms/location/DetectedActivity.html  

[14]  Google  Developers.  Places  API.  https://developers.google.com/places/documentation/?hl=en  

[15]  Google  Developers.  Directions  API.  https://developers.google.com/maps/documentation/directions/?hl=en  

[16]  Android  Developers.  ArrayList.  http://developer.android.com/reference/java/util/ArrayList.html  

[17]  Google  Developers.  GoogleApiClient.Builder.  http://developer.android.com/reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html  

[18]  Android  Developers.  GoogleApiClient.  http://developer.android.com/reference/com/google/android/gms/common/api/GoogleApiClient.html  

[19]  Android  Developers.  PendingIntent.  http://developer.android.com/reference/android/app/PendingIntent.html  

[20]  Android  Developers.  MapFragment.  

Page 80: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 78  

http://developer.android.com/reference/com/google/android/gms/maps/MapFragment.html  

[21]  Android  Developers.  GoogleMap.  http://developer.android.com/reference/com/google/android/gms/maps/GoogleMap.html  

[22]  Android  Developers.  HashMap.  http://developer.android.com/reference/java/util/HashMap.html  

[23]  Android  Developers.  LatLng.  http://developer.android.com/reference/com/google/android/gms/maps/model/LatLng.html  

[24]  Android  Developers.  GridView.  http://developer.android.com/reference/android/widget/GridView.html  

[25]  Android  Developers.  TextView.  http://developer.android.com/reference/android/widget/TextView.html  

[26]  Android  Developers.  LinearLayout.  http://developer.android.com/reference/android/widget/LinearLayout.html  

[27]  Facebook  Developers.  Facebook  Login  for  Android.  https://developers.facebook.com/docs/android/login-­‐with-­‐facebook/v2.2  

[28]  Google  Developers.  Google+  Sign-­‐in  for  Android.  https://developers.google.com/+/mobile/android/sign-­‐in?hl=en  

[29]  Android  Developers.  ArrayAdapter.  http://developer.android.com/reference/android/widget/ArrayAdapter.html  

[30]  Android  Developers.  AsyncTask.  http://developer.android.com/reference/android/os/AsyncTask.html  

[31]  Android  Developers.  RecyclerView.  http://developer.android.com/reference/android/support/v7/widget/RecyclerView.html  

[32]  Android  Developers.  ListView.  http://developer.android.com/reference/android/widget/ListView.html  

[33]  Android  Developers.  RecyclerView.ViewHolder.  http://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html  

[34]  Android  Developers.  JSONArray.  http://developer.android.com/reference/org/json/JSONArray.html  

[35]  Android  Developers.  Polyline.  http://developer.android.com/reference/com/google/android/gms/maps/model/Polyline.html  

[36]  Jonas  Gehring.  GraphView.    http://www.android-­‐graphview.org/  [37]  Android  Developers.  JSONObject.  

http://developer.android.com/reference/org/json/JSONObject.html  [38]  Android  Developers.  FileWriter.  

http://developer.android.com/reference/java/io/FileWriter.html                

Page 81: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

79  

   

 

 

 

 

 

 

 

 

Part  VI  Annexes  

                   

Page 82: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 80  

                           

Annex  A  

Journey  Examples        

Page 83: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

81  

A.1.   Journey  1    Information:  The   journey  begins   at   6:30   and   ends   at   13:30   and   two   types   of   transport  have  been  used:  car  and  bus  (two  different  lines).    We   should   remember   that   Android   recognizes   only   on_foot,   bicycle,   still,   vehicle   and  unknown  activities  so,  we  need  to  process  the  data  to  recognize  more  types  of  transport.  In   a   first   approach  we   should   notice   only   vehicle   activities   even  when   using   the   bus   or  metro   and   then,   after   the   post   processing   and   using   Google   APIs,   vehicle   activities   will  change  depending  on  the  transport  detected.    

     Left  image  shows  the  “raw”  version,  where  we  only  notice  vehicle  activities,  in  the  image  on  the  right  a  vehicle  activity  has  turned  into  bus  activity.  The  journey  by  car  (black  line  in  the  image  on  the  right)  has  been  a  total  success,  the  route  followed  is  almost  the  same  and  did  not  turn  into  bus  activity  because  there  was  no  route  between  origin  and  destination  with  these  start  and  end  time.        Conversely,  only  one  of  the  two  journeys  by  bus  has  been  detected.  As  we  can  see,  on_foot  activity  is  detected  instead  of  vehicle.  This  is  due  to  a  traffic  jam  in  this  zone  so  low  speeds  were  detected  causing  this  error.          

Page 84: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 82  

A.2.   Journey  2    Information:  The  journey  begins  at  8:05  and  ends  at  14:37  and  the  type  of  transport  used  is   the  Metro  (round  trip).  The  Metro  ride   is  between  Canyelles  and  Lesseps  (Line  3)  and  after  a  long  walk  destination  is  reached.                                                                                                                                          The  Metro  ride  has  been  detected  perfectly  the  first  time  but  not  in  the  return  trip.  Metro  detection   is   triggered  when   consecutive  bad   locations   are   registered   (this   is   the  normal  behaviour  in  the  Metro)  but  sometimes  location  gets  stuck  and  the  same  location  (i.e.  the  last   good   one   location)   is   received   until   we   leave   the   metro.   In   this   situation   Metro  recognition  is  not  triggered  and  then  we  only  have  2  different  locations  and  consequently  a  straight  line  is  displayed  on  the  map.    This  misbehaviour  will   be   corrected   in   future   versions   of  MobilitApp  with   an   improved  algorithm.      

Page 85: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

83  

A.3.   Journey  3    Information:  Home-­‐UPC  journey  (round  trip)  by  bus  (Line  60).                                                                                                                                                    In  both  cases  bus  recognition  was  successful  (one  more  accurate  than  the  other).  There  is  a  section  with  still  activity  in  the  return  trip  because  the  bus  was  still  a  long  time.  It   is   important   to  know  that  all   road   journeys  require   the  GPS  because   there   is  no  Wi-­‐Fi  nearby.  To  avoid  huge  battery  drain,  GPS  is  enabled  every  5  seconds  for  a  maximum  of  4  minutes.    

Page 86: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 84  

A.4.   Journey  4    Information:  Walk  journey  without  using  any  transport.                                                                                                                                                      GPS  was  not   required   in   this   journey;  Wi-­‐Fi   is   sufficient   for   this   kind  of   journeys.  Wi-­‐Fi  positioning  has  a  block  level  accuracy  of  100  meters;  this  is  the  reason  of  some  “peaks”  on  the  map.    

Page 87: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

85  

A.5.   Journey  5    Information:  Journey  by  car.                                                                                                                                                                Conversely,  GPS  was  required  during  this  journey  by  car.  We  only  notice  good  locations  in  the  middle  of   the   journey  because  GPS   takes  a   little   time   to  be  100%  functional  and  not  always  good  locations  are  received  even  in  favourable  conditions.    

Page 88: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 86  

 

 

 

 

 

 

 

 

Annex  B  

MobilitApp  User  Guide                                                  

Page 89: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

87  

                                             

MobilitApp  Android  App    

User  Guide                                

     

Page 90: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 88  

B.1.  Installation    First  we  need  to  enable  Unknown  Sources  (in  Spanish,  orígenes  desconocidos).  To  enable  Unknown  Sources  go  to  Settings  >  Security  and  check  the  box  next  to”  Unknown  Sources   “.   A   dialogue   box  may   pop-­‐up   asking   you   to   confirm   the   action,   just   tap   OK   to  confirm.    MobilitApp   can   be   downloaded   in   APK   (Android   Application   package)   format   in   the  following  URL  (Simulators  and  Code  section):  

http://sertel.upc.edu/~maguilar/indexold.html    Here,  we  can  also  download  the  final  degree  project  where  all  related  with  MobilitApp  is  explained.    Once   you   have   the   APK   file   downloaded   on   your   laptop   or   PC,   connect   your   Android  device   to   the   computer   and   copy   (drag   and   drop)   the  APK   file   to   the  external/internal  storage  on  your  device  (for  example  in  Downloads,  Music  folder,  etc.).  

-­‐ In  Mac  OS,  you  would  need  an  application  named  Android  File  Transfer,  that  can  be  found  in:  https://www.android.com/filetransfer/    

-­‐ In  Windows,  if  you  connect  your  Android  device  to  the  USB  port,  once  the  drivers  have   been   installed   (automatic),   you   could   browse   your   device   like   it   was   a  pendrive.    

 IMPORTANT   -­‐>  If  your  Android  device  does  not  have  a  file  explorer  or  similar,  you  need  to  go   to   the  Play  Store   (in  your  device)  and  search  and  download  ES   File  Manager/  ES  Explorador  de  Archivos  (in  spanish).    Open  File  Manager  and  navigate   to   the  directory  where  you  have  copied  or  downloaded  your  APK   file.  Mostly,   it’s   stored   in   the   “Downloads”   folder   on   your  Android  device   (for  instance  -­‐>  /storage/emulated/0/Download  is  my  Download  Folder).  If  your  device  has  an  SD  card  maybe  you  need  to  navigate  to  /storage/sdcard0.  Once   in  the  directory,   tap  the  APK  icon  and  an  installation  dialogue  box  will  pop-­‐up.  Hit  the  install  button  to  install  the  APK  on  your  Android.                              

Page 91: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

89  

B.2.  Log  in  and  preferences    After  installation,  click  on  the  MobilitApp  icon  to  run  the  app.  Now,  you  will  see  the  login:  

       • You   can   log   in   with   your   Gmail   account   or   with  Facebook.    • Also  you  can  press  Later  (Más  tarde  in  Spanish)  to   log  in  later.                  

 Once  the  login  is  done  or  Later  is  pressed,  the  preferences  screen  will  pop  up.    

             • Here  we  can  select  our  gender,  age  range  and  

set  our  weight.    • Weight   is   important   because   is   needed   to  

compute/estimate   the   number   of   calories   that  you  burn  (on  foot  activity).    • To   continue,   we   need   to   press   the   top   left  

arrow  (marked  with  a  red  circle  in  the  image)                    

Page 92: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 90  

B.3.  General  functions              • Initial   screen   with   the   toolbar,   the   map   and   the  icon  to  zoom  the  map.    • The   toolbar   is   used   to   give   functionality   to  MobilitApp                                

• That  toolbar  consists  in:          

• Top-­‐left   icon:   The   navigation  menu   appears  when  pressed  (showed  in  the  following  screenshot).    

• IMPORTANT:   Shutdown   icon   used   to  completely   finish   the   Application.   By   clicking   that  icon,   the   services   used   to   track   the   position   and  guess  your  activity  finish.    

• Top-­‐right   icon:     Used   to   show   again   the  preferences   screen   in   order   to   modify   any   wrong  values.                

Page 93: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

91  

       

• This   navigation   menu   is   showed   when  you  have  not  logged  in.    

• You  can   log   in  by  pressing   the   text   that  appears   to   the   right   of   the   logo   or   in   Log   in  (Iniciar  Sesión  in  Spanish).    

• History:  Go  to  History  screen.    

• Plots:  Go  to  Plot  screen.    

• Clean   Map:   cleans   the   map   when  markers  and  lines  are  showed.                    

                   

1. Appears  when  you  are  logged  in.    

2. The  main  difference  is  that  we  go  to  the  profile   screen   when   Profile   (Perfil   in   Spanish)  or  your  name  is  pressed.                        

Page 94: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 92  

B.3.1.   History    

• By   pressing   the   different   days   you  will   see   in  the  map  your   approximate   route   in   that   day  with   the  different  activities  (on  foot,  still,  by  bus…).    

• These  files  are  locally  stored  in  your  device  so,  in  order  to  delete  this  files  you  can  longclick/longpress  and  a  button  will  appear.  Note  that  you  can  only  delete  files  created  (at  least)  3  days  ago.    

           

 Let’s  press  one  day  and  something  like  this  will  be  showed:  

             

• For   each   activity   you   have   done   a  marker  will  be  displayed  over  the  map  and  also,  a  line  with  your  approximate  route.    

• If   you   want   to   see   the   information   of  those  routes  you  only  need  to  press  the  marker.                            

Page 95: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

93  

If  we  want  more  detailed  information  we  can  press  that  pop  up  window  and  we  will  see:  speed,  distance,  duration,  co2  saved  or  calories  burned.                                                                                            To  return  to  full  map  we  must  simply  press  some  part  of  the  map.    Note:  These   two  new   icons   are  not   part   of  MobilitApp,   if   you  press   them  you  will   go   to  Google  Maps  application.              

Page 96: PROJECTE FINAL DE CARRERA - arxiv.org

Design  and  implementation  of  an  Android  application  to  analyze  mobility  patterns  of  citizens    

 94  

B.3.2.   Plot                                                                            Plot  to  show  calories  burned  (in  kcal)  and  co2  saved  (in  gr.).                      

Page 97: PROJECTE FINAL DE CARRERA - arxiv.org

 

PFC  Sergi  Casanova  Fouce    

95  

B.3.3.   Profile                                                                              Profile  screen  shows  user  information  based  on  your  login/preferences.  In  future  versions  of  MobilitApp  that  information  may  be  changed  (only  in  MobilitApp  scope).    We  can  close  Facebook  or  Gmail  session  by  pressing  the  Log  Out  button  (Cerrar  sesión  in  spanish).    Note:    The   transport  part   (below   the  profile)   is  non-­‐functional   so,  pressing   that  will  not  affect  in  the  application.