【问题标题】:GeoFence Not Triggered w/Mock Location没有使用模拟位置触发 GeoFence
【发布时间】:2015-03-29 00:17:54
【问题描述】:

我正在尝试为位置感知应用程序测试 GeoFences。我已经获得了多达 11 次连续的成功,但之后通常会出现数十次失败。重新启动设备没有帮助。卸载/重新安装没有帮助。禁用位置,重新启用位置没有帮助。更改设备的位置精度设置没有帮助。

我已经在 v2.3.4、v4.0.3、v4.4.2、v4.4.4 和 2 个 v5.0.1 物理设备上进行了测试。 Lollipop 设备之一是具有蜂窝服务的设备。其余设备是无 SIM 卡的,仅用于测试。旁注:没有服务的设备很难通过 MockLocation 设置它们的位置,但如果它们设法设置它们的位置,它们几乎不会注册栅栏入口/出口。

已通过模拟位置很好地更新了位置,但没有以任何可靠性触发 GeoFence。

我已经用谷歌搜索过了。我查看了 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.
    }

}

【问题讨论】:

  • 您是否尝试过通过在围栏外启动模拟位置然后以适合步行/骑自行车/驾驶的速度进出进行测试?
  • 起始位置肯定在围栏区域之外。我每 1000 毫秒应用一次位置更新。位置已成功更新,但是栅栏很少触发其进入消息。为了便于阅读,我已经排除了日志记录。我的起始位置通常距离所需位置 89000 多米。大约在第 3 次迭代之后,我收到了一个位置更新事件,我与所需位置的距离约为 0.2m(四舍五入)。
  • 所以你是在以宇宙飞船的速度旅行,还是我读错了你的最后一条评论。我认为在内部会有一些限制来防止嘈杂的数据。您能否说明您使用的是 AOSP 位置管理器还是 Google 服务。
  • AOSP(问题已更新)至于我的旅行速度:没关系。我在栅栏外,然后我在栅栏内。
  • 更多的旁注,因为您正在使用 AOSP 进行测试 - 当我使用 Google 服务进行测试时,我发现如果我将模拟位置更新限制为“合理”并让结果解决考虑到“噪音”,我能够获得一致的结果,但我的测试场景与您的不同(5-10 秒/更新,单独的应用程序提供模拟,Google 服务)所以也许其他人有想法。跨度>

标签: android unit-testing geolocation android-location geofencing


【解决方案1】:

地理围栏管理器将平等考虑所有系统范围的位置请求,而不仅仅是您的特定应用程序发出的请求。如果您的设备上有任何其他应用程序或服务当前正在使用定位服务,则这些外部应用程序会生成在触发地理围栏时考虑使用的纬度/经度位置。

鉴于您正在生成模拟位置,外部应用程序或服务可能会生成冲突的 LocationUpdates,并且这些模拟位置和真实位置之间的跳跃会导致您的地理围栏测试结果不稳定。

您可以通过在设置中禁用您的真实位置服务并纯粹使用模拟位置来确认这一点,或者查找当前可能正在使用位置服务的任何应用程序,并在这些特定应用程序停止或禁用后重新测试。

【讨论】:

  • 事实上,这正是正在发生的事情。我删除了几个使用位置服务的应用程序,并强制停止了那些我想保留的应用程序。从那以后,所有的测试都成功了。谢谢你的帮助!!!
  • 完全禁用位置服务,防止在我的应用中触发模拟位置。
猜你喜欢
  • 2017-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多