我正在尝试为一个位置感知应用程序测试地理围栏。我已经连续获得了11次成功,但通常会接连失败几十次。重新启动设备没有帮助。卸载/重新安装也没有帮助。禁用位置,重新启用位置也没有帮助。更改设备的位置精度设置也没有帮助。
我已经在v2.3.4、v4.0.3、v4.4.2、v4.4.4和2个v5.0.1物理设备上进行了测试。其中一个Lollipop设备是带有蜂窝服务的设备。其余设备没有SIM卡,仅用于测试。顺便说一句:没有服务的设备很难通过MockLocation设置它们的位置,但如果它们成功设置了它们的位置,它们几乎从不注册围栏的进入/退出。
位置通过Mock Location更新得足够好,但地理围栏没有任何可靠性地被触发。
我已经谷歌过了。我已经查看了developer.android.com网站上的文档。我已经搜索了StackOverflow。实际上,其他人提出的许多建议都已经在下面的代码中实现了。
那么,如何可靠地使用MockLocation触发我的GeoFence?
我已经在v2.3.4、v4.0.3、v4.4.2、v4.4.4和2个v5.0.1物理设备上进行了测试。其中一个Lollipop设备是带有蜂窝服务的设备。其余设备没有SIM卡,仅用于测试。顺便说一句:没有服务的设备很难通过MockLocation设置它们的位置,但如果它们成功设置了它们的位置,它们几乎从不注册围栏的进入/退出。
位置通过Mock Location更新得足够好,但地理围栏没有任何可靠性地被触发。
我已经谷歌过了。我已经查看了developer.android.com网站上的文档。我已经搜索了StackOverflow。实际上,其他人提出的许多建议都已经在下面的代码中实现了。
那么,如何可靠地使用MockLocation触发我的GeoFence?
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.
}
}