Tuesday, October 7, 2014

Android Widget Creation and facebook messenger like Chathead

I recently developed an Android widget which pops up an Facebook messenger like image when clicked. This pop-up is similar to the Facebook messenger. Here is a screenshot of the app.

What did I learn from this app:
* How to create a widget
* How the facebook messenger and Button savior app is implemented

The icon can be dragged by touching within the WindowManager (except the Notification bar on top and SoftKey at bottom if any). Now i can create a bunch of wonderful apps which can run on top of all the apps and the whole UI. Wonderful. :-)





The MainActivity.java looks like this:

package com.app.samplewidget;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
import android.widget.Toast;

public class MainActivity extends AppWidgetProvider {

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        Toast.makeText(context, "onDeleted called",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Intent in = new Intent(context,ChatThread.class);
        PendingIntent pi = PendingIntent.getService(context, 0, in, 0);
        
        final int N = appWidgetIds.length;
        for(int i=0; i<N ; i++){
            int awId = appWidgetIds[i]; 
            RemoteViews v = new RemoteViews(context.getPackageName(), R.layout.widget);
            v.setOnClickPendingIntent(R.id.bwidgetOpen, pi);
            appWidgetManager.updateAppWidget(awId, v);
        }
        
    }
}
The ChatThread.java looks like this:

package com.app.samplewidget;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

public class ChatThread extends Service {

    public static final String TAG = "ChatThread";
    Context c;
    public static boolean status = false;
    private WindowManager windowManager;
    private ImageView chatHead;
    WindowManager.LayoutParams params;

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        chatHead = new ImageView(this);
        chatHead.setImageResource(R.drawable.ic_launcher);

        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        params.gravity = Gravity.TOP | Gravity.LEFT;
        params.x = 0;
        params.y = 100;

        windowManager.addView(chatHead, params);
        chatHead.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    initialX = params.x;
                    initialY = params.y;
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();
                    return true;
                case MotionEvent.ACTION_UP:
                    return true;
                case MotionEvent.ACTION_MOVE:
                    params.x = initialX
                            + (int) (event.getRawX() - initialTouchX);
                    params.y = initialY
                            + (int) (event.getRawY() - initialTouchY);
                    windowManager.updateViewLayout(chatHead, params);
                    return true;
                }
                return false;
            }
        });

    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.i(TAG, "onDestroy Called");
        if (chatHead != null)
            windowManager.removeView(chatHead);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // TODO Auto-generated method stub
        return super.onUnbind(intent);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        if (status) {
            status = false;
            this.stopSelf();
        } else {
            status = true;
        }
        Log.i(TAG, "onStartCommand - " + status);
        return super.onStartCommand(intent, flags, startId);

    }

}


