Microsoft Kills Nokia’s Symbian
Dear Nokia Developer,
With the growing business opportunities available on the Asha and Windows Phone platforms, we have been reviewing our developer content programs to see how we can maximize our support to you, our developers. As a result of this review, we have decided to focus our support and investment in new content toward Asha and Windows Phone. Over the next few months we will be transitioning our active developer support away from Symbian and MeeGo.
If you have Symbian and MeeGo content in the Nokia Store, it will continue to be available for download to customers, and you will continue to receive download and revenue reports as well as payouts for downloaded content. However, starting January 1, 2014, you will no longer be able to publish any new content or update existing content for Symbian and MeeGo.
We are very excited about the opportunities available with Asha and Windows Phone, and hope that you will bring your talents to these platforms. We believe that these changes will help improve our ability to support you as you develop fantastic apps for your customers.
Best regards,
The Nokia Developer Team
Moving IIS sites using AppCmd
Backup Process
%windir%\System32\inetsrv>appcmd list apppool /config /xml >C:\temp\apppools.xml
%windir%\System32\inetsrv>appcmd list sites /config /xml >C:\temp\sites.xml
… And all your website files
Zip up all these files, and move them to the destination server.
Restore Process
… Restore all your website files from the zip file.
Then Edit the apppools.xml file, and comment out any appPools that are already present in the destination server, for example
“DefaultAppPool” etc.
Then … Import App Pools using:
%windir%\system32\inetsrv\appcmd add apppool /in < c:\apppools.xml
Step 2.
Edit the Sites.xml file, and comment out any websites that are already present in the destination server, for example “Default website” etc
Edit the sites.xml file, and change the Site.ID=”<number>” and ID=”<number>” attributes so that they are larger than the largest Site ID in IIS.
Important: If you import a site with the same site ID as an existing site, then the entire server will crash
%windir%\system32\inetsrv\appcmd add site /in < c:\sites.xml
no xaml was found at the location ‘/mainpage.xaml’
After upgrading a WP7 app to WP8 (VS 2013 RC), I got this very annoying error when trying to run the app in the emulator. “no xaml was found at the location ‘/mainpage.xaml'”.
I came across a conversation on twitter, regarding this, and saw that someone had the same problem, but said “Found it!!! Your application MUST have Invariant Language ticked as a supported language. Blog post to come :-)”
So, that narrowed my search, and I discovered a one line fix; In the AssemblyInfo.cs file, you have to change the line:
[assembly: NeutralResourcesLanguage(“en”, UltimateResourceFallbackLocation.Satellite)]
To
[assembly: NeutralResourcesLanguage(“en”)]
One line fix!. Pity the error message is not helpful at all.
Saving files locally using PhoneGap
One of the quintessential differences between an application and a web page is that applications are trusted to read and write to the hard drive on the machine it is running on. With the exception of limited space given under certain circumstances for Isolated storage (Silverlight), Cookies and Localstorage (5Mb ~ or effectively 2.5 Mb of text), web pages aren’t trusted enough to read and write to your hard drive, and rightly so.
With Apps, there is an elevated level of trust, so you can read and write files within your application “Sandbox”, i.e. space devoted to your app, and no-one else’s. With smartphones coming now with up to 64 GB of storage, this gives plenty of opportunity to download images, video and content for offline use.
I just learned this morning how to use PhoneGap’s File API, – This example applies specifically to version 2.9.0 on iOS, but it should be equally applicable to other versions, and Android.
First off, you need to get a handle to the local file system, which you can do on the device ready event like so:
var fileSystem = null;
document.addEventListener(“deviceready”, onDeviceReady, false);
function onDeviceReady()
{
console.log(“Device Ready”);
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function gotFS(fs)
{
console.log(“Got File System Reference”);
fileSystem = fs;
}, fail);
}
Here the variable fileSystem is declared with global scope, and I have selected Temporary storage. Temporary storage is not designed for “mission critical” or user generated content, just things that can be downloaded again, if need be. Ideal for short-term caching.
Then, I have written a handy function to store this data onto disk:
function createFileWithContent(filename, content)
{
fileSystem.root.getFile(
filename,
{create: true, exclusive: false},
function gotFileEntry(fileEntry) {
console.log(“Got File Entry Reference”);
console.log(fileEntry.toURL());
fileEntry.createWriter(
function gotFileWriter(writer) {
writer.onwriteend = function(evt) {
console.log(writer.fileName);};
writer.write(content);
}, fail);
}, fail);
}
This function writes text content to a file. You don’t worry about the path, since this is dictated by the operating system.
To read this back in, you can use simple ajax, as you would read a local file off disk.
The fail function is omitted here, but it can be a simple console.log, or something more advanced, depending on how you wish the app to respond to errors in the process of saving data.
The Search API for Shopping has been shut down
As of this morning, Google shut down its Shopping API (As was forewarned). Now, if you try to call it, https://www.googleapis.com/shopping/search/v1/public/products?key=…&country=US&q=pogo&alt=json you get the following Error 412 response:
{
“error”: {
“errors”: [
{
“domain”: “global”,
“reason”: “conditionNotMet”,
“message”: “The Search API for Shopping has been shut down”,
“locationType”: “header”,
“location”: “If-Match”
}
],
“code”: 412,
“message”: “The Search API for Shopping has been shut down”
}
}
Adieu, le Shopping API.
Console.log – Remote
If you have a PhoneGap/Cordova App, then you surely use Console.log statements to help with the debugging of your app while it is running in a simulator, or USB-attached device.
However, if your device cannot be attached to your development machine, or you cannot debug in the normal way, then this simple script lets you see Console.log output on a web browser.
Firstly, you’ll need access to a windows web-server, and upload this script:
<script language="C#" runat="server">
public static System.Collections.Generic.List<LogItem> logList = new
System.Collections.Generic.List<LogItem>();
protected void Page_Load(object sender, EventArgs e)
{
string strText = Request.QueryString["text"];
if (strText != null)
{
logList.Add(new LogItem(strText));
return;
}
Response.Write("Log Running...<hr>");
Response.Flush();
DateTime startTime = DateTime.UtcNow;
while(DateTime.UtcNow - startTime < TimeSpan.FromMinutes(1))
{
foreach(LogItem logItem in logList)
{
if (!logItem.isRead)
{
Response.Write(logItem.text + "<br>");
Response.Flush();
logItem.isRead = true;
}
}
System.Threading.Thread.Sleep(100);
}
Response.Redirect(Request.RawUrl);
}
public class LogItem
{
public LogItem(string text)
{
this.text = text;
}
public string text = "";
public bool isRead = false;
}
</script>
Let’s imagine that you put this script at http://www.yourserver.com/log.aspx
Then, you need to override the default action of console.log with this piece of javascript (Which requires JQuery)
console = {};
console.log = function(text)
{
$.get(“http://www.yourserver.com/log.aspx?text=” + encodeURIComponent(text) + “&nocache=” + Math.random());
}
This, then means that instead of writing to the console output, it makes an AJAX call to the logging script. Visiting the logging script webpage will display the text passed to console.log.
There are some limitations, such that it is only suitable for one-app-one-developer type environments, and you have to remember to remove the override for console.log before submitting the app to Google / Apple / BlackBerry …
Exceeding the Maximum size for Google static Maps
The table below shows the maximum allowable values for the size parameter at each scale value.
| API | scale=1 |
scale=2 |
scale=4 |
|---|---|---|---|
| Free | 640x640 |
640x640 (returns 1280×1280 pixels) |
Not available. |
| Google Maps API for Business | 2048x2048 |
1024x1024 (returns 2048×2048 pixels) |
512x512 (returns 2048×2048 pixels) |
– As per Google’s documentation, this is the largest size images you can get from the Google Static Maps API
However, there is a work-around that allows for larger images to be returned from the Google static maps API. But it requires quite a bit of work. Basically, you need to find the adjacent tile to the requested tile.
For this, you need to flatten your longitude and latitudes into a flat x / y grid. Once you have X/Y coordinates, then you can use simple maths to pick up the next tile, then with these new x/y positions, you have to re-map this to the spherical projection of the world, to give you back longitude and latitude values.
Flattening and projecting latitude/longitude coordinates to x/y grid coordinates is done using the Mercator projection. Here is a modified version of Mercator.js, that you can include in your project.
var MERCATOR_RANGE = 256;
function bound(value, opt_min, opt_max) {
if (opt_min != null) value = Math.max(value, opt_min);
if (opt_max != null) value = Math.min(value, opt_max);
return value;
}function degreesToRadians(deg) {
return deg * (Math.PI / 180);
}function radiansToDegrees(rad) {
return rad / (Math.PI / 180);
}function MercatorProjection() {
this.pixelOrigin_ = {x: MERCATOR_RANGE / 2, y: MERCATOR_RANGE / 2};
this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
};MercatorProjection.prototype.fromLatLngToPoint = function(latLng) {
var me = this;var point = {x:0,y:0};
var origin = me.pixelOrigin_;
point.x = origin.x + latLng.lng * me.pixelsPerLonDegree_;
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
// 89.189. This is about a third of a tile past the edge of the world tile.
var siny = bound(Math.sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999);
point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 – siny)) * -me.pixelsPerLonRadian_;
return point;
};MercatorProjection.prototype.fromPointToLatLng = function(point) {
var me = this;
var origin = me.pixelOrigin_;
var lng = (point.x – origin.x) / me.pixelsPerLonDegree_;
var latRadians = (point.y – origin.y) / -me.pixelsPerLonRadian_;
var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) – Math.PI / 2);
return {lat:lat, lng:lng};
};
Let’s just quickly have a look at how the Google static maps API works.
function renderMap(image, LatLng)
{
image.attr(“src”,”http://maps.googleapis.com/maps/api/staticmap?center=” + LatLng.lat + “,” + LatLng.lng + “&zoom=10&size=400×400&sensor=false”);
}
This displays a map of a specified latitude and longitude at zoom level 10, and a 400×400 size image. The image parameter is a jquery collection object referring to a HTML IMG tag.
Now, to display a map at 55,-7 you’d call:
renderMap($(“#img11”),{lat:55,lng:-7});
Now, to apply some magic to this, and display the map tile immediately eastward of this map location, then I use this function:
function GetTileDelta(center,zoom,mapWidth,mapHeight,delta){
var proj = new MercatorProjection();
var scale = Math.pow(2,zoom);
var centerPx = proj.fromLatLngToPoint(center);
var DeltaPx = {
x: (centerPx.x + ((mapWidth / scale) * delta.x)) ,
y: (centerPx.y + ((mapHeight/ scale) * delta.y))
};
var DeltaLatLon = proj.fromPointToLatLng(DeltaPx);
return DeltaLatLon;
}
Which is called as follows:
var RightLatLng = GetTileDelta({lat:55,lng:-7},10,400,400,{x:+1,y:0});
renderMap($(“#img12”),RightLatLng);
How this works, is by “flattening” the globe using the mercator projection, using simple maths to shift the x position the width of the map over to the right (eastward), then folding the x/y coordinates over the globe using the mercator projecion again, to provide the lat/lon coordinates.
By extension, you can then use this to obtain any size map required.
Translation API without an API Key

Over the last few days, I’ve been on the hunt for a good unlimited , free translation API. I’ve stumbled upon Glosbe.com, which does not require an API key, although they do mention it may be limited by request per IP to prevent abuse, and I’ll test that out on Monday.
But, as always, here is the C# code required to access this translation API:
First, we get the JSON data from their API as follows:
string strUrl = “http://glosbe.com/gapi/translate?from=eng&dest={1}&format=json&phrase={0}&pretty=true&tm=false”;
strUrl = string.Format(strUrl, word, language);
WebClient wc = new WebClient();
wc.Encoding = Encoding.UTF8;
var strJson = wc.DownloadString(strUrl);
The JSON object returned contains much more than just one word, it provides some sample usage, sentences, alternative translations, etc. But I’ll just assume the first translation is valid;
Here is the a sample translation of “cat” into italian
{
"result" : "ok",
"authors" : {
"1" : {
"U" : "http://en.wiktionary.org",
"id" : 1,
"N" : "en.wiktionary.org"
},
"86" : {
"U" : null,
"id" : 86,
"N" : "wiki"
},
"25018" : {
"U" : "http://glosbe.com",
"id" : 25018,
"N" : "GlosbeResearch"
},
"2695" : {
"U" : "http://dumps.wikimedia.org/enwiktionary/latest/enwiktionary-latest-pages-articles.xml.bz2",
"id" : 2695,
"N" : "Wiktionary"
},
"2771" : {
"U" : "http://dizionario.dejudicibus.it/",
"id" : 2771,
"N" : "Dizionario-generale-Inglese"
}
},
"dest" : "ita",
"phrase" : "cat",
"tuc" : [ {
"authors" : [ 1 ],
"meaningId" : -2324632015665027181,
"meanings" : [ {
"text" : "domestic species",
"language" : "eng"
}, {
"text" : "Mammifero carnivoro, felino di taglia media dal muso corto, domestico o allo stato selvatico (Felis Silvestris)",
"language" : "ita"
}, {
"text" : "A common four-legged animal (Felis silvestris) that is often kept as a household pet.",
"language" : "eng"
} ],
"phrase" : {
"text" : "gatto",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : 3792577973885107081,
"meanings" : [ {
"text" : "domestic species",
"language" : "eng"
} ],
"phrase" : {
"text" : "gatta",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : -8655742666001237549,
"meanings" : [ {
"text" : "domestic species",
"language" : "eng"
}, {
"text" : "Mammifero carnivoro, felino di taglia media dal muso corto, domestico o allo stato selvatico (Felis Silvestris)",
"language" : "ita"
}, {
"text" : "A common four-legged animal (Felis silvestris) that is often kept as a household pet.",
"language" : "eng"
} ],
"phrase" : {
"text" : "micio",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : 7605985072771688493,
"meanings" : [ {
"text" : "domestic species",
"language" : "eng"
} ],
"phrase" : {
"text" : "micia",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : 4835673442782652847,
"meanings" : [ {
"text" : "member of '''Felidae'''",
"language" : "eng"
} ],
"phrase" : {
"text" : "felina",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : -797550926637310842,
"meanings" : [ {
"text" : "member of '''Felidae'''",
"language" : "eng"
} ],
"phrase" : {
"text" : "felino",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : -1699184890059243019,
"meanings" : [ {
"text" : "raise anchor to cathead",
"language" : "eng"
} ],
"phrase" : {
"text" : "caponare",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : 3378167150074910555,
"phrase" : {
"text" : "caponare l’ancor",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : -6368320918367433051,
"phrase" : {
"text" : "capone",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : -6436875142752376744,
"phrase" : {
"text" : "doppio tripode",
"language" : "ita"
}
}, {
"authors" : [ 86 ],
"meaningId" : 6190890005020929990,
"phrase" : {
"text" : "felis silvestris catus",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : 4594590012605235113,
"phrase" : {
"text" : "flagellare",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : -3077370652934689664,
"phrase" : {
"text" : "frustare",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : 6355132814983896932,
"phrase" : {
"text" : "fustigare",
"language" : "ita"
}
}, {
"authors" : [ 25018 ],
"meaningId" : -8207633928534718191,
"phrase" : {
"text" : "gatto selvatico",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : 2464893808723829126,
"phrase" : {
"text" : "lippa",
"language" : "ita"
}
}, {
"authors" : [ 2695 ],
"meaningId" : -599611544161509388,
"phrase" : {
"text" : "micio micia",
"language" : "ita"
}
}, {
"authors" : [ 2771 ],
"meaningId" : 9131410793497437392,
"phrase" : {
"text" : "ragazza maliziosa",
"language" : "ita"
}
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "An enthusiast or player of jazz.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(computing) A ‘catenate’ program and command in Unix that reads one or more files and directs their content to an output device.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(slang, vulgar, African American Vernacular) A vagina; female external genitalia",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(slang) To vomit something.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(Irish, informal) terrible, disastrous.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(archaic, uncountable) The game of "trap and ball" (also called "cat and dog").",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(slang) Any of a variety of earth-moving machines. (from their manufacturer Caterpillar Inc.)",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(nautical) To flog with a cat-o'-nine-tails.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "vomit",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(archaic) A sturdy merchant sailing vessel (now only in "catboat").",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(slang) Prostitute. [from at least early 15th c.]",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "Any similar animal of the family Felidae, which includes lions, tigers, etc.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(nautical) Contraction of cat-o'-nine-tails.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "guy, fellow",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(archaic, uncountable) The trap of the game of "trap and ball".",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(slang) A person (usually male).",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(nautical) To hoist (the anchor) by its ring so that it hangs at the cathead.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(computing slang) To dump large amounts of data on (an unprepared target) usually with no intention of browsing it carefully.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(derogatory) A spiteful or angry woman. [from earlier 13th c.]",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "A catfish.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "A domesticated subspecies (Felis silvestris catus) of feline animal, commonly kept as a house pet. [from 8th c.]",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(nautical) A strong tackle used to hoist an anchor to the cathead of a ship.",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "(computing) To apply the <b>cat</b> command to (a file).",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "strong tackle used to hoist an anchor to the cathead of a ship",
"language" : "eng"
} ]
}, {
"authors" : [ 1 ],
"meaningId" : null,
"meanings" : [ {
"text" : "A catamaran.",
"language" : "eng"
} ]
} ],
"from" : "eng"
}
So, using this JSON, I created a C# class, omitting the “Authors” section that didn’t convert well, and I didn’t need anyway;
public class Meaning
{
public string text { get; set; }
public string language { get; set; }
}public class Phrase
{
public string text { get; set; }
public string language { get; set; }
}public class Tuc
{
public List<int> authors { get; set; }
public object meaningId { get; set; }
public List<Meaning> meanings { get; set; }
public Phrase phrase { get; set; }
}public class RootObject
{
public string result { get; set; }
public string dest { get; set; }
public string phrase { get; set; }
public List<Tuc> tuc { get; set; }
public string from { get; set; }
}
and finally, de-serializing it, and returning the one word I need;
System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
RootObject ro = js.Deserialize<RootObject>(strJson);
return ro.tuc[0].phrase.text;
Yandex Translation in C#

Ever since Google started charging for it’s Translation API, and Microsoft put a 2 Million character limit on their free translation API, then you have to start looking outside of the USA for a free translation service. That’s when I discovered the Russian translation service provided by Yandex. They also do plenty of other languages, (Albanian Armenian Azerbaijani Belarusian Bulgarian Catalan Croatian Czech Danish Dutch Estonian Finnish French German Greek Hungarian Italian Latvian Lithuanian Macedonian Norwegian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swedish Turkish Ukrainian)
So, the first step is to go to http://api.yandex.com/translate/ and sign up for a Yandex Passport, and get an API key.
Then, I created a C# class with a static method to do the translation from code:
public static string Translate(string word, string language)
{
string strUrl = “https://translate.yandex.net/api/v1.5/tr.json/translate?”;
strUrl += “key=trnsl.1.1……..”;
strUrl += “&lang=en-” + language;
strUrl += “&text=” + word;
WebClient wc = new WebClient();
wc.Encoding = Encoding.UTF8;
string strJson = wc.DownloadString(strUrl);
….
}
This returns a JSON string in the format:
{
“code”: 200,
“lang”: “en-ru”,
“text”: [
“Быть или не быть?”,
“Вот в чем вопрос.”
]
}
So, to de-serialize this to a C# object, I used a class generated from http://json2csharp.com/ as follows:
public class RootObject
{
public int code { get; set; }
public string lang { get; set; }
public List<string> text { get; set; }
}
Then the de-serialization can take place at the end of the translate method:
System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
RootObject ro = js.Deserialize<RootObject>(strJson);
return ro.text[0];
A quirk I noticed when doing this as a console app, was that the console could not write our Cyrillic characters. There is a way around this by using the Windows API, but I just used a MessageBox.
Offline Geolocation

Offline Geolocation is an Android Library that can be used to determine the location of an Android phone when both GPS positioning and an Internet connection are unavailable.
This project is completely open source, you can download the source code for the Android App, and import it into your eclipse workspace. All we ask is that you tell us who you are and what you plan to do with the code before downloading it. You can then use the code freely, without any license restrictions, although we’d love it if you can give us credit in your final product.
How this App works, is it detects nearby cell towers, and compares the cell id, MCC, MNC and LAC codes against a SQLLite database of over 2 million known cell towers worldwide. It is designed to give you the best answer it can, although, the data is not exhaustive. This data will never be as accurate as GPS or Online Geolocation, but it serves as a good failover, whenever an Internet connection is unavailable.
Please read more at www.offlinegeolocation.com
