Determine the phone's location without GPS...

Turning hub "Development under Java ME" came across the topic of Spb Transport J2ME, where the author uses map services, and one of the TODO is to support GPS (for better usability). The problem is that phones with internal GPS receiver in a relatively small amount. I hope this post will help not only the author of the theme, but someone else, he once stuffed a lot of cones. So, let's start.

To determine the location of the user (as you like), you can use several methods:
— GPS. Method is the most accurate. Among the shortcomings: a relatively long start, consumes a lot of energy, not so many devices with built-in receiver.
— the towers of the operator. The average precision. Energy eats a little. Of the minuses: not all phones data is available.
— on the IP. Least accurate. Actually this is the biggest disadvantage.
— on CB messages of the operator

So, we need a more or less acceptable accuracy in determining the location (for the city is approximately 150-300 meters (this is where the 1.5-2 minutes on foot), city of, respectively, 2-5 km and more, as lucky), as we need to cover a larger number of devices, and it would be nice to quickly update the coordinates.
The most appropriate definition of location data through the mobile operator.

Services:
in Order to convert network data and get the coordinates, we will need a database of cell-tower operators. In the network there are a lot of resources, I used the time-tested Google maps, Yandex.Locator, location-api.com and opencellid.org (for greater accuracy and reliability using all at once). plus, as a bonus from Yandex API has a method of determining location given the signal strength, but about this later.
Each of the services has a well documented API (except GoogleMaps). The parameters taken by the API: MCC (country code), MNC (network code the network), LAC (code cell), CellID (identifier tower).
The API will return the coordinates for this dataset.

Details:
to the above-mentioned data is not a trivial task, because each of the manufacturers considered it a point of honour to invent a Bicycle. As a result, each brand has its own set of keys for the calling System.getProperty(key), to find that it is not so easy.
There are also a number of other unpleasant moments. For example Siemens'Ah data network without patching the firmware to fail. SonyEricsson returns the data in HEX representation. Nokia refuses to give LAC uncertified (ie almost all) of the MIDlet.

Solution:
I wrote a class that iterates through the known keys and receiving those keys and information about the network. Then the keys went in the service APIs, get the coordinates and output the average value, which I think is the most plausible (year use I do not remember cases of very large errors). If the phone allows you to receive the power signal, we use Yandex bonus: get the coordinates of the given signal strength, we obtain the Delta of these values, apply it to all results from the API and calculate the average result. Oddly enough, the last decision turned out to be a double-edged sword. With a uniform attenuation accuracy compared with the conventional method is increased two times, but if it's dense urban areas or hilly terrain where the signal is distributed unevenly in this case, the accuracy decreases quite strongly.

In the end, there is a possibility to determine the location on the phones of Siemens, SonyEricsson, Samsung (for example s5230), Huawei and others. Load time coordinates and addresses of about 10-15 seconds.
Example of the demo (used by add-in Location class, which is the definition of the coordinates and download them for addresses)
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
import loc.*;

public class HelloWorld extends MIDlet implements Runnable {

Display Display;
Form form;

public void startApp() {
display = Display.getDisplay(this);
form = new Form("NetMonitor");

display.setCurrent(form);
new Thread(this).start();
}

public void run() {
//check not Nokia whether
if (!Location.reallyNull(Location.lac)) {
//updating data network
Location.getData();
//get the coordinates
Location.getCoordinates();
//if you have access to the signal strength
if (!Location.reallyNull(SystemUtil.signal())) {
form.append(("Netmonitor: ") + "\PCOD country: "+ String.valueOf(Location.mcc) + "\PCOD network: "+ String.valueOf(Location.mnc) + "\PCOD cell: "+ String.valueOf(Location.lac) + "\PCOD BS: "+ String.valueOf(Location.cid) + "\psila signal: "+ SystemUtil.signal() + "\n");
} //otherwise
else {
form.append("Netmonitor:" + "\PCOD country: "+ String.valueOf(Location.mcc) + "\PCOD network: "+ String.valueOf(Location.mnc) + "\PCOD cell: "+ String.valueOf(Location.lac) + "\PCOD BS: "+ String.valueOf(Location.cid) + "\n");
}
}
//other data from the phone
String txt = SystemUtil.nativeDigitSupport();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
txt = SystemUtil.operatorName();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
txt = SystemUtil.serviceProvider();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
txt = SystemUtil.traffic();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
txt = SystemUtil.gid1();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
txt = SystemUtil.gid2();

if (!Location.reallyNull(txt)) {
form.append(txt + "\n");
}
//GEODATA
form.append("Street: ".concat(String.valueOf(Location.getStreet().concat(" \n"))));
form.append("City: ".concat(String.valueOf(Location.getCity().trim().concat(" \n"))));
form.append("Region: ".concat(String.valueOf(Location.getArea().concat(" \n"))));
form.append("Country: ".concat(String.valueOf(Location.getCountry().concat(" \n"))));
form.append("Longitude: ".concat(String.valueOf(Location.getLongitude().concat(" \n"))));
form.append("Latitude: ".concat(String.valueOf(Location.getLatitude().concat(" \n"))));
form.append("Altitude.m.: ".concat(String.valueOf(Location.getElevation().concat(" m \n"))));
//for sportsmenov bonus
String sens = System.getProperty("microedition.sensor.version");
if (sens != null && sens.length() != 0 && !sens.equals("null")) {
sens = SensorApi.getSensor(3);

if (sens != null && sens.length() != 0 && !sens.equals("null") && !sens.equals("0")) {
form.append("Today Hiking steps:" + String.valueOf(sens) + "\n");
}
}


}

public void pauseApp() {
}

public void destroyApp(boolean flag) {
}
}



Well, the source code from demo
goo.gl/lPkON
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

ODBC Firebird, Postgresql, executing queries in Powershell

garage48 for the first time in Kiev!

The Ministry of communications wants to ban phones without GLONASS