Android Oauth Login with Google Account with new Google Play Services

New-googleplay-service-signin


To use Google sign in, you need to first set up a project on the server using Google's developer console. Go to accounts.google.com and make sure that you're signed in to your google account. And, if you don't have one, then, create one. So, I'm going to sign in to my account. Once you're signed in, go to https://developers.google.com/mobile/add. This will take you to the screen on the Google servers where you can add a project to your developer account.
So, I'm going to choose Pick a platform, and I'm gonna choose Android App. Now, I've already done this for my existing project. So, I'm just going to show you what it is that I did, and you can follow along with me. So, I can either chose an existing project or make a new one.


androidxu-google-sigin


androidxu-google-sigin


And, since I've already done this, I'm just going to create a temporary example to show you what I did. But, you can make a new project for yourself. So, I'm going to give the project a name. I'm just gonna call it google-signin.
Adding the SHA 1 key

Paste the command in you terminal windows to genrate the SHA 1 key
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android


Once done you can download the google-services.json file and add it your app directory of your project. 



So, let's go into Android studio and finish setting things up. So, in Android studio, I'm going to open the Sign in project. Alright,when it loads, what we're going to do is, in the projects explorer, we're gonna open up the build.gradle for the project Sign in. And under the classpath definition that you see here, we're going to add another one. We're going to add classpath com.google.gms:google-services.

Lets get started!



1. In Android Studio, go to File -> New Project and fill all the details required to create a new project. When it prompts to select a default activity, select Blank Activity and proceed.

Adding Dependencies

2. Open build.gradle and add android design support library  com.android.support:design:23.2.1 and other dependencies.
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "android.com.google_signin"
        minSdkVersion 10
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.google.android.gms:play-services:8.4.0'
}

apply plugin: 'com.google.gms.google-services'



Next Creating the  layout and adding the custom google signin buttom

<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="android.com.google_signin.MainActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Status: "
        android:textSize="24sp"
        android:id="@+id/tvStatusLabel"
        android:textStyle="bold" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Not Connected"
        android:id="@+id/tvStatus"
        android:layout_alignParentTop="true"
        android:textSize="24sp"
        android:layout_toEndOf="@id/tvStatusLabel" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Display Name:"
        android:id="@+id/tvDispNameLabel"
        android:layout_below="@+id/tvStatusLabel"
        android:layout_alignParentStart="true"
        android:textStyle="bold"
        android:textSize="24sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Email: "
        android:id="@+id/tvEmailLabel"
        android:textStyle="bold"
        android:textSize="24sp"
        android:layout_below="@+id/tvDispName"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tvDispName"
        android:layout_alignTop="@+id/tvDispNameLabel"
        android:layout_toEndOf="@+id/tvDispNameLabel"
        android:textSize="24sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tvEmail"
        android:layout_alignTop="@+id/tvEmailLabel"
        android:layout_toEndOf="@+id/tvEmailLabel"
        android:textSize="24sp" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Disconnect"
        android:id="@+id/btnDisconnect"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Sign Out"
        android:id="@+id/btnSignOut"
        android:layout_above="@+id/btnDisconnect"
        android:layout_centerHorizontal="true" />

    <com.google.android.gms.common.SignInButton
        android:id="@+id/btnSignIn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnSignOut"
        android:layout_centerHorizontal="true"
        android:visibility="visible" />
</RelativeLayout>

Working with MainActivity.java and Google sign in Api.

So let's scroll down to the onCreate function. And here is a to-do for us to implement the Google sign-ins object, and you can see that the GoogleApiClient is being created right below this. So let's implement that code.

