Saturday, 18 May 2013

Android Screen Rotation : handling Activity Runtime orientation change

Handling orientation change in android is bit interesting topic to explore. on change of orientation your Android device's width changes to height and vice versa. It make developer to force some changes in layout for better user expeperience. We can handle user interface while changing orientation using two way. Lets discuss best possible way to handle activity orientation change.

1) Avoid recreating activity using android:configChanges="orientation|screenSize" and android:screenOrientation="user". Its not easy to save state all the process running and resuming them. It may force you write lots of code. If Application structure is complex and User Interface is similar in all orientation then using this way is prodigy. Even thought this way give you event of changing orientation in onConfigurationChanged(Configuration newConfig), but it add overhead to change layouts.

Tip1 : try to minimize the padding and margin to minimize the impact of screen size.
Tip 2: Use Relative Layout

Pros : Avoiding huge among of code if process are in enough numberCons : Using this way in multipane layout is not possible. Its shows the bad user experience.


2) Handle recreating activity and assign fresh resource on base of orientation. Attribute android:screenOrientation="user" force activity to recreating to load the new resource on the base of current screen orientation. Remove android:configChanges="orientation|screenSize" in this case
Tip 1: Create two layout folder inside resource layout for portrait and layout-land for landscape
Tip 2: Android provide a way to save current activity state while changing application orientation. Save your data inside onSaveInstanceState(Bundle outState);


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("progress", 10);
        outState.putBoolean("isRecreated", true);
        super.onSaveInstanceState(outState);
    }

Tip 3: Now check in onCreate(Bundle savedInstanceState), is it creating or recreating. Restore the process and thread in case recreating

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int progress = 0;
        boolean isRecreated = false;
        if (savedInstanceState != null) {
            // Restore Process and Thread
            progress = savedInstanceState.getInt("progress");
            isRecreated = savedInstanceState.getBoolean("isRecreated");
        } else {
            // Start Fresh Process and Thread
        }

        Log.e(String.valueOf(progress), String.valueOf(isRecreated));
    }

Pros : Code Overhead
Cons : Better user exeperience. easy to handle Multipane layout

Sunday, 12 May 2013

Android Download Manager Example , Controlling download in android application

Android provide download manager to download different kind of data. Download Manager make developer life much easier. Handling download becomes very easy.
DownloadManager class support only after API 9

Implementing DownloadManager is easy. Lets have a look how we can start downloading using DownloadManager  in android application

    /**
     * Start Download
     */
    public void startDownload() {
        DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        Request mRqRequest = new Request(
                Uri.parse("http://androidtrainningcenter.blogspot.in/2012/11/android-webview-loading-custom-html-and.html"));
        mRqRequest.setDescription("This is Test File");
//        mRqRequest.setDestinationUri(Uri.parse("give your local path"));
        long idDownLoad=mManager.enqueue(mRqRequest);
    }



Request mRqRequest = new Request(
Uri.parse("http://androidtrainningcenter.blogspot.in/2012/11/android-webview-loading-custom-html-and.html")); allow you request from DownloadManager to start downloading. You can set your custom Description using Request class.

Handling Download : Stopping, Removing and opening download file

When you start download request, it return you one id. Application can handle download using that id

long idDownLoad=mManager.enqueue(mRqRequest);
mManager.remove(idDownLoad);
try {
mManager.openDownloadedFile(idDownLoad);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

Catching Action Using BroadCastReceiver And Notify User

Take on BroadCastReceiver and Register it. You will ACTION_DOWNLOAD_COMPLETE if application register this Intent-Filter.

    DownLoadComplte mDownload;

    @Override
    protected void onStart() {
        super.onStart();
        mDownload = new DownLoadComplte();
        registerReceiver(mDownload, new IntentFilter(
                DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mDownload);
    }

    private class DownLoadComplte extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equalsIgnoreCase(
                    DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Toast.makeText(context, "Download Complte", Toast.LENGTH_LONG)
                        .show();
            }
        }
    }

Viewing your downloaded File


public void viewDownload() {
Intent mView = new Intent();
mView.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(mView);
}

Saturday, 4 May 2013

How to make Android service unstoppable and run it continuously

Android service runs in different mode with help of flag e.g START_CONTINUATION_MASK, START_NOT_STICKY. It enable to control the behavior of Android service life. But service will work until user allow it work. If he/she stops it, it will destroy automatically. More than often, we required it to run unstoppable  If in case user stop, re-instance the old service instance.
For some people, it may malware but sometimes we have to full filled client requirement and that's all our purpose is.

Case when your service can be stopped



  • User stop it forcefully
  • Low Memory situation
  • Device restarted


Handling first two case


