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/