In addition to the above two file, AndroidManifest.xml is also important:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.samplewidget"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="14" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service 
            android:name=".ChatThread">
        </service>`
        
        <receiver android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter >
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_stuff"/>
        </receiver>
    </application>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    
</manifest>




Code is shared on github SampleWidget.

Reference:
Widget Creation Thenewboston Android videos (160-164)
Chathead basics: http://www.piwai.info/chatheads-basics/

Wednesday, September 3, 2014

Adding Timeline to Google Site

I came across a Timeline which can be embedded in the Google site. Check the video here.


Reference: http://timeline.knightlab.com/

I followed the exact steps as per the video. However the timeline was not being displayed in the Google site. On digging further in the issue I found out that Google doesn't allow the http pages in the iFrame.

The solution is to convert the http to https page as follows:


Yeyy.. it works for me...!!! :-)

Sunday, July 13, 2014

Socket Server to transfer Accelerometer Sensor data to PC

Hi Guys,

Recently, I have been trying to get the accelerometer data on PC in real time. Here is how to make it work.

The idea basically is to create a socket server in the Android device and a socket client in local PC to transfer data over wifi. Now lets create a socket server in the Android device which transmits the linear acceleration data.

Create an android Project in Eclipse:
package com.example.myserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {
    String mClientMsg = "";
    Thread myCommsThread = null;
    public static final String TAG = "SocketServer";
    private CommsThread commsThread = null;
    TextView tv;
    PrintWriter out;
    private float ax, ay, az;
    private long timenow = 0, timeprev = 0, timestamp =0 ;

    private SensorManager sm;
    private Sensor sensor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).get(0);
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        sm.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
        this.commsThread = new CommsThread();
        this.myCommsThread = new Thread(this.commsThread);
        this.myCommsThread.start();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        sm.unregisterListener(this);
        if (commsThread != null) {
            commsThread.stopComms();
        }
    }    

    Handler myHandler = new Handler(){
        public void handleMessage(Message msg){
            TextView status = (TextView) findViewById(R.id.textView3);
            status.setText("Status: Streaming Now!");
        }
    };

    class CommsThread implements Runnable {
        private volatile boolean stopFlag = false;
        private ServerSocket ss = null;
        private static final int SERVERPORT = 6000;
        public void run() {
            Socket s = null;
            try {
                ss = new ServerSocket(SERVERPORT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                s = ss.accept();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            myHandler.sendEmptyMessage(0);
            
            while(!stopFlag){
                try {
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
                    out.printf("*#%3.2f#%3.2f#%3.2f#%2d#*\n",ax,ay,az,(int)timestamp );
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void stopComms() {
            // TODO Auto-generated method stub
            this.stopFlag = true;
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }         
        }
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub       
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        ax = event.values[0];
        ay = event.values[1];
        az = event.values[2];
        timenow = event.timestamp;
        timestamp = (timenow - timeprev)/1000000;
        refreshDisplay();
    }

    private void refreshDisplay() {
        // TODO Auto-generated method stub
        String output = String.format("time: %d -- x:%03.2f | Y:%03.2f | Z:%03.2f", timestamp, ax,ay,az);
        timeprev = timenow;
        tv.setText(output);
    }
}


In the AndroidManifest.xml add the following lines:
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.INTERNET"/>
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.ACCESS_NETWORK_STATE"/>

Now install the socket server on the Android device and launch the program. The server is up and running. It now waits for the client to connect and then transmit the real-time linear acceleration data to the client.

Now lets write a simple client to read the data on Ubuntu PC.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256] = "\0";
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    //printf("Please enter the message: ");
    bzero(buffer,256);

    //fgets(buffer,255,stdin);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    while(1){
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
            error("ERROR reading from socket");
        printf("%s\n",buffer);
    }
    close(sockfd);
    return 0;
}



compile the above code using
gcc -o socketclient client.c
To connect to the server over wifi network:
./socketclient 192.168.1.2 6000
to connect to the server via USB cable:
adb forward tcp:1234 tcp:6000
./socketclient localhost 1234
Now the data will be streaming on the Ubuntu PC. I'll try to plot this data in my next blog.

References:
C socket programming:
1. http://www.linuxhowtos.org/C_C++/socket.htm 
USB port forwarding:
2. http://www.anothem.net/archives/2010/02/15/communicating-over-the-usb-cable/
Android Socket Programming:
3. http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
4. http://www.edumobile.org/android/android-development/socket-programming/ 

Sunday, July 6, 2014

adb port forwarding via USB



Here is a way to create a socket connection between Android phone and Ubuntu 14.04 desktop.

Pre-requites:
1. Android Terminal Emulator App (On Android Device)
2. Android SDK installed on host computer

create a socket on the device using nc command:
jai@jai-server:~$ adb shell
shell@mako:/ $ nc -l -p 1234
---//
The above command could be executed on the terminal Emulator as follows:



On the host machine:
jai@jai-server:~$ adb forward tcp:1235 tcp:1234
jai@jai-server:~$ nc localhost 1235
--//
Connection is established and you are good to go. Start writing on any of the device. It should be reflected on other device.

Reference: http://bharathisubramanian.wordpress.com/2012/03/10/android-socket-communication-thru-adb/