Android Wear: How to send data from Android Wear to Mobile Device ?

Android Wear or Let say Smart Watches are new and trending technology. Android apps are updating and they all comes with Android wear support. if you want it is in your app you can find simple Helloworld wear app tutorials easily on Google. but what if you want to explore it more let say you want to display a List view in android wear or get some kind of input from android wear app. so these tutorial is for you. In this tutorial i have created simple list in android wear app in which user click on list item and an app in mobile device gets open. for example you want to display list of songs in android wear app and on the click of that you want to change song in your device or let say you can display to do list on android wear and on the click of list item you can open to do item details inside your mobile app. this list can be infinite and its totally depends on you and apps in android.

Android Wear sample


Steps

Step - 1
First of let i start with adding a android wear module in development. If you have already added android wear module in you app you can skip this step. To add right click on your app root folder (name of your app folder) and go to New > Module. Select Android Wear Module and click on next. Give same name in Application name (Mobile app name) and in Module Name write wear. so you can differentiate them. Make sure you give same package name also. because when you send some data through mobile app or wear app MessageApi will check for the same package and pass that data. so if you give different name you won't be able to send or receive data. On the next screen select Blank Wear Activity and on the next screen give proper name to it.

Note - Above steps are for Android studio wizard. Sorry for eclipse developers (Please migrate to AS)

Step - 2
So our android wear module is added. I hope you have no issue in above steps. in the main activity or launcher activity i have created a List (basically list of my tutorials). For learning purpose you can start with same and after that you can change it is as you want. so put below code in appropriate layout files.

wear/layout/activity_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub 
   xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/watch_view_stub"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#e4e5e5"
    app:rectLayout="@layout/rect_activity_list"
    app:roundLayout="@layout/round_activity_list"
    tools:context=".ListActivity"
    tools:deviceIds="wear">

</android.support.wearable.view.WatchViewStub>


wear/layout/rect_activity_list.xml & wear/layout/round_activity_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout
    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"
    android:fitsSystemWindows="true"
    tools:context=".ListActivity"
    tools:deviceIds="wear_round">

        <android.support.wearable.view.WearableListView
            android:id="@+id/listView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:overScrollMode="never" />

        <TextView
            android:id="@+id/tv_header"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_gravity="top|center"
            android:textSize="30sp"
            android:layout_marginTop="10dp"
            android:textColor="#52bf90"
            android:fontFamily="sans-serif-light"
            android:text="@string/app_name"/>

</android.support.wearable.view.BoxInsetLayout>



Step - 3
List layout is done in Step -2. now let's jump to coding part where i have initialize WearableListView with Array adapter. Using GoogleApiClient i have checked if there is a connection to a android wear from an app or not. we can get all connected nodes or devices using Wearable.NodeApi.getConnectedNodes method. check below code and make sure you understand or go through it for one time so you know what is actually going on. otherwise you will get confused.

wear/java/ListActivity.java
package com.androprogrammer.tutorials;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.wearable.view.WatchViewStub;
import android.support.wearable.view.WearableListView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;

import java.util.ArrayList;

public class ListActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,WearableListView.ClickListener {

    private WearableListView mListView;

    private ArrayList<String> listItems;

    Node mNode; // the connected device to send the message to
    GoogleApiClient mGoogleApiClient;
    private boolean mResolvingError=false;

    public static String SERVICE_CALLED_WEAR = "WearListClicked";
    public static String TAG = "WearListActivity";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);

        //Connect the GoogleApiClient
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        initializeListItems();
        final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
        stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
            @Override
            public void onLayoutInflated(WatchViewStub stub) {
                mListView = (WearableListView) stub.findViewById(R.id.listView1);

                mListView.setAdapter(new MyAdapter(ListActivity.this, listItems));
                mListView.setClickListener(ListActivity.this);

            }
        });
    }

    private void initializeListItems() {

        listItems = new ArrayList<>();
        listItems.add("Async File Read");
        listItems.add("Battery Status");
        listItems.add("Volume Setting");
        listItems.add("Frame Animation");
        listItems.add("Video Player");
        listItems.add("Circular Image View");
        listItems.add("Track User Location");
        listItems.add("Take Image");
        listItems.add("Image Grid View");
        listItems.add("Image Switcher");
        listItems.add("Tabs with Toolbar");
        listItems.add("Icon Tabs with Toolbar");
        listItems.add("Push Notification");


    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mResolvingError) {
            mGoogleApiClient.connect();
        }
    }

    /**
     * Resolve the node = the connected device to send the message to
     */
    private void resolveNode() {

        Wearable.NodeApi.getConnectedNodes(mGoogleApiClient)
                .setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
                    @Override
                    public void onResult(NodeApi.GetConnectedNodesResult nodes) {
                        for (Node node : nodes.getNodes()) {
                    mNode = node;
                }
            }
        });
    }

    @Override
    public void onConnected(Bundle bundle) {
        resolveNode();
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

    /**
     * Send message to mobile handheld
     */
    private void sendMessage(String Key) {

        if (mNode != null && mGoogleApiClient!= null && mGoogleApiClient.isConnected()) {
            Log.d(TAG, "-- " + mGoogleApiClient.isConnected());
            Wearable.MessageApi.sendMessage(
                    mGoogleApiClient, mNode.getId(), SERVICE_CALLED_WEAR + "--" + Key, null).setResultCallback(

                    new ResultCallback<MessageApi.SendMessageResult>() {
                        @Override
                        public void onResult(MessageApi.SendMessageResult sendMessageResult) {

                            if (!sendMessageResult.getStatus().isSuccess()) {
                                Log.e(TAG, "Failed to send message with status code: "
                                        + sendMessageResult.getStatus().getStatusCode());
                            }
                        }
                    }
            );
        }

    }

    @Override
    public void onClick(WearableListView.ViewHolder viewHolder) {
        TextView view = (TextView) viewHolder.itemView.findViewById(R.id.row_tv_name);
        String Key = view.getText().toString();
        Log.d(TAG, Key);
        sendMessage(Key);
    }

    @Override
    public void onTopEmptyRegionClick() {
        Toast.makeText(this, "You tapped on Top empty area", Toast.LENGTH_SHORT).show();
    }


    private class MyAdapter extends WearableListView.Adapter {
        private final LayoutInflater mInflater;
        private ArrayList<String> data;

        private MyAdapter(Context context, ArrayList<String> listItems) {
            mInflater = LayoutInflater.from(context);
            data = listItems;
        }

        @Override
        public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new WearableListView.ViewHolder(
                    mInflater.inflate(R.layout.row_wear_list, null));
        }

        @Override
        public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
            TextView view = (TextView) holder.itemView.findViewById(R.id.row_tv_name);
            view.setText(data.get(position));
            holder.itemView.setTag(position);
        }

        @Override
        public int getItemCount() {
            return data.size();
        }
    }
}


