zoukankan      html  css  js  c++  java
  • 模拟位置 定位 钉钉打卡 运动轨迹 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
    MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    目录

    模拟位置

    参考:
    允许模拟位置在Android M下的坑
    Android手机模拟GPS位置
    android 模拟位置信息Location使用示例
    参考这个工程

    很多文章中说,M以上选择模拟位置信息应用只能影响当前应用的定位信息,实际测试后发现这个结论是完全错误的,这个定位结果是可以影响所有APP的。

    开启模拟位置的方法

    • Android 6.0 以下:【开发者选项 -> 允许模拟位置】
    • Android 6.0 及以上:【开发者选项 -> 选择模拟位置信息应用】

    需要的权限

    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    判断是否开启了系统模拟位置
    Android 6.0 以下:使用Settings.Secure.ALLOW_MOCK_LOCATION判断。

    boolean canMockPosition = Settings.Secure.getInt(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0

    Android 6.0 及以上:没有【允许模拟位置】选项,同时弃用了Settings.Secure.ALLOW_MOCK_LOCATION,无法通过上面的方法判断。增加了【选择模拟位置信息应用】的方法,需要选择使用模拟位置的应用。但是不知道怎么获取当前选择的应用

    开始、停止模拟位置

    manager.setTestProviderLocation(PROVDER_NAME, location);// 添加并启动GpsMockProvider
    manager.removeTestProvider(PROVDER_NAME);//移除GpsMockProvider

    源码

    <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.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>

    SimpleMockActivity

    public class SimpleMockActivity extends ListActivity {
        private static final String CHHJ = "30.557622,114.337485,0,0";//楚河汉街【30.557622,114.337485,0,0】
    
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            String[] array = {"startService",
                "stopService",
                "打开GPS设置",
                "进入测试页面",};
            setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array));
    
            String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
            ActivityCompat.requestPermissions(this, permissions, 0);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            stopService(new Intent(this, MockIntentService.class));
        }
    
        @Override
        protected void onListItemClick(ListView l, View v, int position, long id) {
            switch (position) {
                case 0:
                    Intent intent = new Intent(this, MockIntentService.class);
                    intent.putExtra("location", Utils.parseLocation(LocationManager.GPS_PROVIDER, CHHJ.split(",")));
                    String name = "任务" + new Random().nextInt(100);
                    intent.putExtra("name", name);
                    startService(intent);
                    Log.i("bqt", "【startService】" + name);
                    break;
                case 1:
                    stopService(new Intent(this, MockIntentService.class));
                    break;
                case 2:
                    startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));//打开GPS设置
                    break;
                case 3:
                    stopService(new Intent(this, MockIntentService.class));
                    startActivity(new Intent(this, MockTestActivity.class));
                    break;
            }
        }
    }

    MockIntentService

    public class MockIntentService extends IntentService {
    
        private static final String PROVDER_NAME = LocationManager.GPS_PROVIDER;
        private LocationManager manager;
        private boolean hasAddTestProvider;
        private boolean stop;
        private boolean hasNewIntent;
    
        public MockIntentService() {
            super("【MockIntentService】");
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i("bqt", "【onCreate】");
            manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); //位置服务
            if (!manager.isProviderEnabled(PROVDER_NAME)) { //Returns the current enabled/disabled status of the given provider.
                Log.i("bqt", "【准备启用Gps Provider】");
                //false, false, false, false, true, false, false, 0, 5 或 false, false, false, false, true, true, true, 0, 5
                manager.addTestProvider(PROVDER_NAME, true, true, false,
                    false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
                manager.setTestProviderEnabled(PROVDER_NAME, true);
                hasAddTestProvider = true;
            }
        }
    
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            Log.i("bqt", "【onStartCommand】");
            hasNewIntent = true;//先把旧的任务停掉,如果不停掉的话,onHandleIntent是不会执行的
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            Log.i("bqt", "【onHandleIntent】");
            hasNewIntent = false;//执行到这里表明前一个任务已经执行完毕了
            if (intent != null && intent.hasExtra("location")) {
                Location location = intent.getParcelableExtra("location");
                String name = intent.getStringExtra("name");
                if (location != null) {
                    while (!hasNewIntent && !stop) {//如果只在有限的时间内发一次,会导致其他APP获取不到定位信息,必须持续刷新
                        location.setTime(System.currentTimeMillis()); //当前时间
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                        }
                        Log.i("bqt", name + "【模拟位置】经度 " + location.getLongitude() + ",维度 " + location.getLatitude());
                        manager.setTestProviderLocation(PROVDER_NAME, location);// 添加并启动GpsMockProvider
                        SystemClock.sleep(1000);
                        Log.i("bqt", "卧槽,如果不加这一行日志,会导致休眠时间不确定!");//绝对不能删
                    }
                    Log.i("bqt", "【任务结束】");
                }
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("bqt", "【onDestroy】");
            if (hasAddTestProvider) {
                try {
                    manager.clearTestProviderEnabled(PROVDER_NAME);
                    manager.removeTestProvider(PROVDER_NAME);//若未成功addTestProvider,或者系统模拟位置已关闭则会出错
                } catch (Exception e) {
                    e.printStackTrace();
                }
                hasAddTestProvider = false;
            }
            stop = true;
        }
    }

    MockTestActivity

    public class MockTestActivity extends ListActivity implements ServiceConnection, LocationListener {
        private Location currentLocation;
        private IMyBinder mIBinder;
        private TextView textView;
        private EditText editText;
        private LocationManager manager;
        private static final String PROVDER_NAME = LocationManager.GPS_PROVIDER;
        private boolean stop;
    
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            String[] array = {"获取当前位置",
                "打开开发者模式,请在【选择模拟位置信息应用】中选择本应用",
                "bindService",
                "unbindService",
                "模拟步行轨迹,请打开高德地图APP查看效果",
                "模拟当前位置,模拟的当前位置可能是模拟位置",
                "模拟输入的位置",
                "模拟在输入位置四周乱转",};
            setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array));
    
            editText = new EditText(this);
            editText.setText("30.557622,114.337485,0,0");
            getListView().addFooterView(editText);
            textView = new TextView(this);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
            textView.setTextColor(Color.BLUE);
            getListView().addFooterView(textView);
    
            manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); //模拟位置服务
            requestLocationUpdates();
        }
    
        @Override
        protected void onListItemClick(ListView l, View v, int position, long id) {
            switch (position) {
                case 0://获取当前位置
                    Location location = Utils.getCurrentLocatioon(this);//经度 114.337675,维度 30.558067
                    if (location != null) {
                        textView.setText(String.format("【当前位置】经度 %s,维度 %s
    ", location.getLongitude(), location.getLatitude()));
                        currentLocation = location;
                    }
                    break;
                case 1://打开开发者模式
                    startActivity(new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
                    break;
                case 2:
                    bindService(new Intent(this, MockService.class), this, Context.BIND_AUTO_CREATE);
                    break;
                case 3:
                    if (mIBinder != null) {
                        unbindService(this);
                        mIBinder = null;
                    }
                    break;
                case 4://模拟步行
                    //百度地图和腾讯地图都屏蔽了模拟位置,但是如果你的应用中集成了这些地图SDK,在你不明确禁用的情况下,还是能使用的
                    if (mIBinder != null) mIBinder.mockMovingLocation();
                    else Toast.makeText(this, "服务未开启", Toast.LENGTH_SHORT).show();
                    break;
                case 5://模拟当前位置
                    if (mIBinder != null) {
                        if (currentLocation != null) mIBinder.mockFixLocation(currentLocation);
                        else Toast.makeText(this, "获取位置失败", Toast.LENGTH_SHORT).show();
                    } else Toast.makeText(this, "服务未开启", Toast.LENGTH_SHORT).show();
                    break;
                case 6:
                    if (mIBinder != null) {
                        mIBinder.mockFixLocation(Utils.parseLocation(PROVDER_NAME, editText.getText().toString().split(",")));
                    } else Toast.makeText(this, "服务未开启", Toast.LENGTH_SHORT).show();
                    break;
                case 7:
                    mockCircle();
                    break;
            }
        }
    
        private void mockCircle() {
            if (mIBinder != null) {
                new Thread(() -> {
                    stop = !stop;
                    while (stop) {
                        String[] datas = editText.getText().toString().split(",");
                        double lat = Double.parseDouble(datas[0]);
                        double lon = Double.parseDouble(datas[1]);
                        Location location = new Location(PROVDER_NAME);//the name of the provider that generated this location
                        location.setLatitude(lat - 0.001 + 0.002 * new Random().nextDouble());// 维度(度)
                        location.setLongitude(lon - 0.001 + 0.002 * new Random().nextDouble());// 经度(度)
                        location.setAccuracy(20f); // 精度(米)
                        SystemClock.sleep(1000);
                        mIBinder.mockFixLocationOnce(location);
                    }
                }).start();
    
            } else Toast.makeText(this, "服务未开启", Toast.LENGTH_SHORT).show();
        }
    
        private void requestLocationUpdates() {
            if (manager.isProviderEnabled(PROVDER_NAME)) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED
                    && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "没有权限", Toast.LENGTH_SHORT).show();
                    return;
                }
                manager.requestLocationUpdates(PROVDER_NAME, 0, 0, this);
            } else {
                Toast.makeText(this, "Gps Provider 不可用", Toast.LENGTH_SHORT).show();
            }
        }
    
        //region ServiceConnection
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("bqt", "【onServiceConnected】" + name.getClassName());
            mIBinder = (IMyBinder) service;
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("bqt", "【onServiceDisconnected】" + name.getClassName());
        }
        //endregion
    
        //region LocationListener
        @Override
        public void onLocationChanged(Location location) {
            textView.append("经度 " + location.getLongitude() + ",维度 " + location.getLatitude() + ",速度" + location.getSpeed() + ",方向" + location.getBearing() + "
    ");
        }
    
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            Log.i("bqt", "【onStatusChanged】" + provider + "," + status);
        }
    
        @Override
        public void onProviderEnabled(String provider) {
            Log.i("bqt", "【onProviderEnabled】" + provider);
        }
    
        @Override
        public void onProviderDisabled(String provider) {
            Log.i("bqt", "【onProviderDisabled】" + provider);
        }
        //endregion
    }

    MockService

    public class MockService extends Service {
        private static final String PROVDER_NAME = LocationManager.GPS_PROVIDER;
        private LocationManager manager;
        private ScheduledExecutorService executor;//定时修改位置信息
        private boolean hasAddTestProvider;
    
        @Override
        public void onCreate() {
            super.onCreate();
            manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            if (!manager.isProviderEnabled(PROVDER_NAME)) {
                manager.addTestProvider(PROVDER_NAME, true, true, false,
                    false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
                manager.setTestProviderEnabled(PROVDER_NAME, true);
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return new MyMyBinder();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            stopExecutor();
            if (hasAddTestProvider) {
                try {
                    manager.clearTestProviderEnabled(PROVDER_NAME);
                    manager.removeTestProvider(PROVDER_NAME);//若未成功addTestProvider,或者系统模拟位置已关闭则会出错
                } catch (Exception e) {
                    e.printStackTrace();
                }
                hasAddTestProvider = false;
            }
        }
    
        private class MyMyBinder extends Binder implements IMyBinder {
    
            @Override
            public void stopMockLocation() {
                stopExecutor();
            }
    
            @Override
            public void mockMovingLocation() {
                stopExecutor();
                executor = Executors.newScheduledThreadPool(2);
                ConcurrentLinkedQueue<Location> locations = Utils.getGaodeTestLocations(MockService.this, PROVDER_NAME);
                executor.scheduleWithFixedDelay(() -> mockTask(locations.poll()), 1, 1, TimeUnit.SECONDS);
            }
    
            @Override
            public void mockFixLocation(Location location) {
                stopExecutor();
                executor = Executors.newScheduledThreadPool(2);
                executor.scheduleWithFixedDelay(() -> mockTask(location), 1, 1, TimeUnit.SECONDS);
            }
    
            @Override
            public void mockFixLocationOnce(Location location) {
                mockTask(location);
            }
    
            private void mockTask(Location location) {
                if (location != null) {
                    location.setTime(System.currentTimeMillis()); //当前时间
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                    }
                    Log.i("bqt", "【模拟位置】经度 " + location.getLongitude() + ",维度 " + location.getLatitude());
                    manager.setTestProviderLocation(PROVDER_NAME, location);// 添加并启动GpsMockProvider
                }
            }
        }
    
        private void stopExecutor() {
            if (executor != null && !executor.isShutdown()) {
                executor.shutdownNow();
            }
        }
    }

    IMyBinder

    public interface IMyBinder {
        void stopMockLocation();
    
        void mockMovingLocation();
    
        void mockFixLocation(Location location);
    
        void mockFixLocationOnce(Location location);
    }

    Utils

    public class Utils {
        private static double PI = 3.14159265358979324;//圆周率 GCJ_02_To_WGS_84
    
        public static ConcurrentLinkedQueue<Location> getGaodeTestLocations(Context context, String name) {
            ConcurrentLinkedQueue<Location> locations = new ConcurrentLinkedQueue<>();
            try {
                InputStreamReader reader = new InputStreamReader(context.getResources().getAssets().open("test_tji.csv"));
                BufferedReader bufferedReader = new BufferedReader(reader);
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    String[] datas = line.split(",");
                    Location location = Utils.initGaodeLocaton(name, datas);
                    locations.add(location);
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return locations;
        }
    
        private static Location initGaodeLocaton(String name, String[] datas) {
            Location location = new Location(name);//the name of the provider that generated this location
            double latitude = Double.parseDouble(datas[0]);
            double longitude = Double.parseDouble(datas[1]);
            double[] transformLocation = Utils.delta(latitude, longitude);
            location.setLatitude(transformLocation[0]);// 维度(度)
            location.setLongitude(transformLocation[1]);// 经度(度)
            location.setSpeed(Float.parseFloat(datas[2]) / 3.6f); //速度(米/秒)
            location.setBearing(Float.parseFloat(datas[3]));// 方向(度)
            location.setAltitude(30);  // 海拔(米)
            location.setAccuracy(20f); // 精度(米)
            return location;
        }
    
        //此方法可以将高德地图SDK获取到的GPS经纬度转换为真实的经纬度,可以用于解决安卓系统使用高德SDK获取经纬度的转换问题。
        private static double[] delta(double lat, double lon) {
            double a = 6378245.0;//克拉索夫斯基椭球参数长半轴a
            double ee = 0.00669342162296594323;//克拉索夫斯基椭球参数第一偏心率平方
            double dLat = transformLat(lon - 105.0, lat - 35.0);
            double dLon = transformLon(lon - 105.0, lat - 35.0);
            double radLat = lat / 180.0 * PI;
            double magic = Math.sin(radLat);
            magic = 1 - ee * magic * magic;
            double sqrtMagic = Math.sqrt(magic);
            dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
            dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
            return new double[]{lat - dLat, lon - dLon};
        }
    
        //转换经度
        private static double transformLon(double x, double y) {
            double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
            ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
            return ret;
        }
    
        //转换纬度
        private static double transformLat(double x, double y) {
            double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
            ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
            return ret;
        }
    
        public static Location getCurrentLocatioon(Context context) {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
                return null;
            }
    
            LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); //模拟位置服务
            List<String> prodiverlist = manager.getProviders(true);
            if (prodiverlist == null || prodiverlist.size() == 0) {
                Toast.makeText(context, "没有可用的位置提供器", Toast.LENGTH_SHORT).show();
                return null;
            }
            Log.i("bqt", "【可用位置服务】" + prodiverlist); //[passive, network, GpsMockProvider, gps]
    
            Location location;
            for (String prodiver : prodiverlist) {
                location = manager.getLastKnownLocation(prodiver);
                if (location != null) { //经度 114.337675,维度 30.558067,速度 0.0,方向 0.0
                    Log.i("bqt", "【当前位置】类型 " + location.getProvider() + ",经度 " + location.getLongitude()
                        + ",维度 " + location.getLatitude() + ",速度 " + location.getSpeed() + ",方向 " + location.getBearing());
                    return location;
                }
            }
    
            Toast.makeText(context, "获取位置失败", Toast.LENGTH_SHORT).show();
            return null;
        }
    
        public static Location parseLocation(String provider, String[] datas) {
            Location location = new Location(provider);//the name of the provider that generated this location
            location.setLatitude(Double.parseDouble(datas[0]));// 维度(度)
            location.setLongitude(Double.parseDouble(datas[1]));// 经度(度)
            location.setSpeed(Float.parseFloat(datas[2])); //速度(米/秒)
            location.setBearing(Float.parseFloat(datas[3]));// 方向(度)
            location.setAltitude(30);  // 海拔(米)
            location.setAccuracy(20f); // 精度(米)
    
            Bundle bundle = new Bundle();
            bundle.putString("info", "来自包青天模拟的位置");
            location.setExtras(bundle); //额外的信息
            return location;
        }
    }

    2019-4-11

  • 相关阅读:
    【WebGoat笔记】 CrossSite Scripting(XSS)
    SQL注入测试工具:Pangolin(穿山甲)
    SQL注入测试工具:Pangolin(穿山甲)
    js取两日期差,包含周六周日?
    CrossSite Scripting(XSS): 跨站脚本攻击介绍
    apmserv虚拟主机不能用set_time_limit(0);
    名称 不是有效的标识符 sql
    最佳的75个安全测试工具
    fzu 1686(DLX 重复点覆盖)
    hdu 3529(DLX)
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/10692941.html
Copyright © 2011-2022 走看看