/*
* ShareNav - Copyright (c) 2009 Kai Krueger apmonkey at users dot sourceforge dot net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See COPYING
*/
package net.sharenav.gps.location;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import net.sharenav.gps.location.GetCompass;
import net.sharenav.gps.location.SocketGateway;
import net.sharenav.util.Logger;
//#if polish.android
import android.content.Context;
import de.enough.polish.android.midlet.MidletBridge;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
//#endif
import de.enough.polish.util.Locale;
public class CellIdProvider {
private static final int CELLMETHOD_NONE = 0;
private static final int CELLMETHOD_SE = 1;
private static final int CELLMETHOD_S60FP2 = 2;
private static final int CELLMETHOD_MOTO = 3;
private static final int CELLMETHOD_SOCKET = 4;
private static final int CELLMETHOD_DEBUG = 5;
private static final int CELLMETHOD_ANDROID = 6;
private static final int CELLMETHOD_SAMSUNG = 7;
private static final int CELLMETHOD_LG = 8;
private static CellIdProvider singelton;
private static final Logger logger = Logger.getInstance(CellIdProvider.class,
Logger.TRACE);
private int cellRetrievelMethod = -1;
GsmCell cachedCell = null;
private CellIdProvider() {
//#debug info
logger.info("Trying to find a suitable cell id provider");
//#if polish.android
try {
//#debug info
logger.info("Trying to see if android method is available");
GsmCell cell = obtainAndroidCell();
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_ANDROID;
//#debug info
logger.info(" Yes, the Android method works");
return;
} else {
//#debug info
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as Android failed", e);
//Nothing to do here, just fall through to the next method
}
//#endif
try {
//#debug info
logger.info("Trying to see if Sony-Ericcson method is available");
GsmCell cell = obtainSECell();
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_SE;
//#debug info
logger.info(" Yes, the Sony-Ericcsson method works");
return;
} else {
//#debug info
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as a Sony-Ericsson failed", e);
//Nothing to do here, just fall through to the next method
}
try {
//#debug info
logger.info("Trying to see if Motorola method is available");
GsmCell cell = obtainMotoOrSamsungCell(false);
if (cell != null) {
logger.error(Locale.get("cellidprovider.MotorolaCellIDPleseCheck")/*Motorola CellID is experimental and may be wrong. Please check data before uploading*/);
cellRetrievelMethod = CELLMETHOD_MOTO;
//#debug info
logger.info(" Yes, the Motorola method works");
return;
} else {
//#debug info
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as a Motorola failed", e);
//Nothing to do here, just fall through to the next method
}
try {
//#debug info
logger.info("Trying to see if Samsung method is available");
GsmCell cell = obtainMotoOrSamsungCell(true);
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_SAMSUNG;
//#debug info
logger.info(" Yes, the Samsung method works");
return;
} else {
//#debug info
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as a Samsung failed", e);
//Nothing to do here, just fall through to the next method
}
try {
//#debug info
logger.info("Trying to see if LG method is available");
GsmCell cell = obtainLGCell();
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_LG;
//#debug info
logger.info(" Yes, the LG method works");
return;
} else {
//#debug info
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as an LG failed", e);
//Nothing to do here, just fall through to the next method
}
try {
//#debug info
logger.info("Trying to see if there is a cellid server running on this device");
GsmCell cell = obtainSocketCell();
// FIXME
// cellRetrievelMethod = CELLMETHOD_SOCKET;
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_SOCKET;
logger.info(" Yes, there is a server running and we can get a cell from it");
return;
} else {
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Could not connect to socket", e);
//Nothing to do here, just fall through to the next method
}
try {
//#debug info
logger.info("Trying to see if S60 3rd FP2 method is available");
GsmCell cell = obtainS60FP2Cell();
if (cell != null) {
cellRetrievelMethod = CELLMETHOD_S60FP2;
logger.info(" Yes, the S60 3rd FP2 method works");
return;
} else {
logger.info(" No, need to use a different method");
}
} catch (Exception e) {
logger.silentexception("Retrieving CellID as a Nokia S60 3rd FP2 failed", e);
}
cellRetrievelMethod = CELLMETHOD_NONE;
//#debug info
logger.error(Locale.get("cellidprovider.NoCellIDUsable")/*No method of retrieving CellID is valid, can not use CellID*/);
}
public synchronized static CellIdProvider getInstance() {
if (singelton == null) {
singelton = new CellIdProvider();
}
return singelton;
}
//#if polish.android
private GsmCell obtainAndroidCell() {
GsmCell cell = new GsmCell();
TelephonyManager tm =
(TelephonyManager) MidletBridge.instance.getSystemService(Context.TELEPHONY_SERVICE);
GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
cell.cellID = location.getCid();
cell.lac = location.getLac();
String networkOperator = tm.getNetworkOperator();
if (networkOperator != null && networkOperator.length() > 0) {
try {
cell.mcc = (short) Integer.parseInt(networkOperator.substring(0, 3));
cell.mnc = (short) Integer.parseInt(networkOperator.substring(3));
} catch (NumberFormatException e) {
}
}
if (location == null) {
//#debug debug
logger.debug("No valid cell-id");
return null;
}
return cell;
}
//#endif
private GsmCell obtainSECell() {
String cellidS = null;
String mccS = null;
String mncS = null;
String lacS = null;
GsmCell cell = new GsmCell();
cellidS = System.getProperty("com.sonyericsson.net.cellid");
mccS = System.getProperty("com.sonyericsson.net.cmcc");
mncS = System.getProperty("com.sonyericsson.net.cmnc");
lacS = System.getProperty("com.sonyericsson.net.lac");
if ((cellidS == null) || (mccS == null) || (mncS == null) || (lacS == null)) {
//#debug debug
logger.debug("No valid cell-id");
return null;
}
try {
cell.cellID = Integer.parseInt(cellidS, 16);
cell.mcc = (short) Integer.parseInt(mccS);
cell.mnc = (short) Integer.parseInt(mncS);
cell.lac = Integer.parseInt(lacS, 16);
} catch (NumberFormatException nfe) {
logger.silentexception("Failed to parse cell-id (cellid: " + cellidS +
" mcc: " + mccS + " mnc: " + mncS + " lac: " + lacS, nfe);
return null;
}
return cell;
}
private GsmCell obtainS60FP2Cell() {
String cellidS = null;
String mccS = null;
String mncS = null;
String lacS = null;
GsmCell cell = new GsmCell();
cellidS = System.getProperty("com.nokia.mid.cellid");
/**
* The documentation claims that the country code is returned as
* two letter iso country code, but at least my phone Nokia 6220 seems
* to return the mcc instead, so assume this gives the mcc for the moment.
*/
mccS = System.getProperty("com.nokia.mid.countrycode");
mncS = System.getProperty("com.nokia.mid.networkid");
if (mncS.indexOf(" ") > 0) {
mncS = mncS.substring(0, mncS.indexOf(" "));
}
//System.getProperty("com.nokia.mid.networksignal");
/*
* Lac is not currently supported for S60 devices
* The com.nokia.mid.lac comes from S40 devices.
* We include this here for the moment, in the hope
* that future software updates will include this into
* S60 as well.
*
* The LAC is needed to uniquely identify cells, but openCellID
* seems to do a lookup ignoring LAC at first and only using it
* if there are no results. So for retrieving Cells, not having
* the LAC looks ok, but we won't be able to submit new cells
* without the LAC
*/
lacS = System.getProperty("com.nokia.mid.lac");
if ((cellidS == null) || (mccS == null) || (mncS == null)) {
//#debug debug
logger.debug("No valid cell-id");
return null;
}
try {
cell.cellID = Integer.parseInt(cellidS);
cell.mcc = (short) Integer.parseInt(mccS);
cell.mnc = (short) Integer.parseInt(mncS);
if (lacS != null) {
//#debug info
logger.info("This Nokia device supports LAC! Please report this to ShareNav so that we can correctly use the LAC");
}
} catch (NumberFormatException nfe) {
logger.silentexception("Failed to parse cell-id (cellid: " + cellidS +
" mcc: " + mccS + " mnc: " + mncS + " lac: " + lacS, nfe);
return null;
}
return cell;
}
private GsmCell obtainMotoOrSamsungCell(boolean samsung) {
String cellidS = null;
String mccS = null;
String mncS = null;
String lacS = null;
String imsi = null;
GsmCell cell = new GsmCell();
if (samsung) {
cellidS = System.getProperty("CELLID");
lacS = System.getProperty("LAC");
} else {
cellidS = System.getProperty("CellID");
lacS = System.getProperty("LocAreaCode");
}
/*
* This method of getting MNC and MCC seems
* highly problematic, as it will produce
* broken data when abroad or otherwise
* roaming outside the home network.
* I hope this won't cause corrupt data
*
* Also, it seems that not all networks use
* the same format for the imsi. Some have
* a two digit mnc and some a three digit mnc
* So this method will fail in some countries.
*/
imsi = System.getProperty("IMSI");
if (imsi != null) {
mccS = imsi.substring(0,3);
mncS = imsi.substring(3,5);
}
if ((cellidS == null) || (mccS == null) || (mncS == null)) {
//#debug debug
logger.debug("No valid cell-id");
return null;
}
try {
cell.cellID = Integer.parseInt(cellidS);
cell.mcc = (short) Integer.parseInt(mccS);
cell.mnc = (short) Integer.parseInt(mncS);
cell.lac = Integer.parseInt(lacS);
} catch (NumberFormatException nfe) {
logger.silentexception("Failed to parse cell-id (cellid: " + cellidS +
" mcc: " + mccS + " mnc: " + mncS + " lac: " + lacS, nfe);
return null;
}
return cell;
}
private GsmCell obtainLGCell() {
String cellidS = null;
String mccS = null;
String mncS = null;
GsmCell cell = new GsmCell();
if (System.getProperty("com.lge.lgjp") == null) {
// should be "LGJP1", "LGJP2" or "LGJP3 according to https://sourceforge.net/tracker/index.php?func=detail&aid=3310226&group_id=192084&atid=939977
// FIXME should we check the value?
return null;
}
cellidS = System.getProperty("com.lge.net.cellid");
mccS = System.getProperty("com.lge.net.cmcc");
mncS = System.getProperty("com.lge.net.cmnc");
// apparently we can't get LAC
if ((cellidS == null) || (mccS == null) || (mncS == null)) {
//#debug debug
logger.debug("No valid cell-id");
return null;
}
try {
cell.cellID = Integer.parseInt(cellidS);
cell.mcc = (short) Integer.parseInt(mccS);
cell.mnc = (short) Integer.parseInt(mncS);
} catch (NumberFormatException nfe) {
logger.silentexception("Failed to parse cell-id (cellid: " + cellidS +
" mcc: " + mccS + " mnc: " + mncS, nfe);
return null;
}
return cell;
}
private GsmCell obtainSocketCell() {
int retval;
retval = SocketGateway.getSocketData(SocketGateway.TYPE_CELLID);
if (retval == SocketGateway.RETURN_OK) {
return SocketGateway.getCell();
}
if (cellRetrievelMethod == CELLMETHOD_SOCKET && retval == SocketGateway.RETURN_IOE) {
/*
* The local helper daemon seems to have died.
* No point in trying to continue trying,
* as otherwise we will get an exception every time
*/
//cellRetrievelMethod = CELLMETHOD_NONE;
return null;
}
return null;
}
private GsmCell obtainDebugCell() {
/*
* This code is used for debugging cell-id data on the emulator
* by generating one of 16 random cell-ids
*/
Random r = new Random();
switch (r.nextInt(16)) {
case 0: return new GsmCell(0x2627, (short) 234, (short) 33, 0x0133);
case 1: return new GsmCell(0x2628, (short) 234, (short) 33, 0x0133);
case 2: return new GsmCell(0x2629, (short) 234, (short) 33, 0x0133);
case 3: return new GsmCell(0x2620, (short) 234, (short) 33, 0x0134);
case 4: return new GsmCell(0x2619, (short) 234, (short) 33, 0x0134);
case 5: return new GsmCell(0x2629, (short) 234, (short) 33, 0x0135);
case 6: return new GsmCell(0x2649, (short) 234, (short) 33, 0x0136);
case 7: return new GsmCell(0x2659, (short) 234, (short) 33, 0x0137);
case 8: return new GsmCell(0xB1D1, (short) 310, (short) 260, 0xB455);
case 9: return new GsmCell(0x79D9, (short) 310, (short) 260, 0x004D);
case 10: return new GsmCell(0x3E92FFF, (short) 284, (short) 3, 0x03E9);
case 11: return new GsmCell(0x1B0, (short) 250, (short) 20, 0x666D);
case 12: return new GsmCell(0x23EC45A, (short) 234, (short) 10, 0x958C);
case 13: return new GsmCell(0x8589A, (short) 234, (short) 10, 0x8139);
case 14: return new GsmCell(0x85A67, (short) 234, (short) 10, 0x8139);
case 15: return new GsmCell(0x151E, (short) 724, (short) 5, 0x0552);
default:
//#debug debug
logger.debug("No valid cell-id");
return null;
}
}
public GsmCell obtainCachedCellID() {
return cachedCell;
}
public GsmCell obtainCurrentCellId() throws Exception {
//#debug info
logger.info("Tring to retrieve cell-id");
switch (cellRetrievelMethod) {
case CELLMETHOD_NONE:
//#debug info
logger.info("Can't retrieve CellID, as there is no valid method available");
return null;
case CELLMETHOD_SE:
cachedCell = obtainSECell();
break;
//#if polish.android
case CELLMETHOD_ANDROID:
cachedCell = obtainAndroidCell();
break;
//#endif
case CELLMETHOD_MOTO:
cachedCell = obtainMotoOrSamsungCell(false);
break;
case CELLMETHOD_SAMSUNG:
cachedCell = obtainMotoOrSamsungCell(true);
break;
case CELLMETHOD_LG:
cachedCell = obtainLGCell();
break;
case CELLMETHOD_S60FP2:
cachedCell = obtainS60FP2Cell();
break;
case CELLMETHOD_SOCKET:
cachedCell = obtainSocketCell();
break;
case CELLMETHOD_DEBUG:
cachedCell = obtainDebugCell();
break;
default:
//#debug error
logger.error("Unknown CellID retrieval method selected!");
return null;
}
//#debug debug
logger.debug("Retrieved " + cachedCell);
return cachedCell;
}
}