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>



Wednesday, September 26, 2012

Adding System Call in Android bionic library

Finally after long time gap I am in my blog again. This time I will explore adding system call in bionic libc.

For simplicity sake let me tell about getpid() system call which is already present

Kernel Changes :

1.  kernel/include/linux/syscalls.h
        This header file provides syscall function prototype
eg:   asmlinkage long sys_getpid(void);
return type: long
asmlinkage macro tells the compiler to pass all function arguments on the stack.

2. kernel/kernel/timer.c
        This source file contains actuall function definition

SYSCALL_DEFINE0(getpid)
{
     // Body of getpid() function.
}

3. kernel/arch/arm/include/asm/unistd.h

The system call need to be given a number in kernel that piece of code is done here
eg: #define __NR_getpid         (__NR_SYSCALL_BASE+ 20)

4. kernel/arch/arm/kernel/calls.S

The declared system call need to be exposed in syscall_table that is done here
eg: CALL(sys_getpid)

This completes Kernel part of exposing syscall getpid()


Bionic Changes:

5. bionic/libc/SYSCALLS.TXT

This is the only place getpid need to exposed in userpace, rest all is taken care automatically by gensyscalls.py python script.
The syntax goes likes this
return_type func_name[:syscall_name][:call_id]([parameter_list])  (#syscall_number|stub)

eg: pid_t getpid()  20

gensyscalls.py script automatically creates getpid.S Stub file and placed in 2 different locations as given below
a. bionic/libc/arch-arm/syscalls.mk
     eg: syscall_src += arch-arm/syscalls/getpid.S

b. bionic/libc/arch-arm/syscalls/getpid.S


With both the changes cross-compile kernel and platform binaries so that you can enjoy the syscall interface between userspace and kernel space.

Please do comment if something is missed...


Always brighter side of the world...
-chandu













Tuesday, May 1, 2012

Creating Symbolic Links, Copy files using Android.mk and learn about permission changing inside init.rc

Its been long time I blogged, I learnt few things in Android.mk which I wanted to share with fellow members.

I started working on ICS Codebase where I have requirement to create Symbolic links, copy files/folders as part of prebuilt to /data and /system partitions and change the permissions during boot time via init.rc

Symbolic Links:
when you want to create symbolic link for a binary which is present in /system/bin the below code snippet will help you achieve the task
/system/bin/xyz -> /system/bin/abc

Pre-requisites:
Inside Android.mk create binary for abc which goes inside /system/bin

COMMANDS = xyz
SYMLINKS := $(addprefix $(TARGET_OUT_EXECUTABLES)/,$(COMMANDS))
$(SYMLINKS): ABC_BINARY := abc
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
                   @echo "Symlink: $@ -> $(ABC_BINARY)"
                   @mkdir -p $(dir $@)
                   @rm -rf $@
                   $(hide) ln -sf $(ABC_BINARY) $@
ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)

Explanation:
xyz would be your symbolic link for abc binary. The above code is self explanatory, please ping me if you dont understand.

Note: symlinks can be created inside init.rc also
ex: symlink /system/etc /etc

Copy files/folders:

PRODUCE_COPY_FILES += external/abc_folder/abc.conf:data/etc/abc.conf

The above command copies abc.conf file from external/abc_folder to /data/etc/ location. when you build and flash the binary you can verify the same in the adb shell

Changing Permissions and creating folders as part of system boot:


init.rc is the location which you need to address for achieving this task,

under on post-fs-data trigger inside init.rc
create below mentioned commands which will be reflected during your boot time.

mkdir /data/var
chmod 0755 /data/var






Wednesday, February 15, 2012

Making Android apps as System Apps during factory building

Today I was asked to build an android application which should go into /system/app rather than being 3rd pary app /data/app

I had written below make file which looks pretty similar to Email app which comes by default with the android source code.

I will explain you what exactly some of the tags means in Android.mk

Note: Place your application inside $(Android_root_path)/packages/apps
Your android application might contains below files/folders

Example: if your application name is "xyz"
1. src/
2. res/
3. libs/
4. AndroidManifest.xml
5. assets/
6. default.properties etc...

Place this Android.mk in your application folder has the files placed above and compile entire source code  $(Android_root_path)# make

Output: You will generate apk file out of your application which will go with your /system/apps. Everytime you need not have to install this application like your 3rd party applications.

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

#This tag is must for making it system apps
LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)

#Any aidl files in your application can be added here
LOCAL_SRC_FILES += \
    src/com/android/xyz/services/IxyzServiceCallback.aidl \
    src/com/android/xyz/services/IxyzService.aidl

LOCAL_JAVA_STATIC_LIBRARIES := \

# include the prebuilt static library which is mentioned in
#LOCAL_PREBUILT_STATIC_JAVA_LIBARIES
LOCAL_STATIC_JAVA_LIBRARIES := liblog4j

LOCAL_PACKAGE_NAME := xyz

LOCAL_PROGUARD_FLAGS := -include $(LOCAL_PATH)/proguard.cfg

include $(BUILD_PACKAGE)

include $(CLEAR_VARS)


#include any prebuilt jars you are using in your application which is present in
#libs folder of your package
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := liblog4j:libs/log4j.jar

include $(BUILD_MULTI_PREBUILT)

include $(call all-makefiles-under,$(LOCAL_PATH))

Wednesday, October 19, 2011

Adding User or Group to Android

Today I had a requirement to add a group(GID) to android system.

I found out that android system has hardcoded GID's for few Groups which is defined during the build time.

Step1: vim $(Android_root_folder)/system/core/include/private/android_filesystem_config.h

Add the below line for "lp" group creation

eg: #define AID_LP 3006

static struct android_id_info android_ids[]={
{"lp", AID_LP, },
};

Step2: Build the android source code.

Step3: Test whether group is created on some file eg: chown root.lp <file_name>

Step4: ls -l on the files you chowned, you can see group gets added successfully.


Note: Like linux you cant find /etc/passwd or /etc/group files in case of android. All the group additions are hardcoded.

I am yet to figure out how we can add users to the groups.