Android 模拟位置辅助类 - Go语言中文社区

Android 模拟位置辅助类


MockPositionManager.java

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.SystemClock;
import android.provider.Settings;

import java.util.ArrayList;
import java.util.List;

/**
 * 模拟位置辅助类
 * 需在AndroidManifest.xml中添加模拟位置权限 android.permission.ACCESS_MOCK_LOCATION
 */
public class MockPositionManager {

    private static MockPositionManager instance = null;
    public static MockPositionManager getInstance() {
        if (instance == null) {
            instance = new MockPositionManager();
        }
        return instance;
    }

    private MockPositionManager() {

    }

    private Context appCtx = null;

    private LocationManager locationManager = null;

    /**
     * 模拟位置的提供者
     */
    private List<String> mockProviders = null;

    public List<String> getMockProviders() {
        return mockProviders;
    }

    /**
     * 是否成功addTestProvider,默认为true,软件启动时防止意外退出导致未重置,重置一次
     * 通过成功addTestProvider判断是否已经设置当前应用进行模拟位置
     */
    private boolean hasAddTestProvider = true;

    public boolean hasAddTestProvider() {
        return hasAddTestProvider || getUseMockPosition();
    }

    /**
     * 是否正在模拟位置
     */
    public boolean isMocking() {
        return hasAddTestProvider;
    }

    /**
     * 初始化
     */
    public boolean init(Context context) {
        appCtx = context.getApplicationContext();
        locationManager = (LocationManager) appCtx.getSystemService(Context.LOCATION_SERVICE);
        if (locationManager == null) {
            return false;
        }

        mockProviders = new ArrayList<>();
        mockProviders.add(LocationManager.GPS_PROVIDER);
//        mockProviders.add(LocationManager.NETWORK_PROVIDER);
        // PASSIVE不允许模拟
//        mockProviders.add(locationManager.PASSIVE_PROVIDER);

        // 防止程序意外终止,没有及时清除模拟GPS
        resetLocationManager();
        return true;
    }