wear/layout/row_wear_list.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="80dp"
    android:orientation="horizontal"
    android:padding="8dp"
    android:gravity="center">

    <TextView
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Medium Text"
        android:textStyle="bold"
        android:ellipsize="end"
        android:maxEms="15"
        android:padding="10dp"
        android:ems="15"
        android:background="@android:color/white"
        android:textColor="@android:color/black"
        android:fontFamily="sans-serif-condensed-light"
        android:gravity="center"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:textSize="16sp"
        android:id="@+id/row_tv_name" />

</LinearLayout>

wear/AndroidManifest.xml
<meta-data android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

Please add above lines of code in manifest file of wear module. because we are using google play service to communicate. otherwise it will give error.

Step - 4
Now android wear module is ready. you can run it separately on emulator and check it. now we require a bridge which can pass android wear message to android mobile app. so when user click on list item in android wear a service get some sort of message and on the basis of that message we start appropriate activity. Using WearableListenerService we will create service which will do same for our app.

mobile/java/WearListCallListenerService.java
package com.androprogrammer.tutorials.services;

import android.content.Intent;
import android.util.Log;

import com.androprogrammer.tutorials.activities.Listactivity;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;

/**
 * Created by Wasim on 08-05-2015.
 */
public class WearListCallListenerService extends WearableListenerService {

    public static String SERVICE_CALLED_WEAR = "WearListClicked";


    @Override
    public void onMessageReceived(MessageEvent messageEvent) {
        super.onMessageReceived(messageEvent);

        String event = messageEvent.getPath();

        Log.d("Listclicked", event);

        String [] message = event.split("--");

        if (message[0].equals(SERVICE_CALLED_WEAR)) {

            startActivity(new Intent((Intent) Listactivity.getInstance().tutorials.get(message[1]))
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
        }
    }
}


Step - 5
In Mobile app put below code to register your service.

mobile/AndroidManifest.xml
<service android:name=".services.WearListCallListenerService">
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
            </intent-filter>
        </service>

That's it...
Now run wear module in android wear emulator and mobile module in device. make sure you are connected. I hope you understand the full tutorial. you can get full source code from my Github repo. if you find it helpful please share this tutorial.

Keep coding...

Material Design: Tabs with Toolbar

Action bar is deprecated in android 5.0 known as Android Lollipop and new toolbar is introduced by Android(Google) developers. Toolbar is also a simple view like others but to enhance UI and UX of apps they have introduced it with some enhancement. In Android 5.0 Tabs are also recreated with some enhancement. because toolbar doesn't support direct tabs like actionbar. In action bar you can add tabs using method called addTab() but with tabs you can't use same method. now you even don't require Tab host or Tab widget to add tabs. so how ?

Well go through full tutorial and you can implement nice tabs like google play, google music and many other apps have. Tabs are mostly used to display two different views in same page or activity. most of the developer load different fragments in tabs so they can have control over tabs and views associated with it. Tabs can be of two types.

1. Tabs with label
2. Tabs with icons




Steps

Step - 1
Create activity which holds tabs inside view part and give proper name to it. In this tutorial it is TabViewDemo Activity. To create tabs first we have to create SlidingTabLayout and SlidingTabStripe custom view. So put below both class code in your project.
Get it from github

SlidingTabLayout.java
SlidingTabStripe.java

Step - 2 a)
Now put below code in activity which you have created in Step - 1. this activity is Demo activity which will display tabs with labels(type -1). Below you can find layout and class file code put the code inside your project.

activity_tabview_demo.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"
    android:paddingTop="?attr/actionBarSize"
    tools:context="com.androprogrammer.tutorials.samples.TabViewDemo">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.androprogrammer.tutorials.customviews.SlidingTabLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tab_layout_header"
            android:elevation="8dp"/>

        <android.support.v4.view.ViewPager
            android:id="@+id/tab_layout_container"
            android:layout_width="match_parent"
            android:layout_height="0px"
            android:layout_weight="1"
            android:background="@color/activity_bg" />

    </LinearLayout>

</RelativeLayout>



TabViewDemo.java
package com.androprogrammer.tutorials.samples;

import android.app.ActionBar;

import android.app.FragmentTransaction;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.transition.Slide;
import android.transition.Transition;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;


import com.androprogrammer.tutorials.R;
import com.androprogrammer.tutorials.activities.Baseactivity;
import com.androprogrammer.tutorials.adapters.TabFragmentAdapter;
import com.androprogrammer.tutorials.customviews.SlidingTabLayout;
import com.androprogrammer.tutorials.fragments.FragmentOne;
import com.androprogrammer.tutorials.fragments.FragmentThree;
import com.androprogrammer.tutorials.fragments.FragmentTwo;

import java.util.ArrayList;

public class TabViewDemo extends Baseactivity implements ActionBar.TabListener {

    protected View view;
    protected SlidingTabLayout tabs_header;
    protected android.support.v4.view.ViewPager mPager;
    protected ArrayList<fragment> fragments;
    protected TabFragmentAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);

            //set the transition
            Transition ts = new Slide();
            ts.setDuration(3000);
            getWindow().setEnterTransition(ts);
            getWindow().setExitTransition(ts);

        }

        super.onCreate(savedInstanceState);

        setReference();

        setToolbarSubTittle(this.getClass().getSimpleName());

        setToolbarElevation(0);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        fragments.add(new FragmentOne());
        fragments.add(new FragmentTwo());
        fragments.add(new FragmentThree());

        String[] titles = {"One", "Two", "Three"};

        mAdapter = new TabFragmentAdapter(getSupportFragmentManager(), fragments, titles);

        mPager.setAdapter(mAdapter);

        tabs_header.setBackgroundColor(getResources().getColor(R.color.primary));
        tabs_header.setTitleColor(Color.WHITE);
        tabs_header.setFittingChildren(true);
        tabs_header.setTabType(SlidingTabLayout.TabType.TEXT);
        tabs_header.setViewPager(mPager);
    }

    @Override
    public void setReference() {

        view = LayoutInflater.from(this).inflate(R.layout.activity_tabview_demo,container);

        tabs_header = (SlidingTabLayout) view.findViewById(R.id.tab_layout_header);
        mPager = (android.support.v4.view.ViewPager) view.findViewById(R.id.tab_layout_container);
        fragments = new ArrayList<fragment>();

        SetTabSelector();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                finish();
                break;
        }

        return super.onOptionsItemSelected(item);
    }

    private void SetTabSelector()
    {
        tabs_header.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position)
            {
                int ColorId = 0;

                switch (position)
                {
                    case 0:
                        ColorId = Color.WHITE;
                        break;

                    case 1:
                        ColorId = Color.MAGENTA;
                        break;
                    case 2:
                        ColorId = Color.RED;
                        break;
                }

                return ColorId;

            }

            @Override
            public int getDividerColor(int position) {
                return 0;
            }
        });

    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        mPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }
}