And in the builder we'll pass in GoogleSignInOptions.Default_Sign_In which is pretty much the only one you can pass and then we'll say .requestEmail . All right, so once we've built the Google sign-in options builder, we need to pass that to the Google API client. And to do that we use our familiar add API method.
So right after here I'll type in .addApi and pass in Auth.Google_Sign_In_API along with the Google sign-in options object that we just created, okay. So that creates the sign-in options object, passes it to the Google API client, and that allows us to use the sign-in API.
So what we're going to do is scroll up to the startSignIn function, and what we need to do now is start the sign-in process. So, to invoke the account picker that lets the user choose the account they want to sign in with, we need to create a sign in intent, and then start it. So let's write that code, I'm going to write Intent signInIntent equals Auth.GoogleSignInApi.getSignInIntent. I'm going to pass in the mGoogleApiClient that I've created and then I'm gonna call startActivityForResult with my signInIntent, and a code, and you can see that I've defined a constant up here to indicate that the activity I'm starting for result is the sign-in process, and we'll use that later when the activity result handler is called.
So I'll type Res_Code_Sign_In. All right, so when the user selects the account to sign in with, that's going to cause the onActivityResult function to be called, and onActivityResult is down here. So when this function is called, we're going to check to make sure that what they're doing is the sign-in process and the code is going to extract the GoogleSignInResult and it's going to pass that to a function called the signInResultHandler. So it gets the GoogleSignInResult by calling the getSignInResultFromIntent, which is this intent that's passed in from the end of the process.
So let's go take a look at the signInResultHandler and the signInResultHandler is up here. So this function checks to see if sign-in was successful by calling the result.isSuccess function.And if so, it extracts information such as the user's Display Name, the user's email, and sets those values into the text fields in our layout.


Adding the MainActivty Code


Copy and paste the code to Mainactivity.java


package android.com.google_signin;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.auth.api.signin.GoogleSignInStatusCodes;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.common.api.Status;

public class MainActivity extends AppCompatActivity implements
        GoogleApiClient.OnConnectionFailedListener,
        View.OnClickListener {

    private static final String TAG = "SIGNIN_EXERCISE";
    private static final int RES_CODE_SIGN_IN = 1001;

    private GoogleApiClient mGoogleApiClient;

    private TextView m_tvStatus;
    private TextView m_tvDispName;
    private TextView m_tvEmail;

    private void startSignIn() {
        // TODO: Create sign-in intent and begin auth flow
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RES_CODE_SIGN_IN);
    }

    private void signOut() {
        // TODO: Sign the user out and update the UI
        Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
                new ResultCallback() {
                    @Override
                    public void onResult(Status status) {
                        m_tvStatus.setText(R.string.status_notsignedin);
                        m_tvEmail.setText("");
                        m_tvDispName.setText("");
                    }
                });
    }

    private void disconnect() {
        // TODO: Disconnect this account completely and update UI
        Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
                new ResultCallback() {
                    @Override
                    public void onResult(Status status) {
                        m_tvStatus.setText(R.string.status_notconnected);
                        m_tvEmail.setText("");
                        m_tvDispName.setText("");
                    }
                });
    }

    private void signInResultHandler(GoogleSignInResult result) {
        Log.d("result=", String.valueOf(result));
        if (result.isSuccess()) {
            GoogleSignInAccount acct = result.getSignInAccount();
            m_tvStatus.setText(R.string.status_signedin);
            try {
                Log.i("Signin",acct.getDisplayName());
                m_tvDispName.setText(acct.getDisplayName());
                m_tvEmail.setText(acct.getEmail());
            }
            catch (NullPointerException e) {
                Log.d(TAG, "Error retrieving some account information");
            }
        }
        else {
            Status status = result.getStatus();
            int statusCode = status.getStatusCode();
            Log.d("StatusCode", String.valueOf(statusCode));
            if (statusCode == GoogleSignInStatusCodes.SIGN_IN_CANCELLED) {
                m_tvStatus.setText(R.string.status_signincancelled);
            }
            else if (statusCode == GoogleSignInStatusCodes.SIGN_IN_FAILED) {
                m_tvStatus.setText(R.string.status_signinfail);
            }
            else {
                m_tvStatus.setText(R.string.status_nullresult);
            }
        }
    }

    // *************************************************
    // -------- ANDROID ACTIVITY LIFECYCLE METHODS
    // *************************************************
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        m_tvStatus = (TextView)findViewById(R.id.tvStatus);
        m_tvDispName = (TextView)findViewById(R.id.tvDispName);
        m_tvEmail = (TextView)findViewById(R.id.tvEmail);

        findViewById(R.id.btnSignIn).setOnClickListener(this);
        findViewById(R.id.btnSignOut).setOnClickListener(this);
        findViewById(R.id.btnDisconnect).setOnClickListener(this);

        // TODO: Create a sign-in options object
        GoogleSignInOptions gso = new GoogleSignInOptions
                .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .requestScopes(new Scope(Scopes.PLUS_LOGIN))
                .build();

        // Build the GoogleApiClient object
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, this)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        // TODO: Customize the sign in button
        SignInButton signInButton = (SignInButton) findViewById(R.id.btnSignIn);
        signInButton.setSize(SignInButton.SIZE_WIDE);
        signInButton.setColorScheme(SignInButton.COLOR_DARK);
        signInButton.setScopes(gso.getScopeArray());
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode,resultCode,data);

        if (requestCode == RES_CODE_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            signInResultHandler(result);
        }
    }

    // *************************************************
    // -------- GOOGLE PLAY SERVICES METHODS
    // *************************************************
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.d(TAG, "Could not connect to Google Play Services");
    }

    // *************************************************
    // -------- CLICK LISTENER FOR THE ACTIVITY
    // *************************************************
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnSignIn:
                startSignIn();
                break;
            case R.id.btnSignOut:
                signOut();
                break;
            case R.id.btnDisconnect:
                disconnect();
                break;
        }
    }
}

