Search This Blog

Tuesday 16 November 2010

How-to add location service to your (not having GPS chip) Android device


Introduction
This is a small tutorial about how I added location service to my Android device. In my case the android device is an ASUS eeepc 901 running Froyo from http://www.android-x86.org/ project. The eeepc does not have a GPS chip on board, therefore the location data should be obtained from an external devcie, i.e. a bluetooth GPS adapter.

However, the main reason doing this is to gain better knowledge of the below Android framework concepts:
  • location service
  • bluetooth service
  • remote service handling
  • notification
  • menu / preferences
  • broadcast receiver
For whom  only interested in this  functionality, there is a nice application named BlueGps4Droid, which I found out after I did this exercise.

The approach is to receive the NMEA data using the available bluetooth port. After processing these data, the location data will be injected into the system using the so-called mock location provider. The advantage of this approach is that you can implement this using the standard Android SDK.

The other way is to integrate the location function into the Android system. Then  you will need the sources of your Android system. But you will get a more complete location service. In a next post I'll describe how I did that as well ...


 
What you need:

Overview
Basically this program is composed of following:
  1. Main activity to start/stop the sevices and to provide menu/preference to define the bluetooth device name
  2. Bluetotoh service
  3.  Location service

Main activity


menu/preferences:
        // init preferences
        preferences = PreferenceManager.getDefaultSharedPreferences(this);



    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch ( item.getItemId() ) {
        case R.id.preferences:
            Intent i = new Intent(this, Preferences.class);
            startActivity(i);
            break;
        }
         return true;
    }


The menu structure is defined in menu/menu.xml and xml/preferences.xml.
You can do this in Eclipse IDE as below.

Define menu:
Select your project,right click on it and select New -> Other -> Android -> "Android XML File"
Then press Add and select "Item"

Define preferences:
Like the menu creation, but select the "Preference"
Then add a "devicename" (EditTextPreference)

Bluetooth service
The used bluetooth API is from Android 2.0 and above.

When starting the bluetooth service, the device name is retrieved from the shared preferences.

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
//        SharedPreferences.Editor edit = sharedPreferences.edit();
        mGpsDevice = sharedPreferences.getString(PREF_BLUETOOTH_DEVICE, "");

        log("onStartCommand called, looking for device:" + mGpsDevice);
        toast("Bluetooth service started");
        me = new Thread(mTask);
        me.start();
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }



Refer to below codes:
       _adapter = BluetoothAdapter.getDefaultAdapter();
       _adapter.startDiscovery();

Scanning the bluetooth device is done in a new thread named mTask. After that the named device has been able to be found, another thread (named mProcTask)  will be created to receive  the GPS data and then to broadcast it


For sake of simplicity, not all of the NMEA data will be processed.

Location service

A mock location provider will be added here:
        locMgr.addTestProvider(MOCK_PROVIDER,
                /* req. netowork */ false,
                /* req. Sat */ false,
                /* req. Cell*/ false,
                /* need money */ false,
                /* has altitude */ true,
                /* has speed */ true,
                /* has bearing */ true,
                /* power */ 0,
                /* accuracy */ TEST_ACCURACY);

 
And the broad-casted data will be received and injected into the Android system:
    class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String sentence = intent.getStringExtra(BluetoothUtil.NMEA_SENTENCE);
            /* assumed data is a GPRMC sentence */
            if ( sentence.startsWith("$GPRMC") ) {
                procRMC(sentence);
            } else if ( sentence.startsWith("$GPGGA") ) {
                procGGA(sentence);
            }
           
            locMgr.setTestProviderLocation(MOCK_PROVIDER, mLoc);
        }


Resources
You can download my codes from here.
Also worth mentioning  the GPS status tool.

No comments:

Post a Comment