Step - 2 b)
This is second sub part of tutorial. if you want to create tabs with icons(type -2) then put below code for tabs with simple text put above code in your activity. to create tabs with icon you have to give name to images like this, ic_one, ic_two etc. because i have fetched images from drawable using tab title. check below code.

private int getResourceIdByName(String resourceName) {
        // get images from mipmap folder
        return getResources().getIdentifier(resourceName, "mipmap", getContext().getPackageName());
    }

if your project consist old drawable pattern then replace mipmap with drawable in SlidingTabLayout file.

ImageTabViewDemo.java
package com.androprogrammer.tutorials.samples;

import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.transition.Slide;
import android.transition.Transition;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;

import com.androprogrammer.tutorials.R;
import com.androprogrammer.tutorials.activities.Baseactivity;
import com.androprogrammer.tutorials.adapters.TabFragmentAdapter;
import com.androprogrammer.tutorials.customviews.SlidingTabLayout;
import com.androprogrammer.tutorials.fragments.FragmentOne;
import com.androprogrammer.tutorials.fragments.FragmentThree;
import com.androprogrammer.tutorials.fragments.FragmentTwo;

import java.util.ArrayList;

public class ImageTabViewDemo extends Baseactivity implements ActionBar.TabListener {

    protected View view;
    protected SlidingTabLayout tabs_header;
    protected android.support.v4.view.ViewPager mPager;
    protected ArrayList<fragment> fragments;
    protected TabFragmentAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);

            //set the transition
            Transition ts = new Slide();
            ts.setDuration(3000);
            getWindow().setEnterTransition(ts);
            getWindow().setExitTransition(ts);


        }

        super.onCreate(savedInstanceState);

        setReference();

        setToolbarSubTittle(this.getClass().getSimpleName());

        setToolbarElevation(0);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        fragments.add(new FragmentOne());
        fragments.add(new FragmentTwo());
        fragments.add(new FragmentThree());

        String[] titles = {"one", "two", "three"};

        mAdapter = new TabFragmentAdapter(getSupportFragmentManager(), fragments, titles);

        mPager.setAdapter(mAdapter);

        tabs_header.setBackgroundColor(getResources().getColor(R.color.primary));
        tabs_header.setTitleColor(Color.WHITE);
        tabs_header.setFittingChildren(true);
        tabs_header.setTabType(SlidingTabLayout.TabType.ICON);
        tabs_header.setViewPager(mPager);
    }

    @Override
    public void setReference() {

        view = LayoutInflater.from(this).inflate(R.layout.activity_tabview_demo,container);

        tabs_header = (SlidingTabLayout) view.findViewById(R.id.tab_layout_header);
        mPager = (android.support.v4.view.ViewPager) view.findViewById(R.id.tab_layout_container);
        fragments = new ArrayList<fragment>();

        SetTabSelector();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                finish();
                break;
        }

        return super.onOptionsItemSelected(item);
    }

    private void SetTabSelector()
    {
        tabs_header.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position)
            {
                int ColorId = 0;

                switch (position)
                {
                    case 0:
                        ColorId = Color.WHITE;
                        break;

                    case 1:
                        ColorId = Color.MAGENTA;
                        break;
                    case 2:
                        ColorId = Color.RED;
                        break;
                }

                return ColorId;

            }

            @Override
            public int getDividerColor(int position) {
                return 0;
            }
        });

    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
        mPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

    }
}



Resources of my project is available at Github so please get images from there. to load three different views i created adapter which extends FragmentPagerAdapter class. below is code of adapter of view pager.

TabFragmentAdapter.java
package com.androprogrammer.tutorials.adapters;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import java.util.ArrayList;

/**
 * Created by Wasim on 28-04-2015.
 */
public class TabFragmentAdapter extends FragmentPagerAdapter {

    private ArrayList<Fragment> fragments;
    private String[] titles;

    public TabFragmentAdapter(FragmentManager fm, ArrayList <Fragment> fragments, String [] title) {
        super(fm);
        this.fragments = fragments;
        this.titles = title;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }

    @Override
    public int getItemPosition(Object object) {
        return super.getItemPosition(object);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles[position];
    }
}


Step - 3
In this tutorial i have even used three fragments to load on three different tabs.the fragments have no logic or code so i don't put that code here. you can find code from here.

That's it. I hope you its clear to you. now run your app. hope it will work fine. if you have any query
or have problem in code implementation write it in below comment box.

Keep coding...

Track user location in android

In android you can get user's latitude and longitude using two different providers.
  1. Using Network
  2. Using GPS
Using Location Listener interface you can get perfect location. but there is no method which actually tells you which provider is best so its good practice to use both. Network provide lat long with good accuracy so i have used it as first option and after that gps.
This tutorial is comprise of get user location and also display it in map. so if you want both the thing go through full tutorial or if you want only users latitude and longitude then skip step 2. which is actually about getting Google map key and setup it in manifest file.



gps in android application, androprogrammer.com


Steps 

Step - 1 : First of all we will create Location listener which actually gives us user location. It is service class which runs in background and give us data on the basis of location change. you can get user location every seconds but it will increase app crash chances so it is better to define time interval and distance interval. i have used 1 min as time interval and 20 meter distance interval so my app won't make call for location each and every seconds. so now create a new class file and put below code inside it.

GetUserLocation.java 

package com.androprogrammer.tutorials.services;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

/**
 * Created by Wasim on 21-03-2015.
 */
public class GetUserLocation extends Service implements LocationListener
{
    private Context context;