Run the App
androidxu-google-sigin

Working with Android material Design Recyclerview and CardView



The RecyclerView widget is a more advanced and flexible version of ListView. This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events.


We all know how to use ListView in our app and we know if we want to increase the ListView performances we can use a pattern called ViewHolder. This pattern consists of a simple class that holds the references to the UI components for each row in the ListView.

This pattern avoids looking up the UI components all the time the system shows a row in the list. Even if this pattern introduces some benefits, we can implement the ListView without using it at all. RecyclerView forces us to use the ViewHolder pattern.
The RecyclerView class simplifies the display and handling of large data sets by providing:
  • Layout managers for positioning items
  • Default animations for common item operations, such as removal or addition of items
You also have the flexibility to define custom layout managers and animations for RecyclerView widgets.
Figure 1. The RecyclerView widget.
To use the RecyclerView widget, you have to specify an adapter and a layout manager.

Working with CardView

CardView extends the FrameLayout class and lets you show information inside cards that have a consistent look across the platform. CardView widgets can have shadows and rounded corners.

To create a card with a shadow, use the card_view:cardElevation attribute. CardView uses real elevation and dynamic shadows on Android 5.0 (API level 21) and above and falls back to a programmatic shadow implementation on earlier versions.

Lets get Started!
We’ll start this by creating a new project and applying the material theme.
1. In Android Studio, go to File -> New Project and fill all the details required to create a new project. When it prompts to select a default activity, select Blank Activity and proceed.

Adding Dependencies

2. Open build.gradle and add android design support library  com.android.support:design:23.2.1 and other dependencies.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:recyclerview-v7:23.2.1'
    compile 'com.android.support:cardview-v7:23.2.1'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
}
Open colors.xml located under res -> values and add the below color values.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#1A4B9C</color>
    <color name="colorPrimaryDark">#003791</color>
    <color name="colorAccent">#FF4081</color>
    <color name="textcolor">#000000</color>
</resources>
Open styles.xml located res -> values and add below styles. The styles defined in this styles.xml are common to all the android versions.
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>



Finally open AndroidManifest.xml and modify the theme to our requirement
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="androidxu.com.menucard">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name="androidxu.com.menucard.ListViewActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Now we have our app material ready. So let’s start adding and building the layout file to demonstrate horizontal and vertical listview
Create and open Open the layout file of item_horizontal_list activity (res->item_horizontal_list.xml) and add below layout code.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="210dp"
    android:layout_height="wrap_content"
    android:layout_marginRight="5dp">

    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            android:adjustViewBounds="true"

            android:src="@drawable/mountain" />

        <TextView
            android:id="@+id/txtview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="@string/lorem_ipsum" />

    </LinearLayout>
