Thursday, February 19, 2015

Location Tracking and Retrieval

As a mobile guy a key feature which attracts most of the developer is location. Android provides Google play services to get the location(Latitude and Longitude), Maps, GeoCoding and Geofencing facility, It also provides a way to track using GPS/Cell Tower/Passive Providers.

As I was looking over the internet I found Verayu.com which provides a complete platform for Location Retrieval and Location Tracking using LAAS API(http://docs.verayu.com/).

How verayu.com is more efficient for Tracking ?
Verayu.com doesnt use GPS Service, it works via the concept of Cell Tower tracking, it has a huge corpus of Location database which was run over different parts of india. The accuracy claim by verayu is more than 80% accurate.

Now this interest me to build an Android application over LAAS API for location tracking. I was always keen to build an application which helps tracking loved one's when they are away, even though they are away they should be under my surveillance so that I can track there safety especially in a country such as India where crime rates are increasing on women.

I would like to give you the broader overview of API and how it can be integrated with mobile applications. First thing is get registered with Verayu.com, you would be provided with API key and Email. For example adding you the API

GetTrackees:
https://laasapi.verayu.com/?method=gettrackees&key=<key>&email=<email>

Key: 32 bit AlphaNumeric encrypted key

Once I am half thru the android app, I would like to share you the flow.


Please watch for my next blog and comments/suggestions are welcome...

Wednesday, January 7, 2015

Android.mk for C++ native library compilation

Here is the sample template Android.mk which helps in compiling C++ Native source code into Shared library

Note: mentioned values differs from which features you need/or you dont need.


Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libabc
LOCAL_MODULE_TAGS := eng
LOCAL_CPP_EXTENSION := .cc
LOCAL_RTTI_FLAG := -frtti
LOCAL_SRC_FILES := main.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include external/stlport/libstlport.mk
LOCAL_LDFLAGS += -lc -lz
LOCAL_SHARED_LIBRARIES := libgabi++ libstlport
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_PLATFORM := android-9
APP_ABI := armeabi
APP_STL := stlport_static(or gnustl_static)
APP_CPPFLAGS := -fexceptions

Android Application: Thread Safe DB Access & Custom View display

After a pretty long timegap I am back again with Android development work. Today I add an opportunity to look into android application. Today I focus on key functionality such as

1. Custom View Display
2. Singleton Sqlite DB Connection across multiple threads

I have written a sample application, I am pasting code snippets which will explain both.

Note: There could be typo please correct it or put your comments so that I can correct it back

DBHelper.java

public class DBHelper extends SQLiteOpenHelper{
private static final String DB_NAME="Billing";

public DBHelper(Context context) {
super(context, DB_NAME, null, 1);
}

@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table particular " + "(id integer primary key, particulars text, qty text, price text, date text)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS particular");
   onCreate(db);
}
}

DatabaseManager.java

public class DatabaseManager {

private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;

public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}

public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(
DatabaseManager.class.getSimpleName()
+ " is not initialized, call initializeInstance(..) method first.");
}
return instance;
}