    private static final String TAG = "GPSGetUserLocation";

    // The maximum time that should pass before the user gets a location update.
    private static final long DEFAULT_DURATION = 1000 * 60 * 1; // 1 min

    // The default search radius when searching for places nearby.
    private static final long DEFAULT_RADIUS = 20; // 20 meters

    private LocationManager mLocationManager = null;

    private double latitude;
    private double longitude;

    // flag for GPS status
    //private boolean isGPSEnabled = false;

    // flag for network status
    //private boolean isNetworkEnabled = false;


    private Location location; // location values


    public GetUserLocation(Context context, boolean isGPSEnabled, boolean isNetworkEnabled)
    {
        this.context = context;
        getUserLocation(isGPSEnabled, isNetworkEnabled);
    }


    public GetUserLocation() {
    }

    public Location getUserLocation(boolean isGPSEnabled, boolean isNetworkEnabled)
    {
        try {

            if (mLocationManager == null)
            {
                mLocationManager = (LocationManager) context
                        .getSystemService(Context.LOCATION_SERVICE);
            }

                // First get location from Network Provider
                if (isNetworkEnabled)
                {
                    mLocationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            DEFAULT_DURATION,
                            DEFAULT_RADIUS, this);

                    Log.d(TAG, "Network");

                    if (mLocationManager != null) {
                        location = mLocationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            setLatitude(location.getLatitude());
                            setLongitude(location.getLongitude());
                        }
                    }
                }

                // if GPS Enabled get lat/long using GPS Services
                if (isGPSEnabled) {
                    if (location == null)
                    {
                        mLocationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                DEFAULT_DURATION,
                                DEFAULT_RADIUS, this);

                        Log.d(TAG, "GPS Enabled");

                        if (mLocationManager != null) {
                            location = mLocationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                setLatitude(location.getLatitude());
                                setLongitude(location.getLongitude());
                            }
                        }
                    }
                }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }

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

    @Override
    public void onLocationChanged(Location location)
    {
        if (location != null)
        {
            setLongitude(location.getLongitude());
            setLatitude(location.getLatitude());
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        Log.d(TAG, "" + latitude);
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        Log.d(TAG, "" + longitude);
        this.longitude = longitude;
    }

    @Override
    public void onDestroy()
    {
        Log.e(TAG, "onDestroy");
        super.onDestroy();

        if (mLocationManager != null)
        {
            // Remove update listener when you don't require
            mLocationManager.removeUpdates(this);
            mLocationManager = null;
        }
    }
}


Step - 2 : To display Google map fragment inside your app you have to register your app at Google Developer console. and then get Map key. you need to set this key inside Android manifest file. otherwise your app may crash. For complete setup of Google Map api v2 you can find here.


if you have already registered your project you can find Map key at
Project > Apis & auth > Credentials.

google map key
Please do not use this key


Step - 3 : Now we need a class which actually start this service. so create a activity which start this service and get location data.in this activity i have used Google map fragment to show user location if you don't want to display lat long then toast it so you can verify that service is working and you are getting user location data.

TrackUserDemo.java 

package com.androprogrammer.tutorials.samples;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.transition.Slide;
import android.transition.Transition;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.Window;
import android.widget.Toast;

import com.androprogrammer.tutorials.R;
import com.androprogrammer.tutorials.activities.Baseactivity;
import com.androprogrammer.tutorials.services.GetUserLocation;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class TrackUserDemo extends Baseactivity
{

    protected View view;

    // Google Map Object
    private GoogleMap googleMap;

    private LatLng userLatLng;

    private boolean IsFirstTimeLoad = true;

    private LocationManager mLocationManager;

    private static final String TAG = "TrackUserDemo";

    private static String RefreshMenu = "Refresh Map";


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

            //set the transition
            Transition ts = new Slide();
            ts.setDuration(5000);
            getWindow().setEnterTransition(ts);
            getWindow().setExitTransition(ts);
        }

        super.onCreate(savedInstanceState);

        setReference();

 getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        setToolbarTittle(this.getClass().getSimpleName());

        mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        initilizeMap();

    }

    @Override
    protected void onResume()
    {
        super.onResume();
        if (!IsFirstTimeLoad)
        {
            if(!mLocationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
                showGpsAlertDialog();
            }
            else {
                Intent intent = new Intent(this, GetUserLocation.class);
                startService(intent);
                initilizeMap();
            }
        }
        else {
            IsFirstTimeLoad = false;
        }
    }

    private void initilizeMap()
    {
        try {
  // Display Toast message if you don't want to display google map using service.getLatitude(), service.getLongitude() methods
            if (googleMap == null) {
                googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
                // check if map is created successfully or not
                if (googleMap == null)
                {
                    Toast.makeText(TrackUserDemo.this, "Sorry! unable to create maps", Toast.LENGTH_LONG).show();
                }
            }

            // getting GPS status
            boolean isGPSEnabled = mLocationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // getting network status
            boolean isNetworkEnabled = mLocationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            GetUserLocation service = new GetUserLocation(this,isGPSEnabled,isNetworkEnabled);

            if (!isGPSEnabled)
            {

                showGpsAlertDialog();

            }

            userLatLng = new LatLng(service.getLatitude(), service.getLongitude());

            MarkerOptions usermarker = new MarkerOptions().position(userLatLng);

            // To remove old marker
            googleMap.clear();

            googleMap.addMarker(usermarker);

            googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(service.getLatitude(), service.getLongitude()),
                    10.0f));

            googleMap.getUiSettings().setZoomControlsEnabled(true);

        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            //e.printStackTrace();
        }
    }

    private void showGpsAlertDialog() {

        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(TrackUserDemo.this);
        alertDialogBuilder.setTitle("Gps Setting");
        alertDialogBuilder.setMessage("Location data provider is disabled.\nPlease enable it to track location.");

        alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                Intent myIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(myIntent);
            }
        });


        alertDialogBuilder.setNegativeButton(android.R.string.cancel,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which)
                    {
                        dialog.dismiss();
                    }
                });

        AlertDialog alertDialog = alertDialogBuilder.create();

        alertDialog.show();
    }

    @Override
    public void setReference()
    {
        view = LayoutInflater.from(this).inflate(R.layout.activity_trackuser_demo,container);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // To display refresh button
        SubMenu btnRefresh = menu.addSubMenu(RefreshMenu);
        btnRefresh.setIcon(android.R.drawable.ic_popup_sync);
        btnRefresh.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

        super.onCreateOptionsMenu(menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle Toolbar item clicks here. The Toolbar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                finish();
                break;
        }


        if (item.getTitle() == RefreshMenu)
        {
            initilizeMap();
        }

        return super.onOptionsItemSelected(item);
    }
}