</android.support.v7.widget.CardView>
Create and open Open the layout file of item_vertical_list activity (res > item_vertical_list.xml) and add below layout code.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image"
            android:layout_width="100dp"
            android:layout_height="80dp"
            android:contentDescription="@string/app_name"
            android:padding="5dp"
            android:src="@drawable/mountain" />

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_toRightOf="@+id/image"
            android:text="@string/lorem_ipsum"
            android:textStyle="bold"
            android:layout_marginLeft="5dp"
            android:textColor="@color/textcolor" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textView"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/image"
            android:layout_below="@+id/text"
            android:layout_marginLeft="5dp"
            android:layout_toEndOf="@+id/image" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

Open the layout folder  and create a blank layout file which hold the layout of recyclerview
Add a Linearalayout which binds both the list in a scrollview  by creating a new blank layout file activity_list.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:scrollbars="vertical"
    android:padding="@dimen/activity_horizontal_margin">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="20dp"
        android:text="Recommended for You"
        android:textStyle="bold" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/horizontal_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:textColor="@color/colorPrimaryDark"
        android:text="Top Deals of the Day"
        android:textStyle="bold" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyle_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
</ScrollView>

Create a HorizontalListAdapter.java which will extend the recylerview to hold the recyclerview .
package androidxu.com.menucard;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class HorizontalListAdapter extends RecyclerView.Adapter<HorizontalListAdapter.ViewHolder> {

    private Activity activity;
    int[] images= {R.drawable.prawan,R.drawable.awadhi_lucknow_biryani,R.drawable.eggwraps,
            R.drawable.chips,R.drawable.mayonnaise,R.drawable.cmp,R.drawable.mixvegwrap};
    String[] food_items={"prawan","awadhi_lucknow_biryani","eggwraps","chips","mayonnaise","companin","mixvegwrap"};


    public HorizontalListAdapter(Activity activity) {
        this.activity = activity;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_horizontal_list, viewGroup, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(HorizontalListAdapter.ViewHolder viewHolder, final int position) {
        viewHolder.imageView.setImageResource(images[position]);
        viewHolder.txtview.setText(food_items[position].toUpperCase());

        viewHolder.linearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(activity, "Position clicked: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return images.length;
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {

        private LinearLayout linearLayout;
        private ImageView imageView;
        private TextView txtview;


        public ViewHolder(View view) {
            super(view);
            imageView = (ImageView) view.findViewById(R.id.imageview);
            txtview = (TextView) view.findViewById(R.id.txtview);
            linearLayout = (LinearLayout) view.findViewById(R.id.layout);
        }
    }
}

Similarly,Create a VerticalListAdapter.java which will extend the vertical recylerview to hold the recyclerview .
package androidxu.com.menucard;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class VerticalListAdapter extends RecyclerView.Adapter {

    private Activity activity;

    public VerticalListAdapter(Activity activity) {
        this.activity = activity;
    }
    int[] images= {R.drawable.prawan,R.drawable.awadhi_lucknow_biryani,R.drawable.eggwraps,
            R.drawable.chips,R.drawable.mayonnaise,R.drawable.cmp,R.drawable.mixvegwrap};
    String[] food_items={"prawan","awadhi_lucknow_biryani","eggwraps","chips","mayonnaise","companin","mixvegwrap"};
    String[] cost={"Rs 200","Rs 300","Rs 150","R 320","Rs 450","Rs 120","Rs 380"};
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_recycler_view, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
       // if ((position + 1) % 2 == 0) {
            viewHolder.imageView.setImageResource(images[position]);
             viewHolder.txtview.setText(food_items[position].toUpperCase());
        viewHolder.txtCost.setText("Cost Per Person "+cost[position]);
       // } else {
          //  viewHolder.imageView.setImageResource(R.drawable.awadhi_lucknow_biryani);
        //}
        viewHolder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(activity, "Position: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return images.length;
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private TextView txtview;
        private TextView txtCost;
        private RelativeLayout container;

        public ViewHolder(View view) {
            super(view);
            imageView = (ImageView) view.findViewById(R.id.image);
            txtview = (TextView) view.findViewById(R.id.text);
            txtCost= (TextView) view.findViewById(R.id.textView);
            container = (RelativeLayout) view.findViewById(R.id.container);
        }

    }
}


Now add both the view and bind the adapters in ListViewActivity.java
package androidxu.com.menucard;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

public class ListViewActivity extends AppCompatActivity {

    private RecyclerView horizontalList;
    private RecyclerView verticalList;
    private HorizontalListAdapter horizontalAdapter;
    private VerticalListAdapter verticalAdapter;

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

        horizontalList = (RecyclerView)findViewById(R.id.horizontal_recycler);
        verticalList = (RecyclerView)findViewById(R.id.recyle_view);

       // horizontalList.setHasFixedSize(true);
        //verticalList.setHasFixedSize(true);

        //set horizontal LinearLayout as layout manager to creating horizontal list view
        LinearLayoutManager horizontalManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
        horizontalList.setLayoutManager(horizontalManager);
        horizontalAdapter = new HorizontalListAdapter(this);
        horizontalList.setAdapter(horizontalAdapter);

        //set vertical LinearLayout as layout manager for vertial listview
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        verticalList.setLayoutManager(layoutManager);
        verticalAdapter = new VerticalListAdapter(this);
        verticalList.setAdapter(verticalAdapter);
    }
}
Run the App

Working with Android Material Support Design-Bottom Navigation Bar


Today we are presenting AndroidBottomSheet which is included in latest support-design libraray.
Bottom sheet comes with two implementations BottomSheetBehavior andBottomSheetFragmentDialog.
There are two major types of bottom sheets:
  • Modal bottom sheets are alternatives to menus or simple dialogs. They can also present deep-linked content from other apps. They are primarily for mobile.
  • Persistent bottom sheets present in-app content.
Elevation distinguishes modal from persistent bottom sheets. Modal bottom sheets rest at a higher elevation than the app’s content; whereas persistent bottom sheets rest at the same elevation as the app and integrate with its content.
On larger screens, where space is less constrained, using alternative surfaces and components such as simple dialogs and menus may be more appropriate than bottom sheets.

Android Material Support Design-Tabs


Android Design Support Library made our day easier by providing backward compatibility to number of material design components all the way back to Android 2.1. In Design support Library the components like navigation drawer, floating action button, snackbar, tabs, floating labels and animation frameworks were introduced. In this article we are going to learn how to implement material swiping tabs in your apps.


  • Tabs enable content organization at a high level, such as switching between views, data sets, or functional aspects of an app.
  • Present tabs as a single row above their associated content. Tab labels should succinctly describe the content within.
  • Because swipe gestures are used for navigating between tabs, don't pair tabs with content that also supports swiping.


Redesigning Facebook FeedView in Ionic and angular

Facebook feed view in angular.js and ionic

Making Time: Redesigning Concept Facebook Feed For Android with Ionic and angular.js


In UX design, few things are more intricate than time and personal time management — only a good arsenal of mobile design patterns and information architecture principles can save you. This is the story of redesigning the UX for a popular social networking app the Facebook Android app.

Before we get started  redesigning the news feed  we were already checked for what

Disclaimer: This app is not intended to be a fully-featured facebook news feed but rather I want to demonstrate how to implement the same UI/UX method in ionic applications.

This was a weekend project which we coded .
What we took as reference to build is the Android app for facebook


Working with Ionic 2,Angular.js and cordova Geolocation

As suggested by some of our readers ,Today we are presenting new post for Ionic-2 with geolocation using angular.js

In this post for a sample we are going to build a weather app using the Forecast API by fetching current location.

Things we are going to do today is building a complete ionic app with side-menu, fetching data from API,asking for user location and much more..  



weather app with ionic and geolocaion


So,Let get Started!
Setting up and Creating a new Blank Project in Ionic:
Now let's create an app. From the terminal, go to your project folder. Type the following command to create a blank app with tabs.
Lets install ionic and cordova first,
npm install -g ionic cordova
Ionic framework now got installed on your machine,now lets create new blank project.
ionic start weatherapp blank

Simply replace tabs in the above line with tab or side menu to create a tab app, or an application with a side menu.
Finally navigate to the project directory and add iOS and/or Android platforms to Ionic and test the app.
cd weatherapp
ionic platform add ios/Android
ionic build ios/Android
ionic emulate ios/android


To complete the app we need to:

  1. Define the front end views
  2. Define controllers that provide data
  3. Define routes to tie the views to the controllers

Since we created a blank apps ,create a template folder and  Navigate to the folder www/templates from your application root directory. This folder contains template files that will be rendered for the app.
Creating template files which we will use for Side-menu and fetching and showing weather UI using Forecast API


A)Create new template/menus.html file and paste the below code to it.
This file contains the html code for creating side-menus in your ionic applications.
We are try to fetch and convert the temperature either to Celsius/Fahrenheit using the ionic-radio component.

<ion-side-menus>
  <ion-side-menu-content>
    <ion-nav-bar class="bar-stable">
      <ion-nav-buttons side="right">
        <button class="button button-clear ion-navicon" menu-toggle="right"></button>
      </ion-nav-buttons>
    </ion-nav-bar>
    <ion-nav-view name="menuContent">
    </ion-nav-view>

  </ion-side-menu-content>
  <ion-side-menu side="right">
    <ion-header-bar class="bar-stable">
      <h1 class="title">Settings</h1>
    </ion-header-bar>
    <ion-content>
      <ion-item class="item-divider icon ion-home"> Home</ion-item>
      <ion-radio ng-model="settings.units" ng-value="'us'" menu-close="true" >Fahrenheit</ion-radio>
    <ion-radio ng-model="settings.units" ng-value="'si'" menu-close="true" >Celsius</ion-radio>
      <ion-item class="item-divider ">Cities</ion-item>
   <ion-item class="item-divider">Location</ion-item>
    </ion-content>
  </ion-side-menu>

</ion-side-menus>


Next ,create the weather.html template which will fetch the weather details from Forecast API and showcase in UI.
The weather.html has the function of pull-to-refresh functionality which will be used to refresh the location.

<ion-view id="weatherContainer">
  <ion-content>
    <ion-refresher pulling-text="Pull to refresh..." on-refresh ="doRefresh()">
    </ion-refresher>
    
    
    <div id="current-weather" ng-show="haveData">
      <h1 class="current-temp">{{currentTemp}}&deg;</h1>
      <h2>{{current.summary}}</h2>
      <h3>
      <span id="temp-hi"><i class="icon ion-arrow-up-c"></i>{{highTemp}}&deg;</span>
      <span id="temp-lo"><i class="icon ion-arrow-down-c"></i>{{lowTemp}}&deg;
      </span>
        </h3> <h3>
      <span id="temp-hi"><i class="icon ion-android-pin"></i>{{longi}}&deg;</span>
      <span id="temp-lo"><i class="icon ion-android-pin"></i>{{lati}}&deg;
      </span>
        </h3>
    </div>
  </ion-content>

</ion-view>

Adding the template and main controller to index.html
Include the controller file and template file in the main index.hml to bind all the things at one. by creating three controller Navigate to js folder and create three js files. controller.js -handling Geolocation of the app by contacting the ngCordova plugin. app.js-Defining the routers and controller mapping service.js-Sending the request to forecast API and updating with response.



<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>
    <script src="lib/ngCordova/dist/ng-cordova.min.js"></script>
    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/controllers.js"></script>
    <script src="js/services.js"></script>
    <script src="js/app.js"></script>
  </head>
  <body ng-app="app">

    <ion-nav-view>
    </ion-nav-view>
  </body>
</html>

Here Comes the Controller!
Building the controller with angular.js that goes to the backend and does all the work

Navigate to js folder and add the below code to it.

angular.module('app', ['ionic', 'ngCordova', 'app.controllers'])
.constant('FORECASTIO_KEY', 'YOUR-API_KEY')//add your key here.
.config(function ($stateProvider, $urlRouterProvider) {
    $stateProvider
      .state('app', {
      url: '/app',
      abstract: true,
      templateUrl: 'templates/menu.html',
      controller: 'AppCtrl'
    })

    .state('app.weather', {
      url: '/weather',
      views: {
        'menuContent': {
          templateUrl: 'templates/weather.html',
          controller: 'WeatherCtrl'
        }
      }
    });

    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/app/weather');
  })
.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

Creating the Controller.js which will be used to locate used using cordova geolocation and fetch the data from Forecast API.

Important Methods while working the geolocation:
getCurrentPosition(options)
timeout -Maximum length of time (milliseconds) that is allowed to pass
maximumAge-Accept a cached position whose age is no greater than the specified time in milliseconds
enableHighAccuracy-Provides a hint that the application needs the best possible results
Returns Object with user information, such as id, lastName

watchPosition(options)

timeout-Maximum length of time (milliseconds) that is allowed to pass
maximumAge-Accept a cached position whose age is no greater than the specified time in milliseconds
enableHighAccuracy-Provides a hint that the application needs the best possible results
Returns Object - watchID which is used to clear watch later on.
clearWatch(watchID)

watchID- Uses the watchID returned from watchPosition()

angular.module('app.controllers', ['app.services'])
  .controller('AppCtrl', function ($scope, $log, Settings) {
    $log.info('AppCtrl Created');
    $scope.settings = Settings;
  })
  .controller('WeatherCtrl', function ($scope, $log, $ionicLoading, $ionicPlatform, $cordovaGeolocation, Location, Weather, Settings) {
    $log.info('WeatherCtrl Created');
  
    $ionicPlatform.ready(function () {
    if (Location.lat == 0) {
      var posOptions = {
        timeout: 10000,
        enableHighAccuracy: false
      };
      $cordovaGeolocation
        .getCurrentPosition(posOptions)
        .then(function (position) {
          Location.lat = position.coords.latitude;
          Location.long = position.coords.longitude;
          getWeather();
      }, function (err) {
          // error
        });
    }
  });
  
    $scope.haveData = false;
    $ionicLoading.show({
      template: 'Loading...'
    });

    function getWeather() {
      $scope.haveData = false;
      $ionicLoading.show({
        template: 'Loading...'
      });
      Weather.getWeatherAtLocation(Location.lat, Location.long).then(function (resp) {
        $log.info(resp);
  $scope.longi=resp.data.longitude;
  $scope.lati=resp.data.latitude;
  
        $scope.current = resp.data.currently;
        $scope.highTemp = Math.ceil(resp.data.daily.data[0].temperatureMax);
        $scope.lowTemp = Math.floor(resp.data.daily.data[0].temperatureMin);
        $scope.currentTemp = Math.ceil($scope.current.temperature);
        $scope.haveData = true;
        $ionicLoading.hide();
        $scope.$broadcast('scroll.refreshComplete');
      }, function (error) {
        alert('Unable to get current conditions');
        $log.error(error);
      });
    }

    //getWeather();

    $scope.doRefresh = function () {
      getWeather(); 
    }
  
    $scope.$watch(function () {
      return Settings.units
    }, function (newVal, oldVal) {
      if (newVal !== oldVal) {
        getWeather();
      }
    });
  });


Setting Up and Calling the Forecast API through services.js
This will build the URL for forecast API with API key which we generated earlier and authenticate the URL to send request to API.
angular.module('app.services', [])
.factory('Settings', function () {
  var Settings = {
    units: 'us'
  };
  return Settings;
})
.factory('Location', function ()  {
    var Location = {
      lat: 0,
      long: 0
    };
    return Location;
})
.factory('Weather', function($http, $log, Settings, FORECASTIO_KEY) {
  $log.info('Weather Factory');
  var url = 'https://api.forecast.io/forecast/' + FORECASTIO_KEY + '/';

  return {
    getWeatherAtLocation: function(lat, lng) {
      return $http.jsonp(url + lat + ',' + lng + '?callback=JSON_CALLBACK&units='+Settings.units);
    }
  }
});
Run the Application Run your application by below command. Ionic serve





Whats next?

In the next post we may use Google Maps to geolocate and build and learn something exciting!

If you have some suggestion for post to be covered you are welcomed to contact!

Please share,like,tweet with other developers happy Coding!