When ever we stop service forcefully (or os kill it), it will call onDestory() method. First concept is to use one receiver and send one broadcast whenever service destroy. And restarted service again.

Third case if device is restarted then already we had onBootCompleted action for receiver to catch

Lets go steps by Step to make our Android Service unstoppable

Step 1) Create one Android BroadCastReciever and register it for two action


Manifest

        <service android:name="ServiceTest" >
        </service>

        <receiver android:name="ReceiverCall" >
            <intent-filter>
                <action android:name="com.android.techtrainner" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

com.android.techtrainner is the custom action. BroadCastReceiver Class contain code to restart service again

public class ReceiverCall extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("Service Stops", "Ohhhhhhh");
        context.startService(new Intent(context, ServiceTest.class));;
    }

}


Step 2) Create Android service class , do some task there (I have taken one Timer to print Log) and in onDestory()


    public void onDestroy() {
        try {
            mTimer.cancel();
            timerTask.cancel();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Intent intent = new Intent("com.android.techtrainner");
        intent.putExtra("yourvalue", "torestore");
        sendBroadcast(intent);
    }

Run your application and go to setting, See running service, you will TestService. Try to close it , ohhhhhh it will not close.

DownloadSource Application



Friday, 26 April 2013

Implementing Search functionality inside Android ListView.

Listing in android contains many features that make ListView a powerful tool. Android developer are very much aware from recycling of View inside BaseAdapter. This tutorial address the issue(or say requirement) of searching inside a ListView.
Concept roam around performing search operation on Array and redraw the ListView.
Let Do this step wise

Step 1) Create one simple User interface to handle requirement search

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <RelativeLayout
        android:id="@+id/top"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        android:background="@drawable/search_input1" >

        <Button
            android:id="@+id/btnSearch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="2dp"
            android:background="@drawable/cancel_search" />

        <Button
            android:id="@+id/btnLeft"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="2dp"
            android:background="@drawable/icon_search" />

        <EditText
            android:id="@+id/edSearch"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@id/btnSearch"
            android:layout_toRightOf="@id/btnLeft"
            android:background="@null"
            android:hint="Search"
            android:imeOptions="actionSearch"
            android:singleLine="true" />
    </RelativeLayout>

    <ListView
        android:id="@+id/mListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/top"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:cacheColorHint="@android:color/transparent"
        android:divider="@android:color/white"
        android:dividerHeight="2dp" >
    </ListView>

</RelativeLayout>

Step 2) Create One BaseAdapter to bind Data inside a ListView

package com.testsearching;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MySimpleSearchAdapter extends BaseAdapter {

    private ArrayList<String> mData = new ArrayList<String>();
    private LayoutInflater mInflater;

    public MySimpleSearchAdapter(Activity activity) {
        mInflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void addItem(String item) {
        mData.add(item);
        notifyDataSetChanged();
    }

    public int getCount() {
        return mData.size();
    }

    public String getItem(int position) {
        return mData.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item_one, null);
            holder.textView = (TextView) convertView.findViewById(R.id.text);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        String str = mData.get(position);
        holder.textView.setText(str);
        return convertView;
    }

    public class ViewHolder {
        public TextView textView;
    }

}


Step 3) Now write the Search Logic inside your activity

package com.testsearching;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

public class SearchFunctionality extends Activity implements OnClickListener,
        OnEditorActionListener, OnItemClickListener {
    ListView mListView;
    MySimpleSearchAdapter mAdapter;
    Button btnSearch, btnLeft;
    EditText mtxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        mListView = (ListView) findViewById(R.id.mListView);
        mAdapter = new MySimpleSearchAdapter(this);
        btnSearch = (Button) findViewById(R.id.btnSearch);
        btnLeft = (Button) findViewById(R.id.btnLeft);
        mtxt = (EditText) findViewById(R.id.edSearch);
        mtxt.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {

            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (0 != mtxt.getText().length()) {
                    String spnId = mtxt.getText().toString();
                    setSearchResult(spnId);
                } else {
                    setData();
                }
            }
        });
        btnLeft.setOnClickListener(this);
        btnSearch.setOnClickListener(this);
        setData();
    }

    ArrayList<String> mAllData;

    String[] str = { "Hit me Hard", "GIJ, Rise Of Cobra", "Troy",
            "A walk To remember", "DDLJ", "Tom Peter Nmae", "David Miller",
            "Kings Eleven Punjab", "Kolkata Knight Rider", "Rest of Piece" };

    public void setData() {
        mAllData = new ArrayList<String>();
        mAdapter = new MySimpleSearchAdapter(this);
        for (int i = 0; i < str.length; i++) {
            mAdapter.addItem(str[i]);
            mAllData.add(str[i]);
        }
        mListView.setOnItemClickListener(this);
        mListView.setAdapter(mAdapter);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btnSearch:
            mtxt.setText("");
            setData();
            break;
        case R.id.btnLeft:

            break;
        }
    }

    public void setSearchResult(String str) {
        mAdapter = new MySimpleSearchAdapter(this);
        for (String temp : mAllData) {
            if (temp.toLowerCase().contains(str.toLowerCase())) {
                mAdapter.addItem(temp);
            }
        }
        mListView.setAdapter(mAdapter);
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        return false;
    }

    @Override
    public void onBackPressed() {
        setResult(Activity.RESULT_CANCELED);
        finish();
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int position,
            long arg3) {
        String str = mAdapter.getItem(position);
        Toast.makeText(this, str, Toast.LENGTH_LONG).show();
    }
}