activity_trackuser_demo.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"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="?attr/actionBarSize"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.androprogrammer.tutorials.samples.TrackUserDemo">

    <fragment
        android:id="@+id/map"
        class="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>


Step - 4 : well now add/define service and google play meta data in AndroidManifest.xml file. put below code inside it.

AndroidManifest.xml
 
<!-- IMPORTANT ! DO NOT FORGET THIS META-DATA !!! -->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="your_key" />

        <uses-feature
            android:glEsVersion="0x00020000"
            android:required="true" />
<service android:name=".services.GetUserLocation" />

Step - 5 : One More thing you have to add dependencies in app > build.gradle file. so put below code in it.

build.gradle 

dependencies {
 // To add toolbar and material theme.
compile 'com.android.support:appcompat-v7:21.0.3'
compile fileTree(include: ['*.jar'], dir: 'libs')
 // To use Google map and other services.
compile 'com.google.android.gms:play-services:6.1.71'

well now run the app if you are testing in emulator then make sure you have Google apps inside it. other wise Google Map will not work. i hope you understand full tutorial. if you have any questions let me know in below comment box. if you like this share it with your friends.

Get code from Github

Keep coding...

Creating New App... WAIT !


Model-View-Controller (MVC) have made our work so much easy. before this coding were too much congested. business logic and design were in same file. imagine how it was. well now we have MVC Structure in all(Many of them) programming language. In which we have different files for different purpose. but still few things you have to consider if you want clean and nit code.

well, what are those things ?


If your app have user interface mobile or web interface the first thing i think most important for you.

1. Font Size

Define font size for Header, labels and detail text. what ever app you have you may require decent and same look through out the app. so this will help you. one more thing define them in Constant Class(where you can define all static and Constant variables) so you can use them through out the app. and please use even proper name also. like header_text_size or text_header_size so you can even recognize for long time.

2. Padding / Margin

One more thing you have to consider for app style and for its decent look. 

well you are thinking how ?


androprogrammer.com


3. Style

After above steps create a style according to you app colors (Theme). so if your client want to change theme you just have to change at one place no more
Ctrl + f for old color code and replace it with new.

4. Define Constants or Strings
 

You may require text like "OK" , "Save" , "Yes/No" at many place so why to write it again and again. define them once and use them through out the app. this will even help when your app is in two or more languages. so according to language you can change them.



5. Use access specifier

Private, protected, public these are the access specifier which acts like a guard. how ?
In hacking or spiffing hackers use programs which can change values of your app variables. but if you have defined access specifier before variable declaration, they are not acceessible by out side the class. So they can not change the value of that. so if you know scope of the variable define them with appropriate access specifiers.

6. Comments

Give or write proper comments for each class or method that you have defined or created. now a days editor have so many plugins which auto generate comment block so use them. you are not only working on the app or you may not work it on life time so your code must be understandable by others. so that proper comments require which clarify what it actually do.

7. Create proper directory structure

Now a days MVC have already separated our files but still we require some files to put in different folders. like in web app we have java script and css file so put them in different folders.
in mobile app create different folders for activities and services and for all others so if any error or change comes you can directly go there and find problem/change.

8. Background colors

Don't use dark or gradient colors as background use light or single color as a background. mostly we use white or light gray as a background. you can give all effects with this color and even it is more acceptable. as it will effect user experience and you may see dig ration in your app popularity.

Well these all are the points which is based on Kiss(Keep it Simple stupid). i hope you know it.
well i think i have covered all basics that you need to consider before creating any app weather it is web app or mobile app. if i forgot any point let me know in below comment box. i am really happy to know your thoughts on this article.

If you liked my blog please share and subscribe with it.

Navigation Drawer With Transparent Status bar

It is second part of  Let's Start with Material Design Series. In this series i will explain how you can give Material over haul to your existing app or how you can create it with Material design. in first part i have created the main layout of the app so if you want to know about it head over to it. Part -1 is about using Recycler view and Toolbar in Pre - Lollipop device using appcompat v21 library. In this part i am going to explain about navigation drawer. how you can implement navigation drawer as per material design guidelines.This tutorial even includes hamburger animation used in Google apps.

According to android documentation If you have hierarchy of views(More than 3 top-level views) then only you have to implement nav drawer in your app. and all top level views must be displayed in nav drawer for quick jumps to the top-level of your app. As nav drawer can be used from all views of app, you can incorporate or display important lower-level views also. but make sure child view indicate its parent view so user won't get confused.

You can use list view or expandable list view for navigation drawer but make sure for each row you use only one text view. for this tutorial i am going to create nav drawer as you can see in google apps (not the same). but as per Material design guidelines, as guidelines suggest drawer should spans the full height of the screen and the drawer should below the status bar. to span full space we need to customize frame layout. That actually Making DrawerLayout behind the system bars using fitSystemWindows property. one more thing we are using toolbar in place of action bar (that look same as action bar) that's how we will overlapping nav drawer above the action bar. as i am using appcompat library this app will look like same on pre-lollipop android device also.

As per doc the width of the side nav is equal to the width of the screen minus the height of the action bar, or 56dp from the right edge of the screen.
Mobile: Width = screen width - app bar height (No wider than 320dp on phones and 400dp on tablets).

Step -1 : As we have already created project in Part -1 we are directly going to change the main layout of project. so put below code inside Main.xml file. as it consist ScrimInsetsFrameLayout which will give error but don't worry it is customized frame layout. as you go through full tutorial you will get class file for it also. The same is used in Google I/O app. why they have given such name even i can't understand.  you can give name what ever you want. Below xml files are layout for main(content view) and navigation drawer view.
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <!-- Setting this one to true makes the status bar
        to have a non-transparent shitty background -->

    <!--
         As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions.
    -->

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="false">

        <include layout="@layout/actionbarlayout"></include>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:layout_marginTop="?attr/actionBarSize"
            android:layout_marginRight="4dp"
            android:layout_marginLeft="4dp"
            android:elevation="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/addButton"
            android:text="+"
            android:textSize="25sp"
            android:textColor="@android:color/white"
            android:textAlignment="center"
            android:layout_marginRight="15dp"
            android:layout_marginBottom="15dp"
            android:background="@drawable/circlebtn"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:stateListAnimator="@animator/anim"
            android:elevation="4dp"
            style="?android:buttonStyleSmall"
            android:layout_gravity="right|bottom" />
        

    </FrameLayout>

    <com.androprogrammer.test.materialapp1.ScrimInsetsFrameLayout
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:elevation="8dp"
        android:layout_gravity="start"
        app:insetForeground="#4000">

        <ListView
            android:id="@+id/list_drawer"
            android:layout_width="@dimen/drawer_width"
            android:layout_height="match_parent"
            android:choiceMode="singleChoice"
            android:background="@android:color/white"
            android:fitsSystemWindows="true" />
       

    </com.androprogrammer.test.materialapp1.ScrimInsetsFrameLayout>
</android.support.v4.widget.DrawerLayout>
actionbarlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:minHeight="?attr/actionBarSize"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/toolbar"
    android:elevation="4dp"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    android:background="@color/primary"/>

drawerlist_header.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="160dp"
        android:id="@+id/imageView"
        android:scaleType="centerCrop"
        android:clickable="false"
        android:src="@drawable/headerbg"
        android:layout_gravity="center_horizontal|top" />
</FrameLayout>

Step -2 : Now layouts are set for main view. now we will create style for app so it will look same threw out the app.
values/styles.xml
    

    

    
values/attrs.xml

    
        
    

values/color.xml

    #fe2e2e
    #EFcb2424

values/dimens.xml

    2dp
    4dp
    320dp
    56dp


values/strings.xml


    My Application1
    Settings
    open
    close


values-v21/styles.xml


Step - 3 : Now we will move forward to code section of the app which was also know as dirty or magical section of the app.  put below code in ScrimInsetsFrameLayout classor what ever you named it in xml layout. 
ScrimInsetsFrameLayout.java
package com.androprogrammer.test.materialapp1;

/**
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;

/**
 * A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
 * (status and navigation bars, overlay action bars).
 */
public class ScrimInsetsFrameLayout extends FrameLayout {
    private Drawable mInsetForeground;

    private Rect mInsets;
    private Rect mTempRect = new Rect();
    private OnInsetsCallback mOnInsetsCallback;

    public ScrimInsetsFrameLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ScrimInsetsView, defStyle, 0);
        if (a == null) {
            return;
        }
        mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground);
        a.recycle();

        setWillNotDraw(true);
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        mInsets = new Rect(insets);
        setWillNotDraw(mInsetForeground == null);
        ViewCompat.postInvalidateOnAnimation(this);
        if (mOnInsetsCallback != null) {
            mOnInsetsCallback.onInsetsChanged(insets);
        }
        return true; // consume insets
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        int width = getWidth();
        int height = getHeight();
        if (mInsets != null && mInsetForeground != null) {
            int sc = canvas.save();
            canvas.translate(getScrollX(), getScrollY());

            // Top
            mTempRect.set(0, 0, width, mInsets.top);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Bottom
            mTempRect.set(0, height - mInsets.bottom, width, height);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Left
            mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Right
            mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            canvas.restoreToCount(sc);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(this);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(null);
        }
    }

    /**
     * Allows the calling container to specify a callback for custom processing when insets change (i.e. when
     * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
     * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
     * clipToPadding to false.
     */
    public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
        mOnInsetsCallback = onInsetsCallback;
    }

    public static interface OnInsetsCallback {
        public void onInsetsChanged(Rect insets);
    }
}