public synchronized SQLiteDatabase openDatabase() {
if (mOpenCounter.incrementAndGet() == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized SQLiteDatabase openReadDatabase() {
if (mOpenCounter.incrementAndGet() == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getReadableDatabase();
}
return mDatabase;
}

public synchronized void closeDatabase() {
if (mOpenCounter.decrementAndGet() == 0) {
// Closing database
mDatabase.close();
}
}
}

Particular.java(Is the MainActivity)

package com.example.billtracking;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.ActionBar;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class Particular extends ActionBarActivity {
EditText edtDate;
Button bAccept;
Button bClear;
public EditText edtParticular;
public EditText edtQty;
public EditText edtPrice;
public ListView listView;
ListViewAdapterHelper adapter;
static Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
static int i = 1;
private MenuItem menuItem;
public EditText edtSearch;
private ProgressDialog prgDialog;
public static final int progress_bar_type = 0;

/*
* FragmentManager fm; private boolean isTaskRunning = false;
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ActionBar actionBar = getActionBar();

edtDate = (EditText) findViewById(R.id.date);
Date myDate = new Date();
edtDate.setText(new SimpleDateFormat("dd/MM/yyyy").format(myDate));

edtParticular = (EditText) findViewById(R.id.particular);
edtQty = (EditText) findViewById(R.id.qty);
edtPrice = (EditText) findViewById(R.id.price);

listView = (ListView) findViewById(R.id.list);

bAccept = (Button) findViewById(R.id.accept);
bClear = (Button) findViewById(R.id.clear);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
| ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);

bAccept.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listView.setAdapter(null);
// Create Inner Thread Class
Thread background = new Thread(new Runnable() {
public void run() {
DatabaseManager.initializeInstance(new DBHelper(
getApplicationContext()));
SQLiteDatabase dbSqlite = DatabaseManager.getInstance()
.openDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("particulars", edtParticular
.getText().toString().trim());
contentValues.put("qty", edtQty.getText().toString()
.trim());
contentValues.put("price", edtPrice.getText()
.toString().trim());
contentValues.put("date", edtDate.getText().toString()
.trim());
dbSqlite.insert("particular", null, contentValues);
DatabaseManager.getInstance().closeDatabase();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(),
"Successfully inserted",
Toast.LENGTH_SHORT).show();
}
});
}
});
background.start();

List<String> arraylist = new ArrayList<String>();
arraylist.add(edtParticular.getText().toString().trim());
arraylist.add(edtQty.getText().toString().trim());
arraylist.add(edtPrice.getText().toString().trim());
arraylist.add(edtDate.getText().toString().trim());
map.put(i++, arraylist);
listView.setAdapter(new ListViewAdapterHelper(getBaseContext(),
map));
}
});

bClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (map.size() > 0) {
map.clear();
i = 1;
listView.setAdapter(null);
}
}
});
}

@Override
public void onResume() {
super.onResume();
if (map.size() > 0) {
listView.setAdapter(new ListViewAdapterHelper(getBaseContext(), map));
}
}

@Override
public void onPause() {
super.onPause();
listView.setAdapter(null);
}

@Override
public void onDestroy() {
super.onDestroy();
listView.setAdapter(null);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case progress_bar_type:
prgDialog = new ProgressDialog(this);
prgDialog.setMessage("Displaying Usage Statistics...");
prgDialog.setIndeterminate(false);
prgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
prgDialog.setCancelable(true);
prgDialog.show();
return prgDialog;
default:
return null;
}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search_action:
menuItem = item;
menuItem.setActionView(R.layout.search_layout);
menuItem.collapseActionView();
edtSearch = (EditText) item.getActionView().findViewById(
R.id.txt_search);

edtSearch.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_DOWN)
&& (keyCode == KeyEvent.KEYCODE_ENTER)) {
if (!edtSearch.getText().toString().trim().equals("")) {
/*ThreadProcess tp = new ThreadProcess();
tp.execute(edtSearch.getText().toString().trim());*/
}
}
return false;
}
});
break;
default:
break;
}
return true;
}

