diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/Gps.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Gps.java new file mode 100644 index 0000000..d8b4376 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Gps.java @@ -0,0 +1,33 @@ +package com.dahe.mylibrary.utils; + +/** + * @ClassName Gps + * @Author john + * @Date 2024/12/13 17:25 + * @Description TODO + */ +public class Gps { + private double wgLon; + private double wgLat; + + public Gps(double wgLat,double wgLon) { + this.wgLat = wgLat; + this.wgLon = wgLon; + } + + public double getWgLon() { + return wgLon; + } + + public void setWgLon(double wgLon) { + this.wgLon = wgLon; + } + + public double getWgLat() { + return wgLat; + } + + public void setWgLat(double wgLat) { + this.wgLat = wgLat; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/RxLocationUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/RxLocationUtils.java new file mode 100644 index 0000000..5e8b955 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/RxLocationUtils.java @@ -0,0 +1,539 @@ +package com.dahe.mylibrary.utils; + + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Address; +import android.location.Criteria; +import android.location.Geocoder; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.location.LocationProvider; +import android.os.Bundle; +import android.provider.Settings; +import android.util.Log; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.List; +import java.util.Locale; + +/** + * @author ondear + * time : 16/11/13 + * desc : 定位相关工具类 + */ +public class RxLocationUtils { + + public static double pi = 3.1415926535897932384626; + public static double a = 6378245.0; + public static double ee = 0.00669342162296594323; + private static OnLocationChangeListener mListener; + private static MyLocationListener myLocationListener; + private static LocationManager mLocationManager; + + /** + * 判断Gps是否可用 + * + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isGpsEnabled(Context context) { + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + return lm.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + /** + * 判断定位是否可用 + * + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isLocationEnabled(Context context) { + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) || lm.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + /** + * 打开Gps设置界面 + */ + public static void openGpsSettings(Context context) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + /** + * 注册 + *

使用完记得调用{@link #unregister()}

+ *

需添加权限 {@code }

+ *

需添加权限 {@code }

+ *

需添加权限 {@code }

+ *

如果{@code minDistance}为0,则通过{@code minTime}来定时更新;

+ *

{@code minDistance}不为0,则以{@code minDistance}为准;

+ *

两者都为0,则随时刷新。

+ * + * @param minTime 位置信息更新周期(单位:毫秒) + * @param minDistance 位置变化最小距离:当位置距离变化超过此值时,将更新位置信息(单位:米) + * @param listener 位置刷新的回调接口 + * @return {@code true}: 初始化成功
{@code false}: 初始化失败 + */ + public static boolean register(Context context, long minTime, long minDistance, OnLocationChangeListener listener) { + if (listener == null) return false; + if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); + ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); + return false; + } + mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + mListener = listener; + if (!isLocationEnabled(context)) { + ToastUtils.showToast(context, "无法定位,请打开定位服务"); + return false; + } + String provider = mLocationManager.getBestProvider(getCriteria(), true); + + Location location = mLocationManager.getLastKnownLocation(provider); + if (location != null) listener.getLastKnownLocation(location); + if (myLocationListener == null) myLocationListener = new MyLocationListener(); + mLocationManager.requestLocationUpdates(provider, minTime, minDistance, myLocationListener); + return true; + } + + /** + * 注销 + */ + public static void unregister() { + if (mLocationManager != null) { + if (myLocationListener != null) { + mLocationManager.removeUpdates(myLocationListener); + myLocationListener = null; + } + mLocationManager = null; + } + } + + /** + * 设置定位参数 + * + * @return {@link Criteria} + */ + private static Criteria getCriteria() { + Criteria criteria = new Criteria(); + //设置定位精确度 Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精细 + criteria.setAccuracy(Criteria.ACCURACY_FINE); + //设置是否要求速度 + criteria.setSpeedRequired(false); + // 设置是否允许运营商收费 + criteria.setCostAllowed(false); + //设置是否需要方位信息 + criteria.setBearingRequired(false); + //设置是否需要海拔信息 + criteria.setAltitudeRequired(false); + // 设置对电源的需求 + criteria.setPowerRequirement(Criteria.POWER_LOW); + return criteria; + } + + /** + * 根据经纬度获取地理位置 + * + * @param context 上下文 + * @param latitude 纬度 + * @param longitude 经度 + * @return {@link Address} + */ + public static Address getAddress(Context context, double latitude, double longitude) { + Geocoder geocoder = new Geocoder(context, Locale.getDefault()); + try { + List
addresses = geocoder.getFromLocation(latitude, longitude, 1); + if (addresses.size() > 0) return addresses.get(0); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 根据经纬度获取所在国家 + * + * @param context 上下文 + * @param latitude 纬度 + * @param longitude 经度 + * @return 所在国家 + */ + public static String getCountryName(Context context, double latitude, double longitude) { + Address address = getAddress(context, latitude, longitude); + return address == null ? "unknown" : address.getCountryName(); + } + + /** + * 根据经纬度获取所在地 + * + * @param context 上下文 + * @param latitude 纬度 + * @param longitude 经度 + * @return 所在地 + */ + public static String getLocality(Context context, double latitude, double longitude) { + Address address = getAddress(context, latitude, longitude); + return address == null ? "unknown" : address.getLocality(); + } + + /** + * 根据经纬度获取所在街道 + * + * @param context 上下文 + * @param latitude 纬度 + * @param longitude 经度 + * @return 所在街道 + */ + public static String getStreet(Context context, double latitude, double longitude) { + Address address = getAddress(context, latitude, longitude); + return address == null ? "unknown" : address.getAddressLine(0); + } + + /** + * 根据经纬度获取详细地址 + * + * @param context 上下文 + * @param latitude 纬度 + * @param longitude 经度 + * @return 所在街道 + */ + public static String getFeature(Context context, double latitude, double longitude) { + Address address = getAddress(context, latitude, longitude); + return address == null ? "未知地点" : address.getFeatureName(); + } + + //------------------------------------------坐标转换工具start-------------------------------------- + + /** + * GPS坐标 转换成 角度 + * 例如 113.202222 转换成 113°12′8″ + * + * @param location + * @return + */ + public static String gpsToDegree(double location) { + double degree = Math.floor(location); + double minute_temp = (location - degree) * 60; + double minute = Math.floor(minute_temp); +// double second = Math.floor((minute_temp - minute)*60); + String second = new DecimalFormat("#.##").format((minute_temp - minute) * 60); + return (int) degree + "°" + (int) minute + "′" + second + "″"; + } + + /** + * 国际 GPS84 坐标系 + * 转换成 + * [国测局坐标系] 火星坐标系 (GCJ-02) + *

+ * World Geodetic System ==> Mars Geodetic System + * + * @param lon 经度 + * @param lat 纬度 + * @return GPS实体类 + */ + public static Gps GPS84ToGCJ02(double lat, double lon) { + if (outOfChina(lat, lon)) { + return null; + } + 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); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLat, mgLon); + } + + /** + * [国测局坐标系] 火星坐标系 (GCJ-02) + * 转换成 + * 国际 GPS84 坐标系 + * + * @param lon 火星经度 + * @param lat 火星纬度 + */ + public static Gps GCJ02ToGPS84(double lat, double lon) { + Gps gps = transform(lat, lon); + double lontitude = lon * 2 - gps.getWgLon(); + double latitude = lat * 2 - gps.getWgLat(); + return new Gps(latitude, lontitude); + } + + /** + * 火星坐标系 (GCJ-02) + * 转换成 + * 百度坐标系 (BD-09) + * + * @param gg_lon 经度 + * @param gg_lat 纬度 + */ + public static Gps GCJ02ToBD09(double gg_lat, double gg_lon) { + double x = gg_lon, y = gg_lat; + double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi); + double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi); + double bd_lon = z * Math.cos(theta) + 0.0065; + double bd_lat = z * Math.sin(theta) + 0.006; + return new Gps(bd_lat, bd_lon); + } + + /** + * 国际 GPS84 坐标系 + * 转换成 + * 百度坐标系 (BD-09) + * + * @param lon 经度 + * @param lat 纬度 + */ + public static Gps GPS84ToBD09(double lat, double lon) { + Gps gps = GPS84ToGCJ02(lat,lon); + if (gps == null) { + return new Gps(lat,lon); + } + //GCJ-02 转 BD-09 + return GCJ02ToBD09(gps.getWgLat(), gps.getWgLon()); + } + + /** + * 百度坐标系 (BD-09) + * 转换成 + * 火星坐标系 (GCJ-02) + * + * @param bd_lon 百度*经度 + * @param bd_lat 百度*纬度 + * @return GPS实体类 + */ + public static Gps BD09ToGCJ02(double bd_lat, double bd_lon) { + double x = bd_lon - 0.0065, y = bd_lat - 0.006; + double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi); + double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi); + double gg_lon = z * Math.cos(theta); + double gg_lat = z * Math.sin(theta); + return new Gps(gg_lat, gg_lon); + } + + /** + * 百度坐标系 (BD-09) + * 转换成 + * 国际 GPS84 坐标系 + * + * @param bd_lon 百度*经度 + * @param bd_lat 百度*纬度 + * @return GPS实体类 + */ + public static Gps BD09ToGPS84(double bd_lat, double bd_lon) { + Gps gcj02 = BD09ToGCJ02(bd_lat, bd_lon); + Gps map84 = GCJ02ToGPS84(gcj02.getWgLat(), + gcj02.getWgLon()); + return map84; + + } + + /** + * 不在中国范围内 + * + * @param lon 经度 + * @param lat 纬度 + * @return boolean值 + */ + public static boolean outOfChina(double lat, double lon) { + if (lon < 72.004 || lon > 137.8347) + return true; + return lat < 0.8293 || lat > 55.8271; + } + + /** + * 转化算法 + * + * @param lon + * @param lat + * @return + */ + public static Gps transform(double lat, double lon) { + if (outOfChina(lat, lon)) { + return new Gps(lat, lon); + } + 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); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLat, mgLon); + } + + /** + * 纬度转化算法 + * + * @param x + * @param y + * @return + */ + public 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; + } + + /** + * 经度转化算法 + * + * @param x + * @param y + * @return + */ + public 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; + } + + public interface OnLocationChangeListener { + + /** + * 获取最后一次保留的坐标 + * + * @param location 坐标 + */ + void getLastKnownLocation(Location location); + + /** + * 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 + * + * @param location 坐标 + */ + void onLocationChanged(Location location); + + /** + * provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数 + * + * @param provider 提供者 + * @param status 状态 + * @param extras provider可选包 + */ + void onStatusChanged(String provider, int status, Bundle extras);//位置状态发生改变 + + void onProviderEnabled(String provider); + + void onProviderDisabled(String provider); + } + + private static class MyLocationListener + implements LocationListener { + /** + * 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 + * + * @param location 坐标 + */ + @Override + public void onLocationChanged(Location location) { + if (mListener != null) { + mListener.onLocationChanged(location); + } + } + + /** + * provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数 + * + * @param provider 提供者 + * @param status 状态 + * @param extras provider可选包 + */ + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + if (mListener != null) { + mListener.onStatusChanged(provider, status, extras); + } + switch (status) { + case LocationProvider.AVAILABLE: + Log.d("onStatusChanged", "当前GPS状态为可见状态"); + break; + case LocationProvider.OUT_OF_SERVICE: + Log.d("onStatusChanged", "当前GPS状态为服务区外状态"); + break; + case LocationProvider.TEMPORARILY_UNAVAILABLE: + Log.d("onStatusChanged", "当前GPS状态为暂停服务状态"); + break; + } + } + + /** + * provider被enable时触发此函数,比如GPS被打开 + */ + @Override + public void onProviderEnabled(String provider) { + if (mListener != null) { + mListener.onProviderEnabled(provider); + } + } + + /** + * provider被disable时触发此函数,比如GPS被关闭 + */ + @Override + public void onProviderDisabled(String provider) { + if (mListener != null) { + mListener.onProviderDisabled(provider); + } + } + } + //===========================================坐标转换工具end==================================== + + + + private static final double EARTH_RADIUS = 6378137.0; //地球半径 + + + /** + * 计算两个经纬度之间的距离 + * + * @param longitude + * @param latitude + * @param longitude2 + * @param latitude2 + * @return 单位米 + */ + public static double getDistance(double longitude, double latitude, double longitude2, double latitude2) { + double lat1 = rad(latitude); + double lat2 = rad(latitude2); + double a = lat1 - lat2; + double b = rad(longitude) - rad(longitude2); + double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2))); + s = s * EARTH_RADIUS; + s = Math.round(s * 10000) / 10000; //四舍五入 + return s; + } + + /** + * 弧度换为角度 + * @param d + * @return + */ + private static double rad(double d) { + return d * Math.PI / 180.0; + } +} +