It is copyrighted by Google developer so if you copy it please give proper reference to them.
MainActivity.java
package com.androprogrammer.test.materialapp1;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity implements ListView.OnItemClickListener
{
    private android.support.v7.widget.RecyclerView mRecyclerView;
    private android.support.v7.widget.RecyclerView.Adapter mAdapter;
    private android.support.v7.widget.RecyclerView.LayoutManager mLayoutManager;
    private android.support.v7.widget.Toolbar toolbar;
    private android.support.v4.widget.DrawerLayout drawerLayout;
    private ActionBarDrawerToggle drawerToggle;
    private ListView leftDrawerList;
    private ArrayAdapter<string> navigationDrawerAdapter;
    private Button fab;
    private String[] leftSliderData = {"Home", "Android", "Sitemap", "About", "Contact Me"};
    protected String[] myDataset = {"facebook", "Google+", "twitter", "Linkdin", "pintrest"};


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        setRef();

        //Set the custom toolbar
        if (toolbar != null)
        {
            toolbar.setTitle(R.string.app_name);
            setSupportActionBar(toolbar);
        }

        drawerToggle = new ActionBarDrawerToggle(
                this,
                drawerLayout,
                toolbar,
                R.string.open,
                R.string.close
        )

        {
            public void onDrawerClosed(View view)
            {
                Log.d("MainActivity", "OnDrawerClosed");
                super.onDrawerClosed(view);
                invalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView)
            {
                Log.d("MainActivity", "OnDrawerOpened");
                super.onDrawerOpened(drawerView);
                invalidateOptionsMenu();
            }
        };

        drawerLayout.setDrawerListener(drawerToggle);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());

        // specify an adapter (see also next example)
        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);

    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    private void setRef()
    {
        mRecyclerView = (android.support.v7.widget.RecyclerView) findViewById(R.id.my_recycler_view);
        fab = (Button) findViewById(R.id.addButton);
        drawerLayout = (android.support.v4.widget.DrawerLayout) findViewById(R.id.drawer_layout);
        drawerLayout.setStatusBarBackground(R.color.primarydark);

        toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
        leftDrawerList = (ListView) findViewById(R.id.list_drawer);

        View list_header = getLayoutInflater().inflate(R.layout.drawerlist_header, null);
        leftDrawerList.addHeaderView(list_header);
        navigationDrawerAdapter = new ArrayAdapter<string>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, leftSliderData);
        leftDrawerList.setAdapter(navigationDrawerAdapter);
        leftDrawerList.setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id)
    {
        Toast.makeText(getApplicationContext(), "Clicked on " + leftSliderData[position - 1], Toast.LENGTH_LONG).show();
    }

}


Screen Shots

android navigation drawer android navigation drawer

Step - 4 : Now every thing done but please apply theme in manifest.xml in application tag.
android:theme="@style/AppTheme"
And one more thing is that to run app you need to add libraries in app.gradle file it is in app folder named as build.gradle
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:support-v4:21.0.0'
    compile 'com.android.support:recyclerview-v7:21.0.+'
    compile 'com.android.support:appcompat-v7:21.0.2'


