Basically a blog which is a mixture of anything that comes up in the author's mind. From the technologies that makes his life convenient to the everyday news in his country.

Showing posts with label mobile development j2me cdc jni symbian. Show all posts
Showing posts with label mobile development j2me cdc jni symbian. Show all posts

CDC, JNI, Network Information

Thursday, March 27, 2008

(0) Comments

After all these days finally I was able to obtain network information from a java CDC app using ericsson's eclipse plugin via JNI.
What went wrong was I keep on inspecting my code while the sad thing is my java CDC app needs a Location and ReadDeviceData capability but you couldn't blame me I've tried adding caps=Location+ReadDeviceData to the cdcproject.properties file and it didn't work out. Fortunately, a guy named Alain Bergevin told me that me error which was -46 (KErrPermissionDenied) means "... it was caused by calling an API while does not have the required capability. eg. for CTelephony::GetSubscriberId , it need ReadDeviceData capability. Pls check whether the capability is specified in MMP file and the developer certificate with such capability is needed when sign the sis." which forced me to scrutinized the cdc eclipse plugin... and so I've found this file:

%epocroot%epoc32\tools\ppro-custom-launcher\custom-app.bat

from this file I've changed this line:
if "%CAPS%" == "" set CAPS=NONE -> if "%CAPS%" == "" set CAPS=ReadDeviceData+Location

and that's it my project started working properly.

Oh boy it took me some time to get here :-D

CDC,

Thursday, March 27, 2008

(0) Comments

P990i, JNI, Network Info(Cell ID, Location Area Code), ete3rdparty.lib

Wednesday, March 26, 2008

(0) Comments

It seems it's impossible to get the network information such as Cell ID, LAC in java CDC using JNI it's because JNI doesn't implement Thread and even though I've created a CActiveScheduler object still all I can get from the lib is the IMEI information. I'm sure my code is working perfectly since it runs and return the network informations accurately in a Console Application. Now I have to resort to a Client/Server application just to get the network informations.

"CDC JNI P990i UIQ3"

Tuesday, March 18, 2008

(1) Comments

My CDC JNI Codes:
[code]
//.pkg
#{"eplDll DLL"},(0xAFFFFFFE),1,0,0
;Localised Vendor name
%{"eScience"}
;Unique Vendor name
:"edwardpantojalegaspi"
"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\eplDll.dll" -"!:\sys\bin\eplDll.dll"

//bld.inf
PRJ_PLATFORMS
WINSCW GCCE
PRJ_EXPORTS
..\inc\eplDll.h
eplDll.def
PRJ_MMPFILES
eplDll.mmp

//definition file
EXPORTS
jni_lookup @ 1 NONAME

//mmp file
TARGET eplDll.dll
TARGETTYPE dll
UID 0x00000000 0xAFFFFFFE
USERINCLUDE ..\inc
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc \Symbian\UIQ3SDK\Extensions\Sony_Ericsson_CDC_Platform_1\epoc32\include
SOURCEPATH ..\src
SOURCE eplDll.cpp
SOURCE eplDllDllMain.cpp LocationInfoNative.cpp lookup.cpp
//#endif
LIBRARY euser.lib estlib.lib Etel3rdParty.lib
CAPABILITY LocalServices Location NetworkServices ReadDeviceData ReadUserData UserEnvironment WriteDeviceData WriteUserData
//JNI related
NOSTRICTDEF
DEFFILE .\ eplDll.def
EXPORTUNFROZEN
MACRO J9EPOC32
#if defined(WINS)
MACRO J9X86
#endif

//java native
public static native String getIMEI();
public static native String getIMSI();
public static native String getAreaCode();
public static native String getOperatorName();
public static native String getCellID();
public static native String getCountryCode();
public static native String getNetworkID();
[/code]

CDC JNI P990i UIQ3

Monday, March 17, 2008

(0) Comments

After quite some time 3 days perhaps I was able to run my JNI application on P990i device. I will post the code next time :D. I will go home to cook for dinner tonight probably plenty dishes hahaha.... Sleepless nights are now gone... A new tomorrow is waiting. That sure was corny... :-)

CDC JNI P990i

Monday, March 17, 2008

(0) Comments

