5

Sto provando a testare GeoFences per un'applicazione location-aware. Ho ottenuto ben 11 successi consecutivi, ma in genere sono seguiti dozzine di fallimenti. Il riavvio del dispositivo non aiuta. La disinstallazione/reinstallazione non aiuta. Disabilitare la posizione, riattivare la posizione non aiuta. Cambiare i dispositivi Posizione Le impostazioni di accuratezza non aiutano.GeoFence non innescato w/Mock Location

Ho provato su dispositivi fisici v2.3.4, v4.0.3, v4.4.2, v4.4.4 e 2 v5.0.1. Uno dei dispositivi Lollipop è un dispositivo con servizio cellulare. I restanti dispositivi sono SIMless e utilizzati solo per il test. Nota a margine: i dispositivi senza servizio sono in difficoltà nell'impostare la loro posizione tramite MockLocation, ma se riescono a impostare la loro posizione non registrano quasi mai una voce/uscita di recinzione.

La posizione viene aggiornata tramite Mock Location abbastanza bene, ma i GeoFence non vengono attivati ​​con alcuna affidabilità.

L'ho cercato su Google. Ho esaminato la documentazione sul sito developer.android.com. Ho cercato StackOverflow. In effetti, molti dei suggerimenti fatti da altri sono stati implementati nel codice qui sotto.

Quindi, come posso attivare in modo affidabile GeoFence utilizzando MockLocation?

import android.location.Location; 
import android.location.LocationManager; 

public class GeoFenceTester extends ActivityInstrumentationTestCase2<GeoFenceTesterActivity> { 


    public static final String TAG = GeoFenceTester.class.getSimpleName(); 

    private LocationManager locationManager; 
    private Activity activityUnderTest; 

    protected void setUp() throws Exception { 
     super.setUp(); 
     activityUnderTest = getActivity(); 
     /* 
      MOCK Locations are required for these tests. If the user has not enabled MOCK Locations 
      on the device or emulator these tests cannot work. 
     */ 
     if (Settings.Secure.getInt(activityUnderTest.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) { 
      throw new RuntimeException("Mock locations are currently disabled in Settings - These tests require mock locations"); 
     } 

     Log.i(TAG, "Setup MOCK Location Providers"); 
     locationManager = (LocationManager) activityUnderTest.getSystemService(Context.LOCATION_SERVICE); 

     Log.i(TAG, "GPS Provider"); 
     locationManager.addTestProvider(LocationManager.GPS_PROVIDER, false, true, false, false, false, false, false, Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 
     locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true); 

     Log.i(TAG, "Network Provider"); 
     locationManager.addTestProvider(LocationManager.NETWORK_PROVIDER, true, false, true, false, false, false, false, Criteria.POWER_MEDIUM, Criteria.ACCURACY_FINE); 
     locationManager.setTestProviderEnabled(LocationManager.NETWORK_PROVIDER, true); 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 
      Log.wtf(TAG, String.format("Location Accuracy: %1$d", Settings.Secure.getInt(activityUnderTest.getContentResolver(), Settings.Secure.LOCATION_MODE))); 
     } 

     /* Our EventBus for onEvent() callbacks */ 
     EventBus.getDefault().register(this); 
    } 

    protected void tearDown() { 
     /* Our EventBus for onEvent() callbacks */ 
     EventBus.getDefault().unregister(this); 

     locationManager.removeTestProvider(LocationManager.GPS_PROVIDER); 
     locationManager.removeTestProvider(LocationManager.NETWORK_PROVIDER); 
     locationManager = null; 

     activityUnderTest = null; 

     super.tearDown(); 
    } 

    public void testGeoFence() { 

     /* 
      Using one or the other or both of these makes no difference. 
     */ 
     Location mockGpsLocation = new Location(LocationManager.GPS_PROVIDER); 
     mockGpsLocation.setLatitude(32.652411); 
     mockGpsLocation.setLongitude(-79.938063); 
     mockGpsLocation.setAccuracy(1.0f); 
     mockGpsLocation.setTime(System.currentTimeMillis()); 

     Location mockNetworkLocation = new Location(LocationManager.NETWORK_PROVIDER); 
     mockNetworkLocation.setLatitude(32.652411); 
     mockNetworkLocation.setLongitude(-79.938063); 
     mockNetworkLocation.setAccuracy(1.0f); 
     mockNetworkLocation.setTime(System.currentTimeMillis()); 

     /* 
      setElapsedRealtimeNanos() was added in API 17 
     */ 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 
      mockGpsLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 
      mockNetworkLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 
     } 