Well that's it from my side now run the app and check how it works. hope you learned from this tutorial if find it useful please hare it with your friends or in circle. if i miss any thing or you have any query please let me know in below comment box.

Keep coding...

Let's Start with Material Design

Material design sampleHave Heard lots of about Android Material design but don't know from where to start, well in this tutorial i will tell you how to create app from scratch with material design. This tutorial is just a beginning of Material design tutorial. so i just keep it simple.


From Kitkat and all older version of android Google has given new overhaul with the Material design in Android 5.0 (Well known as Android Lollipop). with new Card view , Recycler view and some of the new animation it is really user friendly. User will love the animation in this version. So lets start new project with android api -21.

Step - 1 : Create New Android application and give name MainActivity to main activity and same name for layout file.
  • minSdkVersion="21”
  • targetSdkVersion="21"
now put below code in your project main.xml file. you can set layout as you want but for practice purpose you can go with same.
Main.xml


    <android.support.v7.widget.recyclerview android:elevation="5dp" android:id="@+id/my_recycler_view" android:layout_height="match_parent" android:layout_marginleft="4dp" android:layout_marginright="4dp" android:layout_margintop="10dp" android:layout_width="match_parent" android:scrollbars="vertical">
    </android..support.v7.widget.recyclerview>

    




I have used frame layout. it allows to put component(widget/view) at any specific position. To create round button there are number of ways but i have used simple way of setOval method of outline class. this button is for sample in this tutorial. i will make use of it next tutorial so keep subscribed with us.now put below code for oval shape of it.
drawable/ripple.xml

    
        
            
        
    


Below one is layout for recycler view item. RecyclerView is also list view but with some extended features like list item remove or add animation and much more. so put below file in row_layout.xml file.
layout/row_layout.xml


    
    


Step - 2 : Now your layout is set but to apply your custom theme now add style.xml file in value-v21 folder and put below code in it. you can change color codes as per your app theme.
value-v21/styles.xml

    


Step - 3 : Now All layout set so we move to code section. this is start up with material design so i have used simple array to display values in recycler view. put below code in main.java file.
Main.java
package com.androprogrammer.test.myapplication1;

import android.app.Activity;
import android.graphics.Outline;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.Button;


public class MainActivity extends Activity
{
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    protected String [] myDataset = {"facebook", "Google+", "twitter", "Linkdin", "pintrest"};


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        Button fab = (Button) findViewById(R.id.addButton);

        ViewOutlineProvider viewOutlineProvider = new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                // Or read size directly from the view's width/height
                outline.setOval(0, 0, 56, 56);
            }
        };

        fab.setOutlineProvider(viewOutlineProvider);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());

        // specify an adapter
        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);

    }


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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}


MyAdapter.java
package com.androprogrammer.test.myapplication1;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Created by wasim on 07/12/14.
 */
public class MyAdapter extends RecyclerView.Adapter<myadapter .viewholder=""> {
    protected String[] mDataset;

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView mTextView;
        public ViewHolder(View v) {
            super(v);
            mTextView = (TextView) v.findViewById(R.id.row_tv);
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v)
                {
                    Toast.makeText(v.getContext(), "Clicked on " + getPosition(), Toast.LENGTH_LONG).show();
                }
            });
        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(String[] myDataset) {
        this.mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.row_layout, parent, false);
        // set the view's size, margins, paddings and layout parameters

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.mTextView.setText(mDataset[position]);

    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}


RecyclerView.Adapter is extened like other adapters in android. view more about adapters in my previous post. in this class you have to implement view holder pattern that will assign view to each row. well there is no more changes in recycler view then list view. in list view adapter you assign view in getView method while in this case you can assign data in onBindViewholder method.


Screen Shots

Let's Start with Material Design Let's Start with Material Design

So that's it from coding side now you can run app and test it. i hope you it will run smoothly.
if you have any query comment it in below comment box.
Keep coding...

Data Adapters in android

Adapters are like magician. In android if you want to display block of data in List view or Grid view or any other android widget you have to implement some kind of adapter class in your application. It can be Base adapter or Array adapter or any. So in this class you perform some ugly or magical work. Like creating view for each row of list or grid and then assign data and even you can write some business logic also in that adapter class.

Types of adapters in android are as follows
  1. Base Adapter
  2. Simple Adapter 
  3. Array Adapter
  4. Simple Cursor Adapter
  5. List Adapter
  6. Cursor Adapter
  7. Resource Cursor Adapter
  8. Spinner Adapter
  9. Simple Cursor Tree Adapter
  10. Cursor Tree Adapter
  11. Header View List Adapter
  12. Wrapper List Adapter

Well some of them are totally new for me and i hope for you also. Because they are less known and less used by developers. They consist lots of complexity but for different uses it may help you. just check it out in android documentation. These are the list of adapters till android v 4.4 Kitkat. it may happen android team will add new adapters in next version of android named as android L or in future . So from above all the adapters which are mostly used in android and easy to implement. 

Base Adapter
As name suggest it is base class for all adapter class and interface. Base adapter is abstract class.Base Adapter is a very generic adapter that allows you to do pretty much whatever you want. However, you have to do a bit more coding yourself to get it working.using this class you can define custom view for each row and also you can perform task on object click event also. getView method is basically implemented in this class and you can override it and define your layout in this method. using this class you can bind data with list view and spinner. this is the most used adapter class for binding data in any view. even you can write business logic also in this class. in base adapter class you have to implement even getcount method because on the basis of that adapter will call getview method. Read more

Simple Adapter
when you want to bind static data set to list view you can use simple adapter. you can define xml layout for each row and data can be in array list or in map. each row represent single record of array list. simple adapter class extends Base Adapter class so you have all those methods so you can override even in simple adapter class. data binding is done using view Binder method. Read more

Array Adapter
Second is Array Adapter. Array Adapter is a class which can work with array of data. you need to override only getview method. you can override getview method with different types of parameter. but the main use of array adapter when you want to display a single text view in each row of list. then it is batter to use this adapter. you have to pass data layout or resource file id and text view id in getview method. you can even use image view and other object but for that Base adapter class is perfect. Read more

Simple Cursor Adapter
If your application requires data from local database then you can use simple cursor adapter class to bind data. this is class like simple adapter if you require to display data from database in listview then it is best practice to extend this class. it also works as simple adapter class. different between both is in simple adapter data is in array list and static and in this class data is in cursor and comes from database. data binding in this also done using view Binder method. Read more