I was successful in running my JNI application in UIQ3 emulator however it failed when I deployed on my P990i device I wonder what's causing the problem. Again I might stay late but I will not go overtime I'm still tired :D. I wonder if anyone out there has succeeded in doing this kind of thing :D. Oh well the problem is there is less or almost no example or even a clear documentation at all, which makes it harder :D.

BTW I came from province this morning which is Laguna and the South Expressway from Calamba to Alabang is as always traffic hahahaha oh boy I wonder how much longer will I endure this environment :D. DPWH just keep on digging :D.

Again OT, J2ME CDC JNI

Friday, March 14, 2008

(0) Comments

Oh my I have an appointment today but here I am going overtime :-). It's because next week would be the pilot testing of our J2ME project for Wyeth standby for updates, while doing that I'm still researching on how I will run CDC JNI on my SE P990i device cause I'm having a hard time making it run while it perfectly run on my UIQ3 emulator... And tomorrow I will be on standby oh my my schedule just got worse this week :-) but I hope everything get wrap up.

My JNI error is the same as described here: http://developer.sonyericsson.com/message/106704
JNI working in emulator, crashes on phone with KERN-EXEC 3, it's amazing how I got here :-).

P990i CDC JNI

Friday, March 14, 2008

(0) Comments

Finally I was able to run my JNI sample on UIQ3 emulator thanks to this link

http://developer.uiq.com/devlib/uiq_31/SDKDocumentation/doc_source/doc_source/faqSDK/faq_0536.html(bug report)
http://developer.sonyericsson.com/thread.jspa?messageID=115603&tstart=0(JNI steps)

My CODES
[code]
class HelloWorld {
private native String print();
public static void main(String[] args) {
}
public String getString() {
return print();
}
static {
System.loadLibrary("Prompt");
}
}
//native implementation
#include
#include
#include "HelloWorld.h"
JNIEXPORT jstring JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj) {
char *s;
s = "alf";
return (env)->NewStringUTF(s);
}
//lookup
#include
#include // Needed for strcmp

#include "HelloWorld.h"


#ifdef __cplusplus
extern "C" {
#endif

typedef void (*TFunc)();

typedef struct
{
char *token;
unsigned int procaddr;
} TABLE_ENTRY;

// lookup_table MUST be defined as 'const' or this file will cause a build error
// when comipling for the ARMI target
const TABLE_ENTRY lookup_table[]=
{
{ "Java_HelloWorld_print", (unsigned int) Java_HelloWorld_print },
};

// table_size MUST be defined as 'const' or this file will cause a build error
// when comipling for the ARMI target
const int table_size = sizeof(lookup_table) / sizeof(TABLE_ENTRY);


IMPORT_C TFunc jni_lookup(const char* aName);
EXPORT_C TFunc jni_lookup(const char* aName)
{
int res=0;
int mid=0;
int top=0;
int bottom=table_size-1;

// Loop while the number of the items left in the list is greater
// than 2. Each iteration will split the number of items left to search
// in half
while ((bottom - top) > 1) {
// This case handles the normal serach case where the number of
// items left to search is greater than 2
mid=(top+bottom)/2;
res=strcmp(aName,lookup_table[mid].token);
if (res==0) return((TFunc) lookup_table[mid].procaddr);
if (res>0) top=mid; else bottom=mid;
}

// If there are two items left in the list then the bottom item should be
// checked for a match
if (bottom != top) {
// Check the bottom item to see if it is a match
res=strcmp(aName,lookup_table[bottom].token);
if (res == 0) return ((TFunc) lookup_table[bottom].procaddr);
}

// Check the top item to see if it is a match
res=strcmp(aName,lookup_table[top].token);

if (res == 0) return ((TFunc) lookup_table[top].procaddr);

// Neither the top or bottom items were a match so the
// method must not exist in the file
return NULL;
}

#ifdef __cplusplus
}
#endif
//build
PRJ_PLATFORMS
gcce winscw

PRJ_EXPORTS
..\inc\Prompt.h

PRJ_MMPFILES
Prompt.mmp
//definition file
EXPORTS
jni_lookup @ 1 NONAME
//mmp
TARGET Prompt.dll
TARGETTYPE dll
UID 0x00000000 0x0A762D89

