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.
}
}
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? –
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). –
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. –