     try { 
      Method locationJellyBeanFixMethod = Location.class.getMethod("makeComplete"); 
      if (locationJellyBeanFixMethod != null) { 
       locationJellyBeanFixMethod.invoke(mockGpsLocation); 
       locationJellyBeanFixMethod.invoke(mockNetworkLocation); 
      } 
     } catch (Exception e) { 
      // There's no action to take here. This is a fix for Jelly Bean and no reason to report a failure. 
     } 

     for (int i = 0; i < 30; i++){ 
      Log.i(TAG, String.format("Iterating over our location ... (%1$d)", i)); 
      locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, mockGpsLocation); 
      locationManager.setTestProviderLocation(LocationManager.NETWORK_PROVIDER, mockNetworkLocation); 
      try { 
       Thread.sleep(1000); 
      } catch (Exception e) { 
       Log.e(TAG, e.getMessage(), e); 
      } 
     } 
    } 

    public void onEvent(final GeoFenceUpdateEvent event) { 
     // This doesn't get called about 9/10 times. 
     // I have a GeoFence with a 5000m radius around 32.652411, -79.938063 
    } 

    public void onEvent(final LocationUpdateEvent event) { 
     // This gets called without incident and event.getLatitude() & event.getLongitude() are correct. 
    } 

} 
+0

Hai provato a testare iniziando le posizioni simulate fuori dalla recinzione e quindi entrando/uscendo a un ritmo che sarebbe mappato a camminare/andare in bicicletta/guidare? –

+0

La posizione di partenza è decisamente al di fuori dell'area recintata. Applico gli aggiornamenti di posizione ogni 1000ms. La posizione è stata aggiornata con successo, tuttavia, la recinzione raramente attiva il suo messaggio di entrata. Ho una registrazione che ho escluso per la leggibilità. La mia posizione di partenza è in genere a 89000+ metri dalla posizione desiderata. Dopo circa l'iterazione 3 ricevo un evento di aggiornamento della posizione e la mia distanza dalla posizione desiderata è ~ 0,2 m (arrotondamento). –

+0

Quindi stai viaggiando a velocità di veicoli spaziali o sto leggendo il tuo ultimo commento sbagliato. Penserei che internamente ci sarebbero dei limiti per evitare dati rumorosi. Inoltre, puoi chiarire se stai utilizzando AOSP Location Manager o Google Services. –

risposta

3

Il gestore di Geofence considererà tutte le richieste di ubicazione a livello di sistema in modo uguale, non solo quelle create dalla specifica applicazione. Se si dispone di altre applicazioni o servizi sul dispositivo che attualmente utilizzano i servizi di localizzazione, queste applicazioni esterne produrranno posizioni Lat/Lon utilizzate in considerazione quando si attivano i Geofences.

Dato che si stanno creando posizioni simulate, è possibile che applicazioni esterne o servizi stiano producendo LocationUpdate in conflitto e che questi salti tra posizioni Mock e Real causino i risultati dei test di Geofence instabili.

Potresti essere in grado di confermare ciò disabilitando i tuoi reali servizi di localizzazione nelle impostazioni e utilizzando esclusivamente Mock Locations, o cercare eventuali applicazioni che potrebbero utilizzare i servizi di localizzazione e ricontrollare una volta che tali app specifiche sono state arrestate o disabilitate .

+0

Questo è, in effetti, esattamente ciò che stava accadendo. Ho rimosso un paio di applicazioni che utilizzavano i servizi di localizzazione e ho forzato l'arresto di quelli che volevo mantenere. Tutti i test hanno avuto successo da allora. Grazie per l'aiuto!!! –

+2

Disabilitare completamente i servizi di localizzazione, impedisce l'attivazione di postazioni fittizie nella mia app. –