USERINCLUDE ..\inc
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc

SOURCEPATH ..\src

SOURCE Prompt.cpp
SOURCE PromptDllMain.cpp HelloWorld.cpp lookup.cpp

//By default, the build tools look for the WINSCW def file in a BWINS directory
//(at the same level as the directory containing the mmp file),
//the GCC ARM def file in a BMARM directory, and the ARMV5 def file in a EABI directory.
//If def files are stored in these locations, the project files does not need to specify
//the location of the def files explicitly. If you want to store the def files in some other
//location, you will need to specify in the project file where the .def files are using
//the deffile keyword.

//The following commented out code shows how the build system uses the implicit
// location for defiles. To create the DEF files Choose Project > Freeze Exports from Carbide
// or run 'abld freeze' from the command-line
//#if defined (WINS)
// DEFFILE ..\bwins\Prompt.def
//#elif defined (GCC32)
// DEFFILE ..\bmarm\Prompt.def
//#else
// DEFFILE ..\eabi\Prompt.def
//#endif

nostrictdef

LIBRARY euser.lib estlib.lib

DEFFILE .\ exports.def
MACRO J9EPOC32
#if defined(WINS)
MACRO J9X86
#endif
EXPORTUNFROZEN
//pkg
#{"Prompt DLL"},(0x0A762D89),1,0,0


;Localised Vendor name
%{"Vendor-EN"}

;Unique Vendor name
:"Vendor"

"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\Prompt.dll" -"!:\system\libs\Prompt.dll"
[/code]

Taken from the site above:
It’s important that you use the CDC Java VM’s versions of these files,
that are distributed with the CDC Java SDK.extension.

1) Run "javah" on all your class-files with natives.

2) Run the "symexports.exe"-tool in a DOS-window.
This tool takes as input arguments all the javah-header
files and an output-file name and creates a .c-file which
has the dll lookup function.
note: symexports is bundled in the UIQ3 SDK

Using the sample-files from the zip-file, the syntax would be as follows:

symexports -h:file1.h -h:file2.h -out:lookup.c

This creates the lookup.c file.

3) The lookup.c file needs to be included as a source-file
with all your other native source-files in your *.mmp-file
that you use to build the Symbian dll. The line below shows this:
SOURCE lookup.c

4) You need to include the jni.h file in all source-files
with JNI natives. The jni.h includes the jniport.h file
which is also required.

5) You also need a def-file, e.g. exports.def.
Put it in your build directory.
It needs to have the following content:

EXPORTS
jni_lookup @ 1 NONAME

6) The .mmp file needs to have the following lines added to it:

DEFFILE .\ exports.def
MACRO J9EPOC32

NOSTRICTDEF

#if defined(WINS)
MACRO J9X86
#endif

EXPORTUNFROZEN

J2ME Alert->Alert, Form->Alert

Monday, March 10, 2008

(0) Comments

Well, well after almost 20 minutes of debugging I found out that you cannot make something like this form->alert->function->alert what a painful bug it is... My solution was simply creating a new Form so it becomes form->alert->function->form-> and fortunately it works catching the bugs :D.

J2ME RMS

Monday, March 10, 2008

(0) Comments

public void writeStringArray(String file, String[] strArr) throws Exception {
RecordStore rs = RecordStore.openRecordStore(file, true, RecordStore.AUTHMODE_PRIVATE, false);
ByteArrayOutputStream bos = null;
DataOutputStream dos = null;
for(int i = 0; i < strArr.length; i++) {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
dos.writeUTF(strArr[i]);
byte[] b = bos.toByteArray();
rs.addRecord(b, 0, b.length);
}
dos.close();
bos.close();

rs.closeRecordStore();
}

public boolean deleteRecords(String file, String strKeys[], boolean createFile) throws Exception {
RecordStore rs = RecordStore.openRecordStore(file, createFile, RecordStore.AUTHMODE_PRIVATE, createFile);

if(rs.getNumRecords() > 0) {
RecordEnumeration re = rs.enumerateRecords(null, null, true);
ByteArrayInputStream bis = null;
DataInputStream dis = null;
for(int i = 0; i < strKeys.length; i++) {
while(re.hasNextElement()) {
int id = re.nextRecordId();
bis = new ByteArrayInputStream(rs.getRecord(id));
dis = new DataInputStream(bis);
bis = new ByteArrayInputStream(rs.getRecord(id));
dis = new DataInputStream(bis);
String strRecord = dis.readUTF();
if(strRecord.equals(strKeys[i])) {
System.out.println(strKeys[i]);
rs.deleteRecord(id);
break;
}
}
}
dis.close();
bis.close();
}
rs.closeRecordStore();

return true;
}

