Android Advanced Road Series:https://blog.csdn.net/chzphoenix/column/info/16488
Preface:
In android, we usually use Location Manager to get location information, where there are four provider s:
public static final String NETWORK_PROVIDER = "network"; public static final String GPS_PROVIDER = "gps"; public static final String PASSIVE_PROVIDER = "passive"; public static final String FUSED_PROVIDER = "fused"; fused has been discarded, and the other three differences are as follows:
(1) GPS_PROVIDER: Get latitude and longitude information of geographic location by GPS; Advantages: Get geographic location information with high accuracy; Disadvantages: Can only be used outdoors, it takes time and energy to obtain latitude and longitude information;
(2) NETWORK_PROVIDER: Get geographic location by base station or Wi-Fi of mobile network; Advantages: As long as there is network, it can be located quickly, indoors and outdoors; Disadvantages: low accuracy;
(3) PASSIVE_PROVIDER: Passively receive updated geographic location information without requesting it yourself.
PASSIVE_PROVIDER returns locations generated by other providers. The getProvider() method can be queried to determine the origin of location updates. ACCESS_FINE_LOCATION privileges are required, but if GPS is not enabled, this provider may only return rough location matches.
We usually use both gps and network.
But we can also get location information in other ways. This article will give you a detailed explanation of several ways to get location in android.
1. GPS positioning
The most common use of this is to get the last location or to listen for changes, coded as follows:
Require permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
//GPS Positioning
var locManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager var loc = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) if(loc != null){ Log.e("gpslocation", loc.toString()) toast(loc.toString()) } locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0F, object : LocationListener{ override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) { } override fun onProviderEnabled(provider: String?) { } override fun onProviderDisabled(provider: String?) { } override fun onLocationChanged(location: Location?) { Log.e("gpslocation", location.toString()) toast(location.toString()) } })
2. NETWORK Location
Almost always with the gps location code, but changed provider to LocationManager.NETWORK_PROVIDER
3. AGPS positioning
In fact, it combines the above two locations, and the specific principle is as follows:
The AGPS mobile phone first transmits its base station address through the network to the location server.
The location server transmits GPS auxiliary information (including GPS calendar, azimuth pitch, etc.) related to the location of the mobile phone based on its approximate location to the mobile phone.
The mobile phone's AGPS module receives the original GPS signal based on auxiliary information (to enhance the TTFF capability of the first lock-in time of the GPS signal);
After receiving the original GPS signal, the mobile phone demodulates the signal, calculates the pseudo-range from the mobile phone to the satellite (the pseudo-range is the distance affected by various GPS errors), and transmits the information to the location server through the network.
The location server processes the GPS information based on the incoming GPS pseudorange information and auxiliary information from other positioning devices, such as differential GPS reference stations, and estimates the location of the mobile phone.
Location servers transfer the location of the phone over the network to a location gateway or application platform.
My understanding is that by identifying the best satellites through network locations and location servers, the acquisition time of satellite signals is reduced.Because network locations are acquired quickly, the overall locating time can be reduced.
AGPS is not a positioning method, but an optimization scheme. The code is the same as GPS, but the positioning mode is set to AGPS in the settings.
Above is the android's own location method. We can also get some original information (such as base station information, wifi information) and get the location information through the open interface.The following are several ways to get location information using the API using the original information.
4. Base Station Location
Through TelephonyManager we can get base station information, and then through the related api interface we can get latitude and longitude, but the base station positioning accuracy is poor.
Base station information includes the following:
MCC, Mobile Country Code, Mobile Country Code (460 in China);
MNC, Mobile Network Code, Mobile Network Number (China Mobile is 00, China Unicom is 01);
LAC, Location Area Code, Location Area Code;
CID, Cell Identity, Base Station Number, is a 16-bit data (range 0 to 65535).
Once we get this information, we can get latitude and longitude through some public api services as follows:
http://www.google.com/loc/json Gogle's, post request, seems to have been disabled
http://www.cellocation.com/interfac/ Currently available, free of charge
Example:
http://api.cellocation.com:81/cell/?mcc=460&mnc=1&lac=4301&ci=20986&output=json
Return:
{errcode: 0,'lat':'40.00598145','lon':'116.48539734','radius':'937','address':'Donghu Canal in Laiguangying District, Chaoyang District, Beijing; 70m East at the intersection of Xiyang East Road and Pingcui East Road'} Interface parameters:
Name | type | Required | Explain |
mcc | int | yes | mcc country code: China code 460 |
mnc | int | yes | mnc network type: 0 mobile, 1 connected (telecommunication corresponding sid), decimal |
lac | int | yes | Lac (telecommunication for nid), decimal |
ci | int | yes | Cellid (telecommunication corresponding bid), decimal |
coord | string | no | Coordinate type (wgs84/gcj02/bd09), default WGS84 |
output | string | no | Return format (csv/json/xml), default CSV |
There are also many platforms that provide this kind of interface and data, just search by yourself
The code is as follows:
Require permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
//Base station positioning, where only GSM is implemented, with slightly different CDMA
val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager if(telManager.cellLocation is GsmCellLocation) { val cellLoc = telManager.cellLocation as GsmCellLocation if (cellLoc != null) { val operator = telManager.networkOperator val mcc = operator.substring(0, 3).toInt() val mnc = operator.substring(3).toInt() val cid = cellLoc.cid val lac = cellLoc.lac var sb = StringBuilder("http://api.cellocation.com:81/cell/?") sb.append("mcc=") sb.append(mcc) sb.append("&mnc=") sb.append(mnc) sb.append("&lac=") sb.append(lac) sb.append("&ci=") sb.append(cid) sb.append("&output=json") Log.e("tellocation", sb.toString()) doAsync { val result = URL(sb.toString()).readText() Log.e("tellocation", result) } } }
5. WIFI Location
Wifi location gets WiFi information through WifiManager, mainly the BSSID (mac address) of the wifi.Then query latitude and longitude through some api, such as http://www.cellocation.com/interfac/
Example:
http://api.cellocation.com:81/wifi/?mac=00:87:36:05:5d:ea&output=json
Return:
{"errcode":0, "lat":"39.950008", "lon":"116.230049", "radius":"222", "address":"Yiyuan Wenchuan Base of Si Ji Qing Town, Haidian District, Beijing c District 9 Building;561 m northwest of the intersection of Nanpingzhuang Middle Road and Xipingzhuang Road"}
Interface parameters:
Name | type | Required | Explain |
mac | string | yes | MAC address of WIFI hotspot (BSSID) |
coord | string | no | Coordinate type (wgs84/gcj02/bd09), default WGS84 |
output | string | no | Return format (csv/json/xml), default CSV |
The code is as follows: Require permissions<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> //wifi Positioning val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager if(wifiManager.isWifiEnabled) { var mac = wifiManager.connectionInfo.bssid if(TextUtils.isEmpty(mac)) { /** * When the wifi is not linked, you can use the scanned list of wifi to find one with the best signal strength.No comparison here, just use the first one * ScanReuslt Three fields are important: SSID is the wifi name, BSSID is the wifi mac, and level is the signal strength (negative number) * Note that there may be more than one SSID in the result, and if link wifi is needed, the best link can be filtered out by signal strength */ val scanlist = wifiManager.scanResults for(info in scanlist){ Log.e("wifiinfo", info.toString()) } if(scanlist.size > 0) { mac = wifiManager.scanResults[0].BSSID } } if(!TextUtils.isEmpty(mac)) { var sb = StringBuilder("http://api.cellocation.com:81/wifi/?") sb.append("mac=") sb.append(mac) sb.append("&output=json") Log.e("wifilocation", sb.toString()) doAsync { val result = URL(sb.toString()).readText() Log.e("wifilocation", result) } } }
|
6. Mixed positioning
Hybrid positioning is the acquisition of nearby wifi list information (including signal strength) and nearby base station list information (including signal strength), and latitude and longitude through some api.
This method is more accurate than a single base station and wifi location.
Getting a list of nearby WiFi is already mentioned in the WIFI location. Getting a scanned list of WiFi through WifiManager's getScanResults function, where level is the signal strength, may require some weight.
Getting a list of nearby base stations is problematic.
Officially, a method is provided through TelephonyManager's getNeighboringCellInfo function, where mRssi is the signal strength.
Require permissions
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> //Get information about nearby base stations
val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val neighborCells = telManager.neighboringCellInfo for(cell in neighborCells){ //Convert rssi to dBm here val level = -131 + 2 * cell.rssi Log.e("neighboringCellInfo", "cid:${cell.cid} lac:${cell.lac} rssi:$level") }
However, both cid and lac are found to be -1 in practice.
Check the construction of NeighboringCellInfo as follows:
public NeighboringCellInfo(int rssi, String location, int radioType) { // set default value mRssi = rssi; mNetworkType = NETWORK_TYPE_UNKNOWN; mPsc = UNKNOWN_CID; mLac = UNKNOWN_CID; mCid = UNKNOWN_CID; // pad location string with leading "0" int l = location.length(); if (l > 8) return; if (l < 8) { for (int i = 0; i < (8-l); i++) { location = "0" + location; } } // TODO - handle LTE and eHRPD (or find they can't be supported) try {// set LAC/CID or PSC based on radioType switch (radioType) { case NETWORK_TYPE_GPRS: case NETWORK_TYPE_EDGE: mNetworkType = radioType; // check if 0xFFFFFFFF for UNKNOWN_CID if (!location.equalsIgnoreCase("FFFFFFFF")) { mCid = Integer.parseInt(location.substring(4), 16); mLac = Integer.parseInt(location.substring(0, 4), 16); } break; case NETWORK_TYPE_UMTS: case NETWORK_TYPE_HSDPA: case NETWORK_TYPE_HSUPA: case NETWORK_TYPE_HSPA: mNetworkType = radioType; mPsc = Integer.parseInt(location, 16); break; } } catch (NumberFormatException e) { // parsing location error mPsc = UNKNOWN_CID; mLac = UNKNOWN_CID; mCid = UNKNOWN_CID; mNetworkType = NETWORK_TYPE_UNKNOWN; } }
You can see that only GPRS and EDGE networks are processed, whereas 3G and 4G networks are UNKNOWN_CID, or -1.This method is not supported and is obsolete.
There is another way officially available, through the TelephonyManager getAllCellInfo function.This function requires minsdkverison to be at least 17
Require permissions
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> //Get base station information, which only handles LTE network
val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val cells = telManager.allCellInfo for(cell in cells){ if(cell is CellInfoLte) { Log.e("celllist", "cid:${cell.cellIdentity.ci} lac:${cell.cellIdentity.tac} dbm:${cell.cellSignalStrength.dbm} isRegistered:${cell.isRegistered}") } }
The following information is available:
E/celllist: cid:3912981 lac:4154 dbm:-87 isRegistered:true
E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false
E/celllist: cid:2147483647 lac:2147483647 dbm:-102 isRegistered:false
E/celllist: cid:2147483647 lac:2147483647 dbm:-108 isRegistered:false
E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false
The first one is the base station we are using, where you can see the normal returned information and the rest returns the default information (Integer.MAX_VALUE)
Explain that this method can only get the base station information currently in use.And according to the Internet, when using a 2G network, getAllCellInfo gets NULL.
There is no better way to get information from multiple base stations.
When we get the base station information and wifi information nearby, we can use http://www.cellocation.com/interfac/ The Hybrid Location Interface provided to query location information is similar to the one above, which is not detailed here.
Android Advanced Road Series:https://blog.csdn.net/chzphoenix/column/info/16488