package com.igo.user.utils.google import android.Manifest import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Color import android.location.LocationManager import android.os.Handler import android.os.Looper import android.text.TextUtils import android.util.Log import android.view.View import android.widget.Toast import androidx.core.content.ContextCompat import cn.sinata.xldutils.utils.LanguageUtil import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.util.CollectionUtils.listOf import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMapOptions import com.google.android.gms.maps.SupportMapFragment import com.google.android.gms.maps.model.BitmapDescriptor import com.google.android.gms.maps.model.BitmapDescriptorFactory import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.Circle import com.google.android.gms.maps.model.CircleOptions import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLngBounds import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.maps.model.Polygon import com.google.android.gms.maps.model.PolygonOptions import com.google.android.gms.maps.model.Polyline import com.google.android.gms.maps.model.PolylineOptions import com.google.android.libraries.mapsplatform.transportation.consumer.view.ConsumerGoogleMap import com.google.android.libraries.places.api.Places import com.google.android.libraries.places.api.model.AutocompletePrediction import com.google.android.libraries.places.api.model.AutocompleteSessionToken import com.google.android.libraries.places.api.model.Place import com.google.android.libraries.places.api.model.PlaceLikelihood import com.google.android.libraries.places.api.model.TypeFilter import com.google.android.libraries.places.api.net.FetchPlaceRequest import com.google.android.libraries.places.api.net.FindAutocompletePredictionsRequest import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest import com.google.gson.Gson import com.google.maps.android.PolyUtil import com.igo.user.IGoApplication import com.igo.user.R import com.igo.user.utils.Const import okhttp3.MediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response import java.util.Arrays import java.util.Collections.emptyList object AMapKit { val TAG = "GoogleMap" @SuppressLint("MissingPermission") fun initLocation(context: Context, success: (Place) -> Unit, error: (String) -> Unit) { val placesClient = Places.createClient(context) val placeFields: List = listOf(Place.Field.LAT_LNG,Place.Field.NAME,Place.Field.ADDRESS) // Use the builder to create a FindCurrentPlaceRequest. val request: FindCurrentPlaceRequest = FindCurrentPlaceRequest.newInstance(placeFields) // Call findCurrentPlace and handle the response (first check that the user has granted permission). if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { val placeResponse = placesClient.findCurrentPlace(request) placeResponse.addOnCompleteListener { task -> if (task.isSuccessful) { val response = task.result for (placeLikelihood: PlaceLikelihood in response?.placeLikelihoods ?: emptyList()) { Log.i(TAG, "Place '${placeLikelihood.place.name}' has likelihood: ${placeLikelihood.likelihood}") } if (response?.placeLikelihoods?.isEmpty() != true){ success(response.placeLikelihoods[0].place) } } else { val exception = task.exception if (exception is ApiException) { Log.e(TAG, "Place not found: ${exception.message}") } error(exception?.message?:"定位失败") } } } else { // A local method to request required permissions; // See https://developer.android.com/training/permissions/requesting Toast.makeText(context, context.getString(R.string.没有权限), Toast.LENGTH_SHORT).show() // getLocationPermission() error("没有权限") } } fun initMap(mapView: SupportMapFragment,function: (GoogleMap) -> Unit) { mapView.getMapAsync { p0 -> val mMyLocationStyle = GoogleMapOptions() // mMyLocationStyle.interval(5000) // mMyLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) // mMyLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.gps_point)) // p0.setLocationSource() = mMyLocationStyle // p0.isMyLocationEnabled = false // p0.animateCamera(CameraUpdateFactory.zoomTo(aMap.maxZoomLevel - 3)) // 设置定位的类型为定位模式,有定位、跟随或地图根据面向方向旋转几种 // p0.setMyLocationType(GoogleMap.LOCATION_TYPE_LOCATE) // val uiSettings: UiSettings = aMap.uiSettings // uiSettings.isZoomControlsEnabled = false function(p0) } } fun drawLine(context: Context, aMap: GoogleMap, start: LatLng, end: LatLng): Polyline? { val latLngs: MutableList = ArrayList() latLngs.add(start) latLngs.add(end) return aMap.addPolyline( PolylineOptions().addAll(latLngs).width(10f).color( ContextCompat.getColor(context, R.color.quantum_yellow900) ) ) } /*** * 监听地图的移动 */ fun addMapMoveListener(aMap: GoogleMap, marker: Marker, finishPosition: (LatLng) -> Unit) { aMap.setOnCameraMoveListener { marker.position = aMap.cameraPosition.target } aMap.setOnCameraIdleListener { finishPosition(aMap.cameraPosition.target) } } fun drawLineAndMove(context: Context, aMap: GoogleMap, start: LatLng, end: LatLng, padd: Int) { drawLine(context, aMap, start, end) moveCamera(aMap, start, end, padd) } fun drawLine(context: Context, aMap: GoogleMap, latLngs: List?): Polyline? { val options = PolylineOptions().addAll(latLngs!!).width(20f) .color(ContextCompat.getColor(context, R.color.quantum_googgreen500)) return aMap.addPolyline(options) } fun drawLine(context: Context, aMap: ConsumerGoogleMap, latLngs: List?): Polyline? { val options = PolylineOptions().addAll(latLngs!!).width(20f) .color(ContextCompat.getColor(context, R.color.quantum_googgreen500)) return aMap.addPolyline(options) } fun drawLine(context: Context, aMap: GoogleMap, latLngs: List?,color:Int): Polyline? { val options = PolylineOptions().addAll(latLngs!!).width(20f) .color(ContextCompat.getColor(context, color)) return aMap.addPolyline(options) } fun moveCamera(aMap: GoogleMap, latlng: LatLng?) { val mCameraUpdate = CameraUpdateFactory.newCameraPosition( CameraPosition(latlng!!, 16f, 0f, 0f) ) aMap.animateCamera(mCameraUpdate) } fun moveCamera(aMap: GoogleMap, latlng: LatLng?,zoom:Float) { val mCameraUpdate = CameraUpdateFactory.newCameraPosition( CameraPosition(latlng!!, zoom, 0f, 0f) ) aMap.animateCamera(mCameraUpdate) } fun moveCamera(aMap: GoogleMap, start: LatLng?, end: LatLng?) { var bounds: LatLngBounds? = null if (start!!.latitude < end!!.latitude) bounds = LatLngBounds(start, end) else bounds = LatLngBounds(end, start) val mCameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 150) aMap.animateCamera(mCameraUpdate, object : GoogleMap.CancelableCallback { override fun onFinish() { } override fun onCancel() { } }) } fun moveCamera(aMap: GoogleMap, start: LatLng?, end: LatLng?, padd: Int) { val bounds = LatLngBounds(start!!, end!!) val mCameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, padd) aMap.animateCamera(mCameraUpdate) } fun getOption( latLng: LatLng, view: View ): MarkerOptions { return MarkerOptions().anchor(0.5f, 1f) .position(latLng) .icon(BitmapDescriptorFactory.fromBitmap(convertViewToBitmap(view)!!)) .draggable(true).flat(true) } /*** * 修改marker的view */ fun getIcon(view: View): BitmapDescriptor { return BitmapDescriptorFactory.fromBitmap(convertViewToBitmap(view)!!) } /** * 吧iew转化为bitmap * * @param view * @return */ fun convertViewToBitmap(view: View): Bitmap? { view.isDrawingCacheEnabled = true view.measure( View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED ), View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED ) ) view.layout(0, 0, view.measuredWidth, view.measuredHeight) view.buildDrawingCache() val mCacheBitmap = view.drawingCache return Bitmap.createBitmap(mCacheBitmap) } /** * 添加marker点 */ fun addMarker( aMap: GoogleMap, mLat: Double, mLng: Double, view: View, peopleId: String ): Marker? { val options: MarkerOptions = getOption(LatLng(mLat, mLng), view) val marker: Marker = aMap.addMarker(options)!! if (!TextUtils.isEmpty(peopleId)) { marker.tag = peopleId } return marker } fun getTance(tance: Float): String { if (tance == 0f) { return IGoApplication.appContext!!.getString(R.string.zero_tance) } return if (tance > 1000) { String.format("%.1f"+IGoApplication.appContext!!.getString(R.string.公里), (tance / 1000f)) } else { String.format("%.1f"+IGoApplication.appContext!!.getString(R.string.米), tance) } } // fun drawFenceByCity(context: Context, city: String, va1: GeoFenceListener) { // val mGeoFenceClient = GeoFenceClient(context) // mGeoFenceClient.setActivateAction(GeoFenceClient.GEOFENCE_IN) // mGeoFenceClient.addGeoFence(city, ""); // mGeoFenceClient.setGeoFenceListener(va1); // // } fun drawFace(context: Context, aMap: GoogleMap, latLngs: List?): Polygon? { var po = PolygonOptions().addAll(latLngs!!) .fillColor(ContextCompat.getColor(context, R.color.l_transparent_10)).strokeColor( Color.RED ).strokeWidth(1f) return aMap.addPolygon(po) } fun drawCricle(context: Context, aMap: GoogleMap, latLng: LatLng,bg:Double): Circle? { return aMap.addCircle(CircleOptions(). center(latLng). radius(bg). fillColor(ContextCompat.getColor(context, R.color.l_transparent_10)). strokeColor( Color.RED). strokeWidth(1f)); } fun getTimeType(num: Int): String { if (num in 0..60) { return num.toString() + "s" } if (num in 60..60 * 60) { return (num / 60).toString() + ":" + (num % 60).toString() + "s" } if (num in 60..60 * 60 * 24) { return (num / 3600).toString() + ":" + ((num % 3600) / 60).toString() + ":" + (((num % 3600) % 60) % 60).toString() + "s" } return "" } fun initRouteLine( context: Context, start: LatLng, end: LatLng, onClick: (latLngs: MutableList, lineTance: Float, lineTime: Long) -> Unit ) { initRouteLine(context, start, end, null, onClick) } fun initRouteLine( start: LatLng, end: LatLng, onClick: (latLngs: MutableList, lineTance: Float, lineTime: Long) -> Unit ) { initRouteLine(start, end, null, onClick) } fun initRouteLine( start: LatLng, end: LatLng, centerPoint: List?, onClick: (latLngs: MutableList, lineTance: Float, lineTime: Long) -> Unit ) { //https://maps.googleapis.com/maps/api/directions/json?origin=39.99709957757345,116.31184045225382&destination=39.949158391497214,116.4154639095068&sensor=false&mode=driving var language = LanguageUtil.getLanguage() var centerStr = getPointStr(centerPoint ?: arrayListOf()) var url = "https://maps.googleapis.com/maps/api/directions/json" + "?origin=" + start.latitude.toString() + "," + start.longitude.toString() + "&destination=" + end.latitude.toString() + "," + end.longitude.toString() + "&waypoints=" + centerStr + "®ion=" + language + "&key=" + Const.google_key getClient(url) { var googleBean = Gson().fromJson(it, GoogleRouteBean::class.java) var time = 0 //秒 var tance = 0 //米 var allPoint = arrayListOf() val decode = PolyUtil.decode(googleBean.routes?.firstOrNull()?.overview_polyline?.points ?: "") for (routes in googleBean.routes ?: arrayListOf()) { if (routes.legs.isNullOrEmpty()) { Log.i(TAG, "initRouteLine: 无路线") return@getClient } time = routes.legs[0].duration?.value ?: 0 tance = routes.legs[0].distance?.value ?: 0 } allPoint.addAll(decode) onClick(allPoint, tance.toFloat(), time.toLong() / 60) } } fun initRouteLine( context: Context, start: LatLng, end: LatLng, centerPoint: List?, onClick: (latLngs: MutableList, lineTance: Float, lineTime: Long) -> Unit ) { //https://maps.googleapis.com/maps/api/directions/json?origin=39.99709957757345,116.31184045225382&destination=39.949158391497214,116.4154639095068&sensor=false&mode=driving var language = LanguageUtil.getLanguage() val client: OkHttpClient = OkHttpClient().newBuilder() .build() val mediaType: MediaType = MediaType.parse("text/plain")!! val body: RequestBody = RequestBody.create(mediaType, "") var centerStr = getPointStr(centerPoint?: arrayListOf()) val request: Request = Request.Builder() .url("https://maps.googleapis.com/maps/api/directions/json" + "?origin=" + start.latitude.toString()+","+start.longitude.toString() + "&destination="+end.latitude.toString()+","+end.longitude.toString() + "&waypoints="+ centerStr + "®ion="+language+ "&key="+ Const.google_key ) .method("GET", body) .build() val response: Response = client.newCall(request).execute() var resurse = response.body()!!.string() var googleBean = Gson().fromJson(resurse, GoogleRouteBean::class.java) var time = 0 //秒 var tance = 0 //米 var allPoint = arrayListOf() for (routes in googleBean.routes?: arrayListOf()){ if (routes.legs.isNullOrEmpty()){ Log.i(TAG, "initRouteLine: 无路线") return } time = routes.legs[0].duration?.value?:0 tance= routes.legs[0].distance?.value?:0 if (routes.legs.isNullOrEmpty()){ Log.i(TAG, "initRouteLine: 无途径点") return } for (item in routes.legs[0].steps?: arrayListOf()){ allPoint.add(LatLng(item.end_location?.lat?:0.0, item.end_location?.lng?:0.0)) } } onClick(allPoint, tance.toFloat(), time.toLong()/60) } private fun getPointStr(centerPoint: List): String { var s = "" for (item in centerPoint){ if (s.isEmpty()){ s+=item.latitude.toString()+","+item.longitude.toString() }else{ s+="|"+item.latitude.toString()+","+item.longitude.toString() } } return s } /*** * 是否开启gps */ public fun isLocServiceEnable(context: Context): Boolean { val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager var gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) var network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) if (gps || network) { return true } return false } fun getClient(url:String,function: (String) -> Unit){ val client = OkHttpClient().newBuilder().build() val mediaType = MediaType.parse("text/plain") val body = RequestBody.create(mediaType, "") val request: Request = Request.Builder() .url(url) .method("GET",null) .build() Thread{ try { val response = client.newCall(request).execute() Handler(Looper.getMainLooper()).post { function(response.body()?.string()?:"") } }catch (e:Exception){ e.printStackTrace() } }.start() } /*** * 周边检索 * @param lat * @param lng */ fun searchPoint( context: Context, lat: Double, lng: Double, function: ( List) -> Unit ) { var language = LanguageUtil.getLanguage() var url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" + "?location="+ lat.toString()+","+lng.toString() + "&radius=1500" + // "&type=restaurant" + "&language="+language + "&key="+Const.google_key getClient(url){ var near = Gson().fromJson(it,GoogleNearBean2::class.java) if (near.results!!.isNotEmpty() && near.results!!.size > 1){ function(near.results?: arrayListOf()) } } } /*** * 输入内容自动提示 * @param str * @param var1 */ fun searchSite(context: Context, content: String?, cityName: String, function: (List) -> Unit) { val placesClient = Places.createClient(context) var language = LanguageUtil.getLanguage() val token = AutocompleteSessionToken.newInstance() // val bounds = RectangularBounds.newInstance( // LatLng(-33.880490, 151.184363), LatLng(-33.858754, 151.229596)) val request = FindAutocompletePredictionsRequest.builder() // Call either setLocationBias() OR setLocationRestriction(). // .setLocationBias(bounds) .setOrigin(LatLng(IGoApplication.lat, IGoApplication.lon)) .setCountries(language) .setTypeFilter(TypeFilter.ADDRESS) .setSessionToken(token) .setQuery(content) .build() placesClient.findAutocompletePredictions(request).addOnSuccessListener { response -> function(response.autocompletePredictions) }.addOnFailureListener { exception -> if (exception is ApiException) { Log.e(TAG, "Place not found: " + exception.statusCode) } } } fun getPlanceIdDetail(context: Context,id:String,function: (Place) -> Unit){ val placesClient = Places.createClient(context) val placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME) val request = FetchPlaceRequest.newInstance(id, placeFields) placesClient.fetchPlace(request).addOnSuccessListener { response -> val place: Place = response.getPlace() function(place) }.addOnFailureListener { exception -> if (exception is ApiException) { Log.e(TAG, "Place not found: " + exception.message) val statusCode = exception.statusCode } } } /*** * 逆地址编码 */ fun getAddress(context: Context,lat:Double,lon:Double,function:(String)->Unit) { var language = LanguageUtil.getLanguage() var url = "https://maps.googleapis.com/maps/api/geocode/json" + "?latlng="+ lat.toString() +","+lon.toString() + "&language="+language+ "&result_type=postal_code"+ "&key="+Const.google_key getClient(url){ var bean = Gson().fromJson(it,GoogleBackBean::class.java) if (!bean.results.isNullOrEmpty() && bean.results!![0].types.isNotEmpty()) function(bean.results!![0].address_components!![0].short_name!!) } } fun getAddressName(context: Context,lat:Double,lon:Double,function:(String)->Unit) { var language = LanguageUtil.getLanguage() var url = "https://maps.googleapis.com/maps/api/geocode/json" + "?latlng="+ lat.toString() +","+lon.toString() + "&language="+language+ "&result_type=street_address"+ "&key="+Const.google_key getClient(url){ var bean = Gson().fromJson(it,GoogleBackBean::class.java) if (!bean.results.isNullOrEmpty() && bean.results!![0].types.isNotEmpty()) function(bean.results!![0].address_components!![3].short_name!!) } } // fun startNavi(startLat:Double,startLon:Double,endLat:Double,endLon:Double){ // if (ApkUtils.isAvilible(DeviceConfigInternal.context, "com.google.android.apps.maps")) { // val gmmIntentUri: Uri = Uri.parse("google.navigation:q=$endLat,$endLon, + Sydney +Australia") // val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) // mapIntent.setPackage("com.google.android.apps.maps") // DeviceConfigInternal.context.startActivity(mapIntent) // } else { // ToastUtils.showShortToast(IGoApplication.appContext, "您尚未安装谷歌地图") // val uri: Uri = Uri.parse("market://details?id=com.google.android.apps.maps") // var intent = Intent(Intent.ACTION_VIEW, uri) // DeviceConfigInternal.context.startActivity(intent) // } // } /*** * LatLngBounds 此方法有可能错误了 start 和 end 的经纬度可能要拆分开来组合成 左上和右下的位置 */ fun moveCamera(aMap: ConsumerGoogleMap, start: LatLng?, end: LatLng?) { var bounds: LatLngBounds? = null // if (start!!.latitude < end!!.latitude) // bounds = LatLngBounds(start!!, end!!) // else // bounds = LatLngBounds(end, start) var startX = LatLng( if (start!!.latitude < end!!.latitude) start.latitude else end.latitude, if (start!!.longitude < end!!.longitude) start.longitude else end.longitude ) var startY = LatLng( if (start!!.latitude > end!!.latitude) start.latitude else end.latitude, if (start!!.longitude > end!!.longitude) start.longitude else end.longitude ) bounds = LatLngBounds(startX, startY) val mCameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 200) aMap.animateCamera(mCameraUpdate) } }