public String[] getStringArray(String file, boolean createFile) throws Exception {
RecordStore rs = RecordStore.openRecordStore(file, createFile, RecordStore.AUTHMODE_PRIVATE, createFile);
String strArr[] = null;
int ctr = 0;

if(rs.getNumRecords() > 0) {
RecordEnumeration re = rs.enumerateRecords(null, this, true);

strArr = new String[re.numRecords()];
ByteArrayInputStream bis = null;
DataInputStream dis = null;
while(re.hasNextElement()) {
int id = re.nextRecordId();
bis = new ByteArrayInputStream(rs.getRecord(id));
dis = new DataInputStream(bis);
bis = new ByteArrayInputStream(rs.getRecord(id));
dis = new DataInputStream(bis);
strArr[ctr++] = dis.readUTF();
}
dis.close();
bis.close();
}
rs.closeRecordStore();

return strArr;
}

J2ME RMS, HttpConnection

Monday, March 10, 2008

(0) Comments

Last week we finished a big part of our J2ME project which is a commercial application that will cater Malls for their mobile inventory of items using low end phones. We are successful in integrating my Mobile client with the host server. What we did was post data from mobile to host, however this morning I found a strange problem my alert that will tell me if my post works fine did not alert! So I was busy debugging many of my codes try implementing several threads unluckily I was unable to solve the problem. Well this lunch I've noticed a little line space and I was so sure that it was a newline fortunately it was just a host misq for there was a newline inserted in my expected response unfortunately it took my 2 hours :D. Part of the codes:
[code]
Thread deadLock = new Thread(new Runnable() {
String strReply = "";
public void run() {
WaitCanvas cWait = new WaitCanvas();
HttpConnection c = null;
InputStream is = null;
midlet.SetDisplay(cWait);
try {
int rc;
c = (HttpConnection)Connector.open(Settings.Post_Url + strParams);
c.setRequestMethod(HttpConnection.POST);
c.setRequestProperty("If-Modified-Since", "29 Oct 1999 19:43:31 GMT");
c.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
c.setRequestProperty("Content-Language", "en-US");
rc = c.getResponseCode();
if (rc != HttpConnection.HTTP_OK) {
Alert a = new Alert("Error", "Connection to host failed.", null, AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.addCommand(cmdBack);
a.setCommandListener(new MyCommandListener());
midlet.SetDisplay(a);
}
is = c.openInputStream();
int len = (int)c.getLength();
if (len > 0) {
int actual = 0;
int bytesread = 0 ;
byte[] data = new byte[len];
while ((bytesread != len) && (actual != -1)) {
actual = is.read(data, bytesread, len - bytesread);
bytesread += actual;
}                 
strReply = new String(data);
}        
} catch(Exception e) {
//do something here
} finally {
try {
if (is != null)
is.close();
if (c != null)
c.close();
} catch(Exception e) { }
}
if(strReply.equals("1")) {
//do something here
} else if(strReply.equals("0")){
//do something here
} else if(strReply.equals("2")){
//do something here
}
}
});
deadLock.start();
[/code]

GLOBE IMS, ctelephony, etel3rdparty, j2me, travel portal :D

Thursday, March 06, 2008

(0) Comments

Our company recently join the GLOBE IMS Challenge which focuses on using IMS technology on mobile. Many things are possible using Ericsson's SDS4 SDK such as the connectivity between different devices from mobile to TV to PS2 it's really amazing. Unfortunately this technology is new in it's nature limiting the developer like me to what we can develop. Its ericsson's  so target mobile are also ericsson's and we are advised to use P990i, P1 etc. SJP3.4 I think which doesn't have Location API such as JP7.

Now, the main module of our project will use Location API so I was force to use C++ for Symbian Programming using the ctelephony class from etel3rdparty.lib. I was successful in making getting the Location data in Symbian such as Cell ID, Location Area Code, etc. However, my main problem right now is how will I compile the DLL in such a way that I can call it in a java code using JNI which, luckily is supported by most P990i phones. I've tried JNI in windows however, I'm not sure about it's compilation in mobile.

Well, for me to not forget my code here it is :D
[code]
#ifndef SYSTEMMANAGER_H
#define SYSTEMMANAGER_H

#include // For CActive, link against: euser.lib
#include // For RTimer, link against: euser.lib

#include

class CSystemManager : public CActive
{
public:
typedef enum {EHandsetIMEI, EHandsetIMSI, EHandsetNetworkInfo } InfoType;
public:
// Cancel and destroy
~CSystemManager();

// Two-phased constructor.
static CSystemManager* NewL();

// Two-phased constructor.
static CSystemManager* NewLC();

public: // New functions
// Function for making the initial request
void StartL();
TDesC& GetIMEI();
TDesC& GetIMSI();
TUint GetLocationAreaCode();
TUint GetCellID();
TDesC& GetOperatorName();
TDesC& GetCountryCode();
TDesC& GetNetworkID();
private:
// C++ constructor
CSystemManager();
// Second-phase constructor
void ConstructL();
private: // From CActive
// Handle completion
void RunL();
// How to cancel me
void DoCancel();
// Override to handle leaves from RunL(). Default implementation causes
// the active scheduler to panic.
TInt RunError( TInt aError );

private:
enum TSystemManagerState
{
EUninitialized, // Uninitialized
EInitialized, // Initalized
EError // Error condition
};
enum TGetInfoState
{
       EStart = 1,
       EGetPhoneInfo,
       EDone
};
private:
TInt iState; // State of the active object
RTimer iTimer; // Provides async timing service

InfoType iPhoneInfoType;
CTelephony* iTelephony;
CTelephony::TPhoneIdV1 iPhoneIdV1;
    CTelephony::TPhoneIdV1Pckg iPhoneIdV1Pckg;
    
    CTelephony::TSubscriberIdV1 iSubscriberIdV1;
    CTelephony::TSubscriberIdV1Pckg iSubscriberIdV1Pckg;
    
    CTelephony::TNetworkInfoV1 iNetworkInfoV1;
    CTelephony::TNetworkInfoV1Pckg iNetworkInfoV1Pckg;
    
    CActiveSchedulerWait iActiveSchedulerWait;
    
    TBuf iIMEI;
    TBuf iModelNumber;
    TBuf iIMSI;        
    TUint iLocationAreaCode;
    TUint iCellId;
    TBuf<16> iOperatorName;
    TBuf<4> iCountryCode;
    TBuf<8> iNetworkId;
};

#endif // SYSTEMMANAGER_H

#include
#include
#include
#include
#include
#include

#include "SystemManager.h"

CSystemManager::CSystemManager () : CActive(EPriorityStandard), iPhoneInfoType(EHandsetIMEI),
iState(EStart),
iTelephony(NULL),
iSubscriberIdV1Pckg(iSubscriberIdV1),
iPhoneIdV1Pckg(iPhoneIdV1),
iNetworkInfoV1Pckg(iNetworkInfoV1) { }

CSystemManager* CSystemManager::NewLC()
{
CSystemManager* self = new ( ELeave ) CSystemManager();
CleanupStack::PushL( self );
self->ConstructL();
return self;
}

CSystemManager* CSystemManager::NewL()
{
CSystemManager* self = CSystemManager::NewLC();
CleanupStack::Pop(); // self;
return self;
}

void CSystemManager::ConstructL()
{
User::LeaveIfError( iTimer.CreateLocal() ); // Initialize timer
CActiveScheduler::Add( this ); // Add to scheduler
iTelephony = CTelephony::NewL();
}

CSystemManager::~CSystemManager()
{
Cancel(); // Cancel any request, if outstanding
delete iTelephony;
iTimer.Close(); // Destroy the RTimer object
// Delete instance variables if any
}

void CSystemManager::DoCancel()
{
switch(iPhoneInfoType)
{
case EHandsetIMEI: 
iTelephony->CancelAsync(CTelephony::EGetPhoneIdCancel);
break;
case EHandsetIMSI:
iTelephony->CancelAsync(CTelephony::EGetSubscriberIdCancel);
break;
default:
iTelephony->CancelAsync(CTelephony::EGetCurrentNetworkInfoCancel);
break;
}
}

void CSystemManager::StartL()
{
Cancel(); // Cancel any request, just to be sure
//iState = EUninitialized;
//iTimer.After( iStatus, aDelay ); // Set for later
iState = EGetPhoneInfo;
switch(iPhoneInfoType)
{
case EHandsetIMEI:
{
iTelephony->GetPhoneId(iStatus, iPhoneIdV1Pckg);
break;
}
case EHandsetIMSI:
{
iTelephony->GetSubscriberId(iStatus, iSubscriberIdV1Pckg);

break;
}
case EHandsetNetworkInfo:
{
iTelephony->GetCurrentNetworkInfo(iStatus, iNetworkInfoV1Pckg);
break;
}
}
SetActive(); 
iActiveSchedulerWait.Start();
}

void CSystemManager::RunL()
{
iState = EDone;
if ( iActiveSchedulerWait.IsStarted() )
{
iActiveSchedulerWait.AsyncStop();
if(iStatus == KErrNone)
{
switch(iPhoneInfoType)
{
case EHandsetIMEI:
{
iIMEI = iPhoneIdV1.iSerialNumber;
}
break;
case EHandsetIMSI:
{
iIMSI = iSubscriberIdV1.iSubscriberId;
}
break;
case EHandsetNetworkInfo:
{
iLocationAreaCode = iNetworkInfoV1.iLocationAreaCode;
iCellId = iNetworkInfoV1.iCellId;
iOperatorName = iNetworkInfoV1.iLongName;
iCountryCode = iNetworkInfoV1.iCountryCode;
iNetworkId = iNetworkInfoV1.iNetworkId;
}
break;
}
}
else
{
// Do nothing
}
}
}

TDesC& CSystemManager::GetIMEI()
{
iPhoneInfoType = EHandsetIMEI;
iIMEI.Zero();

StartL();
return iIMEI;
}

TDesC& CSystemManager::GetIMSI()
{
iPhoneInfoType = EHandsetIMSI;
iIMSI.Zero();

StartL();
return iIMSI;
}

TUint CSystemManager::GetLocationAreaCode() {
iPhoneInfoType = EHandsetNetworkInfo;
iLocationAreaCode = 0;
StartL();
return iLocationAreaCode;
}

TUint CSystemManager::GetCellID() {
iPhoneInfoType = EHandsetNetworkInfo;
iCellId = 0;
StartL();
return iCellId;
}

TDesC& CSystemManager::GetOperatorName()
{
iPhoneInfoType = EHandsetNetworkInfo;
iOperatorName.Zero();

StartL();
return iOperatorName;
}

TDesC& CSystemManager::GetCountryCode()
{
iPhoneInfoType = EHandsetNetworkInfo;
iCountryCode.Zero();

StartL();
return iCountryCode;
}

TDesC& CSystemManager::GetNetworkID()
{
iPhoneInfoType = EHandsetNetworkInfo;
iNetworkId.Zero();

StartL();
return iNetworkId;
}

TInt CSystemManager::RunError( TInt aError )
{
return aError;
}
[/code]

Actually parts of the code are from sonyericsson and developer.symbian and the uiq 3 documentation the .chm file. I've just paste them together :-).

Currently, I am doing 2 other major projects in short I am really busy and I haven't touch this project for days. For record the other 2 are: 
1.) a Travel web Portal wherein you can book your flights online (search for flights and it's info - how much, when, etc.)
.) J2ME project that will cater the department stores, items' inventory will now be inventoried though mobile using GPRS so a not so very high model phone is required.:D

See I was quite versatile and now I'm writing this 'coz my head is about to explode buwahahaha....

CDC Application

Friday, February 29, 2008

(0) Comments

Continue to RND if I will be able to run a CDC application on my P990i so I can implement a JNI to call my C++ native functions getting the Network Information such as Cell ID, Country Code, Mobile Subscriber etc.

How I wish this phone just supports JP-7 so I can just get the Network Information from java.property...

Contributors