/* class ThreadProcess extends AsyncTask<String, String, String> {

@Override
protected void onPreExecute() {
* int currentOrientation =
* getResources().getConfiguration().orientation; if
* (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
* setRequestedOrientation
* (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else {
* setRequestedOrientation
* (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
 
showDialog(progress_bar_type);
}

@Override
protected void onPostExecute(String result) {
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

dismissDialog(progress_bar_type);
Intent intent = new Intent(Particular.this, SearchResultsActivity.class);
startActivity(intent);
}

@Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
try {
Thread.sleep(7000);
Map<String, Double> map = new HashMap<String, Double>();
DatabaseManager.initializeInstance(new DBHelper(
getApplicationContext()));
SQLiteDatabase dbSqlite = DatabaseManager.getInstance().openReadDatabase();
//where particulars=? ORDER BY date"
Cursor cursor = dbSqlite.rawQuery("select * from particular where particulars=? ORDER BY date", params);
Log.d("com.example.billtracking", "cursor getCount = "+cursor.getCount());
if (cursor.getCount() > 0) {
cursor.moveToFirst();
do {
String key = cursor.getString(cursor
.getColumnIndex("date"));
Double value = Double.parseDouble(cursor
.getString(cursor.getColumnIndex("qty")));

String[] sDate = key.split("/");
Double qtyTemp;

// Calculate total qty of an item within same month
if (map.containsKey(sDate[1])) {
qtyTemp = map.get(sDate[1]);
map.put(sDate[1], qtyTemp + value);
} else
map.put(sDate[1], value);

} while (cursor.moveToNext());
}
DatabaseManager.getInstance().closeDatabase();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}*/
}

listview_row.xml

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="top"
    android:paddingTop="0dip" 
    android:stretchColumns="*"
    android:shrinkColumns="*">

    <TableRow>
        <TableLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingTop="0dip" >

            <TableRow>

                <TextView
                    android:id="@+id/textParticular"
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:layout_height="wrap_content"
                    android:textColor="#000000"
                    android:layout_gravity="left|top"
                    android:layout_marginLeft="10dip"
                    android:layout_marginTop="2dip"
                    android:gravity="left" />                   

                <TextView
                    android:id="@+id/textQty"
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:textColor="#000000"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|right"
                    android:layout_marginRight="10dip"
                    android:gravity="right"
                    android:layout_marginTop="2dip" />                    
                    
            </TableRow>

            <TableRow>

                <TextView
                    android:id="@+id/textPrice"
                    android:layout_width="wrap_content"
                    android:textColor="#000000"
                    android:layout_weight="1"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom|left"
                    android:layout_marginLeft="10dip"
                    android:layout_marginTop="4dip"
                    android:gravity="left"
                    android:text="" />

                <TextView
                    android:id="@+id/textDate"
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:textColor="#000000"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom|right"
                    android:layout_marginRight="10dip"
                    android:layout_marginTop="4dip"
                    android:gravity="right"
                    android:text="" />
                    
            </TableRow>
        </TableLayout>       
    </TableRow>
</TableLayout>


search_layout.xml

<?xml version="1.0" encoding="utf-8"?>

<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/txt_search"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:textColor="#ffffff"
    android:drawableLeft="@drawable/ic_action_search"
    android:hint="Usage Statistics"
    android:focusableInTouchMode="true"
    >

</EditText>


main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp" >

    <EditText
        android:id="@+id/particular"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/particular" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/qty"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@string/qty" />

        <EditText
            android:id="@+id/price"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/price"     
            android:maxLines="1" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" 
        >

        <EditText
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@string/date"
            android:inputType="date"
            android:maxLines="1" />

        <Button
            android:id="@+id/accept"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@string/accept"
            android:paddingBottom="0dp"/>
        <Button
            android:id="@+id/clear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@string/clear"
            android:paddingBottom="0dp"/>
       
    </LinearLayout>
    <ListView
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        android:layout_weight="1"/>

</LinearLayout>

menu/main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:billtracking="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.billtracking.MainActivity" >

    <item
        android:id="@+id/search_action"
        android:actionViewClass="android.widget.SearchView"
        android:icon="@drawable/ic_action_search"
        android:title="@string/action_search"
        billtracking:showAsAction="collapseActionView|ifRoom"/>
    <item
        android:id="@+id/empty"
        android:icon="@drawable/ic_action_overflow"        
        android:title="@string/overflow_menu"
        billtracking:showAsAction="always">
       <!--  <menu>
            <item
                android:id="@+id/rate"
                android:icon="@drawable/ic_menu_friendslist"
                android:showAsAction="always|withText"
                android:title="List"/>
        </menu> -->
    </item>
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        billtracking:showAsAction="never"/>

</menu>