Cursor Adapter
if you want to implement this class make sure your table consist one column named as "_id". because cursor traverse data using this column in cursor adapter. and if you want to perform some filtration or swipe cursor then only use this class. it is quite complex so if you are new in android don't try this try some other adapters. one more thing in cursor adapter you have to implement or override new view and bind view method. in which you can define view for each row and bind data also. cursor view already implement getview method so it is better to not to override this method. Read more

Simple Cursor Tree Adapter
last but not list simple cursor tree adapter is useful when you have nested view like nested list view or grid view.  the class provide you method to define layout for child view or group view so if you have data from database and even it is complex (two / three table data) then you can use this adapter class to display data in nested view. Read more

Well there are other adapters also in the list but they are less used and i just covered few details of each adapter class you can find more details about it. click on read more and it will redirect you to documentation where you can find more about it. one more thing, in android View Holder pattern is most famous and use full pattern of saving row layout before it get recycled by garbage collector. so before implementing look after this pattern.

I hope these details help you to understand about adapters. and if it is helpful to you please share this article with your friends. and if you have any thing to say about this article write down in below comment box. new things and suggestion always welcome.
Keep coding...

Create or Copy Database in Android

Yesterday i spent whole day behind using my database i mean database is created i just require to use it in app. And i came across many problems, Some of them were really annoying and confusing. For some of them you can find online solution but some are really unknown like null pointer exception or getWritableDatabase method called recursively etc. even if there is table and also data in it.   some times it also happens you can not copy big database and it is also big problem in android. 
For that you have to dig up in to your code. You have to debug your app and in android studio it is also tedious task.  so to save your time and without doing all this you can copy database from assets folder to internal storage. Just go through the full tutorial and i hope it will solve all problems regarding coping database.

Step - 1.  Put below code in your SQLiteOpenHelper Class file. you have to put this code in onCreate method. if you have done some other task in oncreate method then rearrange it after this code. this code will check if database exist then do nothing because if you won't check it will overwrite your database every time you call   getWritableDatabase Or getReadableDatabase Method. beacuse it call onCreate method internally.

Step - 2. From your Main Activity only first time call Oncreate method of  SQLiteOpenHelper Class. so for the first time it will create or copy your database. if your database is big you can display progress bar for loading process.

DbHelper.java
package com.androprogrammer.dbdemo;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


public class DbHelper extends SQLiteOpenHelper 
{
 public static final String DB_NAME = "mydb.db";
 public static final int version = 1;
 public static final String product_table = "tblproduct";
 public static final String order_id = "_id";
 public static final String pname = "pname";
 public static final String desc = "desc";
 public static final String quantity = "quantity";
 public static final String rating = "rating";
 
 private SQLiteDatabase ourdb;
 public Context cont;

 public DbHelper(Context context)
 {
  // TODO Auto-generated constructor stub
  super(context, DB_NAME, null, version);
  this.cont = context;
 }

 @Override
 public void onCreate(SQLiteDatabase db)
    {
        try
        {
            File dbFile = cont.getDatabasePath(DB_NAME);

            if (dbFile.exists())
            {
                //Toast.makeText(cont, "Database Already Exist..." , Toast.LENGTH_LONG).show();
            }
            else
            {
                this.getReadableDatabase();

                InputStream input = cont.getAssets().open(DB_NAME);
                int size = input.available();
                input.close();

                if (size > 0)
                {

                    Log.d("file" , dbFile.getPath());

                    copyDataBase(dbFile);
                    //this.close();
                }
                else
                {
                    // TODO Auto-generated method stub
                    db.execSQL("create table " + product_table +" ( "+ order_id + " INTEGER PRIMARY KEY AUTOINCREMENT , " + pname + " TEXT NOT NULL ," + desc + " TEXT ,"
                            + rating + " INTEGER ," + quantity +" INTEGER );");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.ourdb = db;

 }

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // TODO Auto-generated method stub
  
 }

    /**
     * Copies your database from your local assets-folder to the just created empty database in the
     * system folder, from where it can be accessed and handled.
     * This is done by transfering bytestream.
     *
     * @param dbFile*/
    private void copyDataBase(File dbFile) throws IOException {

        //Open your local db as the input stream
        InputStream myInput = cont.getAssets().open(DB_NAME);

        //Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(dbFile);

        //transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0)
        {
            myOutput.write(buffer, 0, length);
            Log.d("buf", "" + length);
        }

        //Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }
  
 public DbHelper open() throws SQLException
 {
        if (this.ourdb == null)
        {
           this.ourdb = this.getWritableDatabase();
        }

  return this;
 }

 public synchronized void close()
 {
        if(this.ourdb.isOpen())
      this.ourdb.close();
 }

 public long insert(String name, String des, Float ratings, int quan) throws SQLException
 {
  // TODO Auto-generated method stub
  ContentValues cv = new ContentValues();
  cv.put(pname, name);
  cv.put(desc, des);
  cv.put(rating, ratings);
  cv.put(quantity, quan);
  return this.ourdb.insertOrThrow(product_table, null, cv);

 }

 public Cursor getAllData() throws SQLException
 {
  // TODO Auto-generated method stub
  String [] colums = new String[]{order_id ,pname ,desc ,rating ,quantity};
  Cursor c = this.ourdb.query(product_table,colums, null, null, null, null, null, null);
  return c;
 }

}



As you can see i have even checked if there is no file in assets folder it will create blank database so application won't crash. because it create bad impect when you publish your app in Google play store and it crash so for safety side you can do this. then you can update it later on. now from your main activity just call the onCreate method for that put below code in it.

SQLiteDatabase db = null;
DbHelper helper = new DbHelper(Main.this);
helper.onCreate(db);

Now your database file created or copied so just check it if you have created display method or activity then open it and check it. you can see in debug window also because i have used Logger to know weather database is copied or not so check debug window in editor. now from all other class or activity just call open method. for that put below code in it.

DbHelper helper = new DbHelper(this);
helper.open();

The open method will return instance of database after checking weather it is opened or not. ok now run your app and see the result. if you find any error or if you have any query let me know. Comment in below comment box. it may happen you may find some new error then also let me know so other can also solve that and i will try my best to solve that problem. i have also written tutorial about add, update and display records from database so if you have any query regarding that also check this out.
Keep coding ...