AndroidPGPS信号模拟
最近有⼀个需求,需要⽤GPS的模拟功能,研究了⼀下源码。
使⽤流程
1. 在开发者模式中的“选择模拟位置信息应⽤”选项,选择我们要模拟的app
2. 在我们的app中调⽤LocationManager.setTestProviderLocation()这个接⼝
开发者模式源码分析
看了开发者模式的源码,路径在/packages/apps/Settings/src/com/android/settings/development
和/frameworks/base/packages/SettingsLib
搜索“选择模拟位置信息应⽤”,在SettingsLib中l的到该声明
进⼀步搜索关键字“mock_location_app”,发现在MockLocationAppPreferenceController.java中使⽤了,所以直接看到这个类。发现勾选我们要模拟的app后主要是调⽤如下代码
private void writeMockLocation(String mockLocationAppName){
removeAllMockLocations();
// Enable the app op of the new mock location app if such.
if(!TextUtils.isEmpty(mockLocationAppName)){
try{
final ApplicationInfo ai = ApplicationInfo(
mockLocationAppName, PackageManager.MATCH_DISABLED_COMPONENTS);
mAppsOpsManager.setMode(AppOpsManager.OP_MOCK_LOCATION, ai.uid,
mockLocationAppName, AppOpsManager.MODE_ALLOWED);
}catch(PackageManager.NameNotFoundException e){
/* ignore */
}
}
}
GPS信号模拟源码分析
看到LocationManager.java的setTestProviderLocation⽅法
⾸先判断了Location是否是完整的,若不完整,则填充默认值。接着通过ILocationManager.aidl调⽤到LocationManagerService。
在最后⾯调⽤了MockProvider的setLocation⽅法,看到MockProvider.java
很简单,直接调⽤了LocationManagerService的reportLocation⽅法,就这样把GPS信息回调上去了。
后续调⽤
mLocationHandler.sendMessageAtFrontOfQueue(m);
handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
handleLocationChangedLocked(myLocation, passive);
receiver.callLocationChangedLocked(notifyLocation);
就这样⼜回到了LocationManager,调⽤LocationChanged(new Location(location))回调到app
APP例⼦
public class MainActivity extends Activity implements View.OnClickListener {
private static final String TAG ="GPS_Test";
private LocationManager locationManager;
private Button btn_set;
private AppOpsManager mAppsOpsManager;
private PackageManagerWrapper mPackageManager;
@Override
protected void onCreate(Bundle savedInstanceState){
setContentView(R.layout.activity_main);
btn_set =findViewById(R.id.btn_set);
btn_set.setOnClickListener(this);
// 调⽤以下⽅法后,就不需要在开发者模式中勾选我们的模拟位置信息的app
mAppsOpsManager =(SystemService(Context.APP_OPS_SERVICE);
mPackageManager =new PackageManager());
writeMockLocation();
try{
Thread.sleep(1000);//延时1秒,确保开发者模式的“选择模拟位置信息应⽤”选项选择了我们的app
}catch(InterruptedException e){
e.printStackTrace();
}
locationManager =(SystemService(LOCATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
// Android M Permission check
List<String> permissionLists =new ArrayList<>();
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
permissionLists.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED){ permissionLists.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.MANAGE_APP_OPS_MODES)!= PackageManager.PERMISSION_GRANTED){ permissionLists.add(Manifest.permission.MANAGE_APP_OPS_MODES);
}
if(!permissionLists.isEmpty()){//说明肯定有拒绝的权限
}else{
Log.d(TAG,"ALL have permissions");
}
}
// 添加并启动GpsProvider
locationManager.addTestProvider(LocationManager.GPS_PROVIDER,false,false,
false,false,true,
false,false,0,5);
// 开启测试Provider
locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER,true);
// 设置监听
}
private void writeMockLocation(){
try{
String mockLocationAppName ="android.gpstest";
final ApplicationInfo ai = ApplicationInfo(
mockLocationAppName, PackageManager.MATCH_DISABLED_COMPONENTS);
mAppsOpsManager.setMode(AppOpsManager.OP_MOCK_LOCATION, ai.uid,
mAppsOpsManager.setMode(AppOpsManager.OP_MOCK_LOCATION, ai.uid,
mockLocationAppName, AppOpsManager.MODE_ALLOWED);
}catch(PackageManager.NameNotFoundException e){
/* ignore */
}
}
protected final LocationListener locationListener =new LocationListener(){
@Override
public void onLocationChanged(Location location){
Log.d(TAG," onLocationChanged "+ String());
}
@Override
public void onStatusChanged(String provider,int status, Bundle extras){
Log.d(TAG,"onStatusChanged "+ provider);
}
@Override
public void onProviderEnabled(String provider){
Log.d(TAG," onProviderEnabled "+ provider);
}
@Override
public void onProviderDisabled(String provider){
Log.d(TAG," onProviderDisabled "+ provider);
}
};
@Override
public void onClick(View v){
Id()){
case R.id.btn_set:
// 创建新的Location对象,并设定必要的属性值
Location mockLocation =new Location(LocationManager.GPS_PROVIDER);
android模拟点击
mockLocation.setLatitude(39.820036);
mockLocation.setLongitude(116.813751);
mockLocation.setAccuracy(501);
mockLocation.setTime(System.currentTimeMillis());
mockLocation.setBearing(1.2f);
mockLocation.setSpeed(10.8f);
mockLocation.setVerticalAccuracyMeters(1.5f);
mockLocation.setBearingAccuracyDegrees(3.3f);
// 这⾥⼀定要设置nonasecond单位的值,否则是没法持续收到监听的
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN){
mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
}
// 设置最新位置,⼀定要在requestLocationUpdate完成后进⾏,才能收到监听
locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, mockLocation);
break;
}
}
}
<!--l-->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="schemas.android/apk/res/android"
package="android.gpstest">
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论