    /**
     * 模拟位置,模拟后系统将不输出NMEA数据
     */
    public boolean mockLocation(Location location) {
        // 系统未开启模拟位置
        if (hasAddTestProvider == false && getUseMockPosition() == false) {
            return false;
        }

        try {
            for (String provider : mockProviders) {
                Location mockLocation = null;
                if (location == null) {
                    mockLocation = new Location(provider);
                } else {
                    mockLocation = new Location(location);
                    mockLocation.setProvider(provider);
                }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
            }
                locationManager.setTestProviderLocation(provider, mockLocation);
            }
            return true;
        } catch (Exception ex) {
            resetLocationManager();
            return false;
        }
    }

    /**
     * 模拟位置是否启用,若启用,则addTestProvider
     */
    private boolean getUseMockPosition() {
        if (isSupportGps() == false) {
            return false;
        }

        // Android 6.0以下,通过Setting.Secure.ALLOW_MOCK_LOCATION判断
        // Android 6.0及以上,需要【选择模拟位置信息应用】,未找到方法,因此通过addTestProvider是否可用判断
        boolean result = (Settings.Secure.getInt(appCtx.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0)
                || Build.VERSION.SDK_INT > 22;
        if (result && hasAddTestProvider == false) {
            try {
                for (String providerStr : mockProviders) {
                    LocationProvider provider = locationManager.getProvider(providerStr);
                    if (provider != null) {
                        locationManager.addTestProvider(
                                provider.getName()
                                , provider.requiresNetwork()
                                , provider.requiresSatellite()
                                , provider.requiresCell()
                                , provider.hasMonetaryCost()
                                , provider.supportsAltitude()
                                , provider.supportsSpeed()
                                , provider.supportsBearing()
                                , provider.getPowerRequirement()
                                , provider.getAccuracy());
                    } else {
                        if (providerStr.equals(LocationManager.GPS_PROVIDER)) {
                            locationManager.addTestProvider(
                                    providerStr
                                    , true, true, false, false, true, true, true
                                    , Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
                        } else if (providerStr.equals(LocationManager.NETWORK_PROVIDER)) {
                            locationManager.addTestProvider(
                                    providerStr
                                    , true, false, true, false, false, false, false
                                    , Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
                        } else {
                            locationManager.addTestProvider(
                                    providerStr
                                    , false, false, false, false, true, true, true
                                    , Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
                        }
                    }
                    locationManager.setTestProviderEnabled(providerStr, true);
                    locationManager.setTestProviderStatus(providerStr, LocationProvider.AVAILABLE, null, System.currentTimeMillis());
                }
                // 模拟位置可用
                hasAddTestProvider = true;
                result = true;
            } catch (SecurityException e) {
                result = false;
            }
        }
        if (result == false) {
            resetLocationManager();
        }

        return result;
    }

    /**
     * 检测设备是否有GPS模块
     */
    private boolean isSupportGps() {
        if (locationManager == null) {
            return false;
        }
        return locationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER);
    }

    /**
     * 取消位置模拟,以免启用模拟数据后无法还原使用系统位置
     * 若模拟位置未开启,则removeTestProvider将会抛出异常;
     * 若已addTestProvider后,关闭模拟位置,未removeTestProvider将导致系统GPS无数据更新;
     */
    public void resetLocationManager() {
        if (locationManager == null) {
            return;
        }

        if (hasAddTestProvider) {
            for (String provider : mockProviders) {
                try {
                    if (locationManager.getAllProviders().contains(provider)) {
                        locationManager.removeTestProvider(provider);
                    }
                } catch (IllegalArgumentException e1) {
                    // 未成功addTestProvider时报错,为防万一有重复调用remove,因此此处不需要输出日志
                } catch (SecurityException e2) {
                    // 若在程序运行过程中,直接关闭系统的允许模拟位置,会导致removeTestProvider报错,
                    // 将导致模拟位置无法正常停止、系统位置不更新的问题
                }
            }
            hasAddTestProvider = false;
        }
    }
}

调用及测试

public class MockPositionActivity extends BaseActivity<AndroidViewModel, ActivityMockPositionBinding> {
    @Override
    protected int getContentViewId() {
        return R.layout.activity_mock_position;
    }

    private LocationManager locationManager;

    /**
     * 是否开启模拟位置
     */
    private volatile boolean isEnableMockLocation = false;

    @SuppressLint("MissingPermission")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 初始化
        MockPositionManager.getInstance().init(this);

        // 开关模拟位置
        toggleMockLocation(isEnableMockLocation);
        dataBinding.setOnMockPositionClickListener(v -> {
            if (isEnableMockLocation) {
                isEnableMockLocation = false;
                MockPositionManager.getInstance().resetLocationManager();
            } else {
                if (MockPositionManager.getInstance().hasAddTestProvider() == false) {
                    Toast.makeText(this, "请在【开发者选项】中设置模拟位置信息应用!", Toast.LENGTH_LONG).show();
                    return;
                }
                isEnableMockLocation = true;

                // 先关上,等待达到条件再模拟
                MockPositionManager.getInstance().resetLocationManager();
            }
            toggleMockLocation(isEnableMockLocation);
        });

        // 获取系统GPS位置
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        RxPermissions permissions = new RxPermissions(this);
        permissions.request(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(aBoolean -> {
                    if (aBoolean) {
                        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);

                        // 模拟位置
                        Observable.interval(1, TimeUnit.SECONDS)
                                .compose(bindToLifecycle())
                                .subscribeOn(Schedulers.computation())
                                .observeOn(AndroidSchedulers.mainThread())
                                .subscribe(aLong -> {
                                    if (isEnableMockLocation) {
                                        Location mockLocation = new Location(LocationManager.GPS_PROVIDER);
                                        mockLocation.setLatitude(30.);
                                        mockLocation.setLongitude(121.);
                                        mockLocation.setAltitude(50.);
                                        mockLocation.setTime(System.currentTimeMillis() / 1000);
                                        mockLocation.setAccuracy(0.01f);
                                        mockLocation.setSpeed(100);
                                        mockLocation.setBearing(90);
                                        MockPositionManager.getInstance().mockLocation(mockLocation);
                                    } else {
                                        MockPositionManager.getInstance().resetLocationManager();
                                    }
                                });
                    }
                });
    }

    @Override
    protected void onDestroy() {
        // 取消模拟位置
        MockPositionManager.getInstance().resetLocationManager();

        // 停止系统定位
        locationManager.removeUpdates(locationListener);
        locationManager = null;
        super.onDestroy();
    }

    private void toggleMockLocation(boolean isEnable) {
        if (isEnable) {
            dataBinding.tvMockPosition.setText("开启");
            dataBinding.ivMockPosition.setImageResource(R.drawable.ic_enable);
        } else {
            dataBinding.tvMockPosition.setText("关闭");
            dataBinding.ivMockPosition.setImageResource(R.drawable.ic_disable);
        }
    }

    private LocationListener locationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            dataBinding.tvTime.setText(new Date(location.getTime()).toString());
            dataBinding.tvLatitude.setText(String.valueOf(location.getLatitude()));
            dataBinding.tvLongitude.setText(String.valueOf(location.getLongitude()));
            dataBinding.tvAltitude.setText(String.valueOf(location.getAltitude()));
            dataBinding.tvSpeed.setText(String.valueOf(location.getSpeed()));
            dataBinding.tvBearing.setText(String.valueOf(location.getBearing()));
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    };
}

效果

在这里插入图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/doris_d/article/details/109536741
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