See Above code output in form of ScreenShot






Download Source Of Application

Wednesday, 24 April 2013

Android Reverse Geo Coding : Getting Human Readable address from latitude and longitude in android

We can show any address on map using latitude and longitude. But showing number rather than any useful information make no sense for any user. Reverse Geo Coding is process to convert latitude and longitude into one readable address in the form of String

     public String getAddress(Activity acLocal) {
 String address="";
       Geocoder geocoder;
        List<Address> addresses = null;
        geocoder = new Geocoder(_acLocal, Locale.getDefault());
        try {
            addresses = geocoder.getFromLocation(lat, longi, 1);

            String address = addresses.get(0).getAddressLine(0);
            String city = addresses.get(0).getAddressLine(1);
            String country = addresses.get(0).getCountryName();
            address = Html.fromHtml(
                    address + "<br>" + city + "<br>" + country).toString();
        } catch (Exception e) {
            e.printStackTrace();
            address = Html.fromHtml("<br>&nbsp;Unable to get any address.")
                    .toString();
        }
       return address;
} 

It will give you available address for respective latitude and longitude. Throws an exception if not able to convert into address

Saturday, 20 April 2013

Removing status bar notification from android application

Status bar notification used to show some important alert from in or outside the application in android. See Creating Simple notification is simple. This tutorial address the issue of removing notification from status bar while you are inside the application. Its easy to remove when you get involve with notification (like touch) but we will learn today how can we remove them without touch or involving with them Main concept run around notification id. You can remove any notification from anywhere if you notification id. So we need one data base to store id of notification while we generate this and later on remove notification


Steps 


Step 1) Required a simple user Interface with one button to generate notification and one to remove it. Create remove.xml 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NotificationRemove" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="14dp"
        android:text="Send Notification" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/button1"
        android:layout_below="@+id/button1"
        android:layout_marginTop="79dp"
        android:text="Clear Notification" />

</RelativeLayout>

Notification
                                             
Step 2) Create a simple data base class DataBase.java to store the notification id

package com.notificationremoval;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBase extends SQLiteOpenHelper {

    public static final String tName = "tName";
    public static final String mNotiID = "mNotiID";

    public DataBase(Context context) {
        super(context, "temp.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String mNotifi = "create table noti(noti_id integer not null);";
        db.execSQL(mNotifi);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

}


Step 3) Now create one Activity that Handle removal of notification


package com.notificationremoval;

import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;

public class NotificationRemove extends Activity implements OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.remove);
        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
    }

    private void createAndGenerateNotifcation() {
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
                this).setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle("Notification TItile").setContentText("Body");
        mBuilder.setAutoCancel(true);
        Intent resultIntent = new Intent();
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addNextIntent(resultIntent);
        int noti_id = (int) System.currentTimeMillis();
        insertNotifi(noti_id);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
                PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(resultPendingIntent);
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(noti_id, mBuilder.build());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            createAndGenerateNotifcation();
            break;
        case R.id.button2:
            RemoveAllNotification();
            break;
        }
    }

    public void RemoveAllNotification() {
        DataBase mBase = new DataBase(this);
        Cursor cur = mBase.getWritableDatabase().query("noti", null, null,
                null, null, null, null, null);
        cur.moveToFirst();
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        do {
            int id = cur.getInt(0);
            mNotificationManager.cancel(id);
        } while (cur.moveToNext());
        try {
            cur.close();
        } catch (Exception e) {
        }
    }

    public void insertNotifi(int id) {
        DataBase mBase = new DataBase(this);
        ContentValues cVales = new ContentValues();
        cVales.put("noti_id", id);
        SQLiteDatabase db = mBase.getWritableDatabase();
        long i = db.insert("noti", null, cVales);
        Log.i("Insert", String.valueOf(i));
        try {
            db.close();
        } catch (Exception e) {
        }
    }

}


Enjoy and keep commenting
Tech Trainner
There was an error in this gadget