Android手机设置——开发人员选择中有一个“允许模仿位置”的选项,开发人员对开发的某些定位软件(一般为地图软件)做测试的时候使用的,功能是模拟手机目前所处的位置(比如手机当前实际位置在中国,但测试软件时要求测试条件为美国,就可以使用该功能进行测试软件模拟定位)。
直接看代码:
package cn.vn.test;
import android.annotation.SuppressLint;
public class SetMockLocation extends Activity {
private static final String TAG = "SetLocation";
private LocationManager mLocationManager;
private Context mContext;
private String mMockProviderName = LocationManager.GPS_PROVIDER;
private double mLongitude = 40.052462;
private double mLatitude = 116.29064;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate");
mContext=this;
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
enableTestProvider();
setLocation();//设置模拟位置信息,也可以建一个thread不断设置虚拟位置信息。
}
@Override
public void onStart() {
super.onStart();
}
public void enableTestProvider(){
ContentResolver res = mContext.getContentResolver();
//获取gps的状态,false为关闭,true为开启。
boolean gps_enable = Settings.Secure.isLocationProviderEnabled(
res, android.location.LocationManager.GPS_PROVIDER);
if(gps_enable){
//关闭gps
Settings.Secure.setLocationProviderEnabled(res,LocationManager.GPS_PROVIDER, false);
}
//获取“允许模拟地点”的状态,0为不允许,1为允许。
int mock_enable = Settings.Secure.getInt(
res, Settings.Secure.ALLOW_MOCK_LOCATION, 0);
if(mock_enable == 0){
try {
//开启 允许模拟地点
Settings.Secure.putInt(res, Settings.Secure.ALLOW_MOCK_LOCATION, 1);
} catch (Exception e) {
Log.e(TAG, "write error", e);
}
}
mLocationManager.addTestProvider(mMockProviderName,
"requiresNetwork" == "", "requiresSatellite" == "",
"requiresCell" == "", "hasMonetaryCost" == "",
"supportsAltitude" == "", "supportsSpeed" == "",
"supportsBearing" == "supportsBearing",
Criteria.POWER_LOW,
Criteria.ACCURACY_FINE);
mLocationManager.setTestProviderEnabled(mMockProviderName, true);
}
@SuppressLint("NewApi")
private void setLocation(){
Log.d(TAG,"setLocation");
Location loc = new Location(mMockProviderName);//这里是模拟的gps位置信息,当然也可以设置network位置信息了。
loc.setAccuracy(Criteria.ACCURACY_FINE);
loc.setTime(System.currentTimeMillis());//设置当前时间
loc.setLatitude(mLongitude); //设置纬度
loc.setLongitude(mLatitude); //设置经度
loc.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
mLocationManager.setTestProviderLocation(mMockProviderName, loc);
}
public void unenableTestProvider(){
int mock_enable = Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0);
if(mock_enable == 0) return;
try {
mLocationManager.clearTestProviderEnabled(mMockProviderName);
mLocationManager.removeTestProvider(mMockProviderName);
} catch (Exception e) {
Log.e(TAG, "", e);
}
try {
//关闭 允许模拟地点
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0);
} catch (Exception e) {
Log.e(TAG, "write error", e);
}
}
@Override
public void onDestroy() {
super.onDestroy();
unenableTestProvider();
}
}
以上的代码中关闭gps和开启允许模拟位置会报错:java.lang.SecurityException: Permission denial: writing to secure settings requires android.permission.WRITE_SECURE_SETTINGS。
配置文件中加入权限:
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
即使这样依旧会报上面的错误,这是因为只有system app才可以有这个权限。
这就要把上面的设置gps和模拟位置的代码删掉。自己去设置中开启模拟位置信息。
这样就可以设置想要的位置了。
别的一些软件可能不显示这个模拟位置,将获取位置信息改为仅设备。这样应该就可以了。
这些设置的模拟位置,我们可以通过平常获取gps和network位置信息获取到。