c# - 使用 LocationManager.SetProviderLocation 模拟位置,如何使位置完整

标签 c# android xamarin.android android-location

我试图通过创建 Location 实例然后使用 LocationManager.SetTestProviderLocation(string providerName, Locatin location) 方法来模拟我的位置。

例如:

Location location = new Location(providerName)
{
    Latitude = 51.20958,
    Longitude = 2.92372,
    Accuracy = 100.0f,
    Time = DateTime.Now.Ticks,
    Altitude = 1.0,
    Speed = 0.0f,
    Bearing = 0.0f,
    Provider = providerName,
};


locationManager.SetTestProviderLocation(providerName, location);

这总是导致异常:

"Incomplete location object, missing timestamp or accuracy? Location[gps 51.209580,2.923720 acc=1 et=?!? alt=1.0 vel=0.0 bear=0.0]"

我找到了一些关于这个主题的信息here .
作者提到 LocationManger 检查一个 isComplete(方法)
以确定 Location 是否完整。

我希望该类的单声道版本具有 IsComplete 属性
和 MakeComplete 方法,但它们不存在(或者至少我找不到它们)

仔细观察 Android SDK source code :

public void makeComplete() 
{
        if (mProvider == null) mProvider = "?";
        if (!mHasAccuracy) {
            mHasAccuracy = true;
            mAccuracy = 100.0f;
        }
        if (mTime == 0) mTime = System.currentTimeMillis();
        if (mElapsedRealtimeNanos == 0) mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
}

我猜是“et=?!?”异常中的值指的是 mElapsedRealtimeNanos 字段
并且由于我无法知道访问该字段我无法让模拟工作。

我是否遗漏了什么,这是 Android 版 Mono 缺少的功能还是
是否有另一种方法可以让它发挥作用。

注意:我知道有一些方法可以使用 DDMS 设置虚假位置, 但我正在寻找一种自动化位置模拟的方法

更新

发布这个问题一段时间后,我意识到我的目标不是 API 级别 16。
因此,Android 版 Mono 没有公开 ElapsedRealtimeNanos 属性。

切换到 API 级别 16 后,该属性可用。然而,它没有,
提供一个MakeComplete 方法。 (也许这是一个错误/缺少的功能)。

所以我做了一个快速的解决方案来验证行为:

Location location = new Location(providerName)
{
    Longitude = locations[position, 0],
    Latitude = locations[position, 1],                    
    Accuracy = 100.0f,
    Time = DateTime.Now.Ticks,
    Altitude = 1.0,
    Speed = 0.0f,
    Bearing = 0.0f,
    Provider = providerName,
    ElapsedRealtimeNanos = (long)(TimeSpan.FromTicks(DateTime.Now.Ticks)
                                          .TotalMilliseconds * 1000000)
};

虽然这解决了 Jelly Bean 设备(4.1 或更高版本)的问题,但代码
会在旧设备上中断。这就是@Cheesebaron 建议的解决方案发挥作用的地方。

最佳答案

您可能需要使用如下代码通过 JNI 访问 makeComplete:

public class MyLocation : Location
{
    protected MyLocation(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
    }

    public MyLocation(Location l) : base(l)
    {
    }

    public MyLocation(string provider) : base(provider)
    {
    }

    public void MakeComplete()
    {
        if ((int)Build.VERSION.SdkInt >= 16)
        {
            var locationClass = JNIEnv.FindClass("android/location/Location");
            var makeComplete = JNIEnv.GetMethodID(locationClass, "makeComplete", "()V");
            JNIEnv.CallVoidMethod(Handle, makeComplete);
        }
    }
}

然后只需在调用 MakeComplete 的地方使用 MyLocation 的实例。但是它只能在 API 16 上运行。

关于c# - 使用 LocationManager.SetProviderLocation 模拟位置,如何使位置完整,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19354331/

相关文章:

c# - c# Windows 应用程序中的线程

c# - 如何显示所有错误的单词

java - Android使用抽屉导航滑动菜单

android - Android 中的 OpenGL

android - 使用 SkiaSharp 在 Xamarin 中加载 SVG 文件

c# - 在 ArrayAdapter 构造函数上抛出 Android NoSuchMethodError

c# - 在 C# 中是否有可视化网格拓扑的控件?

c# - 桌面桥toast打开应用程序

java - 在 android 中使用谷歌地图无法调用 SetOnItemClickListener 事件

xamarin.android - Visual Studio 15.6 不再支持 Xamarin 组件