In the previous Create Chat Application in Android using GCM we built the REST API. In this post we will build our android application. You can follow the previous Create Chat Application in Android using GCM from the link given below.
Create Chat App for Android using GCM Part 1
Our REST APIs are ready now its time to build our application. So lets begin.
Table of Contents
- 1 Create Chat Application in Android using GCM
- 1.1 Creating Android Studio Project
- 1.2 Adding Required Dependencies
- 1.3 Creating a class to store the constants
- 1.4 Creating a class to handle the network request and sharedpreferences
- 1.5 Creating Login Screen on MainActivity
- 1.6 Designing Chat Room
- 1.7 Creating RecyclerView Layout
- 1.8 Creating Message
- 1.9 Creating RecyclerView Adapter
- 1.10 Creating Class to Handle Push Notification
- 1.11 Adding Google Cloud Messaging
- 1.12 Creating Chat Room
- 1.13 Reveiwing AndroidManifest.xml
- 2 Create Chat Application in Android Source Code and Video
- 3 Final Words
Create Chat Application in Android using GCM
Creating Android Studio Project
- Open android studio and create a new android project. Select empty activity and next->next->finish.
- Once your project is loaded, you need to add google-services.json in app directory, which you have generated while creating the app in google developer console. If you don’t know what is it just go through the Android Push Notification Tutorial using GCM.
- Now inside your main package create 3 packages as shown in the image below (this step is optional you can keep all codes in the same package but for the sake of simplicity I have created these packages).
- I have created activities to store all the activities, in gcm we will store gcm classes, and all the rest would go inside helper. At this time your MainActivity is inside the main package to move it inside the package activities just drag it inside activities and it will be moved there.
Adding Required Dependencies
- We will be using many library dependencies for this project so this is my app level build.gradle file. You need to change your file according to this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "net.simplifiedcoding.simplifiedcodingchat" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' //Add these compile 'com.google.android.gms:play-services-gcm:8.3.0' compile 'com.android.support:design:23.0.1' compile 'com.android.support:recyclerview-v7:23.4.0' compile 'com.android.support:cardview-v7:23.4.0' compile 'com.android.volley:volley:1.0.0' } //Add this apply plugin: 'com.google.gms.google-services' |
- We have added play services which is required for GCM. We have also added support design, recyclerview, CardView and volley. We will be using all these libraries.
- Modify project level build.gradle file as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.0' //Add these two lines classpath 'com.google.gms:google-services:1.5.0-beta2' classpath 'com.android.tools.build:gradle:2.0.0-alpha6' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } |
Creating a class to store the constants
- Create two classes inside helper package. One is Constants.java to store all the required constants and other is URLs.java to store the API URLs.
- So create class named Constants.java in helper package and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package net.simplifiedcoding.simplifiedcodingchat.helper; /** * Created by Belal on 5/29/2016. */ public class Constants { public static final String SHARED_PREF_NAME = "simplifiedcodingchat"; public static final String USER_ID = "userid"; public static final String USER_NAME = "username"; public static final String USER_EMAIL= "useremail"; public static final String IS_LOGGED_IN= "is_logged_in"; public static final String PUSH_NOTIFICATION = "pushnotification"; public static final int NOTIFICATION_ID = 235; } |
- Now create URLs.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package net.simplifiedcoding.simplifiedcodingchat.helper; /** * Created by Belal on 5/29/2016. */ public class URLs { public static final String ROOT_URL = "http://192.168.94.1/SimplifiedCodingChat/v1/"; public static final String URL_REGISTER = ROOT_URL + "register"; public static final String URL_STORE_TOKEN = ROOT_URL + "storegcmtoken/"; public static final String URL_FETCH_MESSAGES = ROOT_URL + "messages"; public static final String URL_SEND_MESSAGE = ROOT_URL + "send"; } |
- In the first constant ROOT_URL you need to change the IP according to your system. To know what your IP is you can use ipconfig command in cmd (windows user).
- Now we will create a class. This class will handle the volley requests and sharedpreferences. This would be a singleton class and it will start on the app launch. So we also need to add it inside AndroidManifest.xml. So create a class named AppController.java inside helper package and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
package net.simplifiedcoding.simplifiedcodingchat.helper; import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.text.TextUtils; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import net.simplifiedcoding.simplifiedcodingchat.activities.MainActivity; //Class extending application public class AppController extends Application { //Getting tag it will be used for displaying log and it is optional public static final String TAG = AppController.class.getSimpleName(); //Creating a volley request queue object private RequestQueue mRequestQueue; //Creatting class object private static AppController mInstance; //Creating sharedpreferences object //We will store the user data in sharedpreferences private SharedPreferences sharedPreferences; //class instance will be initialized on app launch @Override public void onCreate() { super.onCreate(); mInstance = this; } //Public static method to get the instance of this class public static synchronized AppController getInstance() { return mInstance; } //This method would return the request queue public RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } //This method would add the requeust to the queue for execution public <T> void addToRequestQueue(Request<T> req) { //Setting a tag to the request req.setTag(TAG); //calling the method to get the request queue and adding the requeust the the queuue getRequestQueue().add(req); } //method to cancle the pending requests public void cancelPendingRequests(Object tag) { if (mRequestQueue != null) { mRequestQueue.cancelAll(tag); } } //Method to get sharedpreferences public SharedPreferences getSharedPreferences() { if (sharedPreferences == null) sharedPreferences = getSharedPreferences(Constants.SHARED_PREF_NAME, Context.MODE_PRIVATE); return sharedPreferences; } //This method will clear the sharedpreference //It will be called on logout public void logout() { SharedPreferences.Editor editor = getSharedPreferences().edit(); editor.clear(); editor.apply(); } //This method will store the user data on sharedpreferences //It will be called on login public void loginUser(int id, String name, String email) { SharedPreferences.Editor editor = getSharedPreferences().edit(); editor.putInt(Constants.USER_ID, id); editor.putString(Constants.USER_EMAIL, email); editor.putString(Constants.USER_NAME, name); editor.putBoolean(Constants.IS_LOGGED_IN, true); editor.apply(); } //This method will check whether the user is logged in or not public boolean isLoggedIn() { return getSharedPreferences().getBoolean(Constants.IS_LOGGED_IN, false); } //This method will return the user id of logged in user public int getUserId() { return getSharedPreferences().getInt(Constants.USER_ID, -1); } //This method will return the username of logged in user public String getUserName() { return getSharedPreferences().getString(Constants.USER_NAME, null); } } |
- Now add this class inside the application tag in your AndroidManifest.xml file.
1 2 3 4 5 6 7 8 9 |
<application android:name=".helper.AppController" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> |
Creating Login Screen on MainActivity
- We need a login screen to enter in the chat room. So inside activity_main.xml write the following xml code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?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=".activities.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:orientation="vertical"> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_password" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/editTextName" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Your Name" android:inputType="text" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/editTextEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Your Email" android:inputType="textEmailAddress" /> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/buttonEnter" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Enter Chat Room" /> </LinearLayout> </RelativeLayout> |
- The above code will generate the following UI.
- We are not using password, if the user is already registered it will be logged in or if user is not already registered it will be registered. So basicallly user need to provide his name and email to enter the Chat Room.
- Now inside MainActivity.java write the following code to add the login functionality.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
package net.simplifiedcoding.simplifiedcodingchat.activities; import android.app.Application; import android.app.ProgressDialog; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import com.android.volley.AuthFailureError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import net.simplifiedcoding.simplifiedcodingchat.R; import net.simplifiedcoding.simplifiedcodingchat.helper.AppController; import net.simplifiedcoding.simplifiedcodingchat.helper.URLs; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; public class MainActivity extends AppCompatActivity implements View.OnClickListener { //Views private EditText editTextEmail; private EditText editTextName; private Button buttonEnter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initiailizing views editTextEmail = (EditText) findViewById(R.id.editTextEmail); editTextName = (EditText) findViewById(R.id.editTextName); buttonEnter = (Button) findViewById(R.id.buttonEnter); buttonEnter.setOnClickListener(this); //If the user is already logged in //Starting chat room if(AppController.getInstance().isLoggedIn()){ finish(); startActivity(new Intent(this, ChatRoomActivity.class)); } } //Method to register user private void registerUser() { final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage("Entering chat room"); progressDialog.show(); final String name = editTextName.getText().toString().trim(); final String email = editTextEmail.getText().toString().trim(); StringRequest stringRequest = new StringRequest(Request.Method.POST, URLs.URL_REGISTER, new Response.Listener<String>() { @Override public void onResponse(String response) { progressDialog.hide(); try { JSONObject obj = new JSONObject(response); int id = obj.getInt("id"); String name = obj.getString("name"); String email = obj.getString("email"); //Login user AppController.getInstance().loginUser(id,name,email); //Starting chat room we need to create this activity startActivity(new Intent(MainActivity.this, ChatRoomActivity.class)); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<>(); params.put("name", name); params.put("email", email); return params; } }; AppController.getInstance().addToRequestQueue(stringRequest); } @Override protected void onResume() { super.onResume(); //Checking if user is logged in if(AppController.getInstance().isLoggedIn()){ finish(); startActivity(new Intent(this, ChatRoomActivity.class)); } } @Override public void onClick(View v) { registerUser(); } } |
- As you can see on login we are starting ChatRoomActivity so we need to create it as well.
Designing Chat Room
- Create a new empty activity named ChatRoomActivity and in the respective layout file write the following xml code (in my case it is activity_chat_room.xml).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?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:windowSoftInputMode="adjustPan|adjustResize" tools:context="net.simplifiedcoding.simplifiedcodingchat.activities.ChatRoomActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#2196F3" android:minHeight="?attr/actionBarSize"></android.support.v7.widget.Toolbar> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/toolbar" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="55dp" android:scrollbars="vertical"> </android.support.v7.widget.RecyclerView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:weightSum="4"> <EditText android:id="@+id/editTextMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:hint="Enter Message" android:lines="1" /> <Button android:id="@+id/buttonSend" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="3" android:text="Send" /> </LinearLayout> </RelativeLayout> </RelativeLayout> |
- The above code would generate the following UI.
- We have a RecyclerView to display the thread in the chat room. And at the bottom we have an EditText and a Button. Â We need to create a logout button to logout from the chat room.
- Create a xml file named menu.xml inside menu folder and write the following code.
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menuLogout" android:title="Logout" /> </menu> |
- We will code this activity at last.
Creating RecyclerView Layout
- For RecyclerView we will create two layouts. One layout for self message which will be displayed from right and other for other’s message which will be displayed from left.
- So first create chat_thread.xml inside layout folder and write the following code. This is for self message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<?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="wrap_content" android:orientation="vertical"> <!-- For self message --> <LinearLayout android:background="#91d49a" android:elevation="5dp" android:layout_gravity="right" android:layout_margin="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:padding="15dp" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/textViewMessage" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello how are you?" /> <TextView android:id="@+id/textViewTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Belal Khan, 2016-05-29 16:02:00?" android:textSize="12dp" /> </LinearLayout> </LinearLayout> </LinearLayout> |
- Now create chat_thread_other.xml and write the following code. This is for other’s messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:background="#d7d3f8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="3dp" android:elevation="5dp" android:orientation="vertical" android:padding="15dp"> <TextView android:id="@+id/textViewMessage" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello how are you?" /> <TextView android:id="@+id/textViewTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Belal Khan, 2016-05-29 16:02:00?" android:textSize="12dp" /> </LinearLayout> </RelativeLayout> |
- Both above codes are same only difference is the alignment and background color. In the message part we have two textviews, the first one is large to display the message and the second one is small to display name of the sender and time of the message.
- The above codes will generate the following UIs.
Creating Message
- Create a class named Message inside helper package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package net.simplifiedcoding.simplifiedcodingchat.helper; import java.io.Serializable; /** * Created by Belal on 5/29/2016. */ public class Message { private int usersId; private String message; private String sentAt; private String name; public Message(int usersId, String message, String sentAt, String name) { this.usersId = usersId; this.message = message; this.sentAt = sentAt; this.name = name; } public int getUsersId() { return usersId; } public String getMessage() { return message; } public String getSentAt() { return sentAt; } public String getName() { return name; } } |
- I have only generated a Constructor and Getters in the above class. You can do it easily by right click->generate in the code window. This class will used to store the messages of the thread.
- Now for our RecyclerView we need to create our Adapter that will show the Thread. I have also covered a recyclerview tutorial you can check to understand it better.
Creating RecyclerView Adapter
- Create a class named ThreadAdapter and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package net.simplifiedcoding.simplifiedcodingchat.helper; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import net.simplifiedcoding.simplifiedcodingchat.R; import java.util.ArrayList; /** * Created by Belal on 5/29/2016. */ //Class extending RecyclerviewAdapter public class ThreadAdapter extends RecyclerView.Adapter<ThreadAdapter.ViewHolder> { //user id private int userId; private Context context; //Tag for tracking self message private int SELF = 786; //ArrayList of messages object containing all the messages in the thread private ArrayList<Message> messages; //Constructor public ThreadAdapter(Context context, ArrayList<Message> messages, int userId){ this.userId = userId; this.messages = messages; this.context = context; } //IN this method we are tracking the self message @Override public int getItemViewType(int position) { //getting message object of current position Message message = messages.get(position); //If its owner id is equals to the logged in user id if (message.getUsersId() == userId) { //Returning self return SELF; } //else returning position return position; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //Creating view View itemView; //if view type is self if (viewType == SELF) { //Inflating the layout self itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.chat_thread, parent, false); } else { //else inflating the layout others itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.chat_thread_other, parent, false); } //returing the view return new ViewHolder(itemView); } @Override public void onBindViewHolder(ViewHolder holder, int position) { //Adding messages to the views Message message = messages.get(position); holder.textViewMessage.setText(message.getMessage()); holder.textViewTime.setText(message.getName()+", "+message.getSentAt()); } @Override public int getItemCount() { return messages.size(); } //Initializing views public class ViewHolder extends RecyclerView.ViewHolder { public TextView textViewMessage; public TextView textViewTime; public ViewHolder(View itemView) { super(itemView); textViewMessage = (TextView) itemView.findViewById(R.id.textViewMessage); textViewTime = (TextView) itemView.findViewById(R.id.textViewTime); } } } |
- Now we will create our Notification Handler.
Creating Class to Handle Push Notification
- Create a class NotificationHandler and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
package net.simplifiedcoding.simplifiedcodingchat.helper; import android.app.ActivityManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Build; import android.support.v4.app.NotificationCompat; import net.simplifiedcoding.simplifiedcodingchat.R; import net.simplifiedcoding.simplifiedcodingchat.activities.ChatRoomActivity; import java.util.List; /** * Created by Ravi on 01/06/15. */ public class NotificationHandler { private Context mContext; public NotificationHandler(Context mContext) { this.mContext = mContext; } //This method would display the notification public void showNotificationMessage(final String title, final String message) { NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext); builder.setSmallIcon(R.mipmap.ic_launcher); Intent intent = new Intent(mContext, ChatRoomActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0); builder.setContentIntent(pendingIntent); builder.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher)); builder.setContentTitle(title); builder.setContentText(message); builder.setAutoCancel(true); NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE); notificationManager.notify(Constants.NOTIFICATION_ID, builder.build()); } //This method will check whether the app is in background or not public static boolean isAppIsInBackground(Context context) { boolean isInBackground = true; ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) { List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { for (String activeProcess : processInfo.pkgList) { if (activeProcess.equals(context.getPackageName())) { isInBackground = false; } } } } } else { List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); ComponentName componentInfo = taskInfo.get(0).topActivity; if (componentInfo.getPackageName().equals(context.getPackageName())) { isInBackground = false; } } return isInBackground; } } |
Adding Google Cloud Messaging
- For google cloud messaging we have to create three classes. We have did all these in previous GCM tutorial. So I am only pasting the codes here. First create a class named GCMRegistrationIntentService inside gcm package and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
package net.simplifiedcoding.simplifiedcodingchat.gcm; import android.app.IntentService; import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.android.volley.AuthFailureError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import net.simplifiedcoding.simplifiedcodingchat.R; import net.simplifiedcoding.simplifiedcodingchat.helper.AppController; import net.simplifiedcoding.simplifiedcodingchat.helper.Constants; import net.simplifiedcoding.simplifiedcodingchat.helper.URLs; import java.util.HashMap; import java.util.Map; /** * Created by Belal on 4/15/2016. */ public class GCMRegistrationIntentService extends IntentService { public static final String REGISTRATION_SUCCESS = "RegistrationSuccess"; public static final String REGISTRATION_ERROR = "RegistrationError"; public static final String REGISTRATION_TOKEN_SENT = "RegistrationTokenSent"; public GCMRegistrationIntentService() { super(""); } @Override protected void onHandleIntent(Intent intent) { registerGCM(); } private void registerGCM() { Intent registrationComplete = null; String token = null; try { InstanceID instanceID = InstanceID.getInstance(getApplicationContext()); token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); Log.w("GCMRegIntentService", "token:" + token); sendRegistrationTokenToServer(token); registrationComplete = new Intent(REGISTRATION_SUCCESS); registrationComplete.putExtra("token", token); } catch (Exception e) { Log.w("GCMRegIntentService", "Registration error"); registrationComplete = new Intent(REGISTRATION_ERROR); } LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete); } private void sendRegistrationTokenToServer(final String token) { //Getting the user id from shared preferences //We are storing gcm token for the user in our mysql database final int id = AppController.getInstance().getUserId(); StringRequest stringRequest = new StringRequest(Request.Method.PUT, URLs.URL_STORE_TOKEN + id, new Response.Listener<String>() { @Override public void onResponse(String s) { Intent registrationComplete = new Intent(REGISTRATION_TOKEN_SENT); LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(registrationComplete); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } }) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<>(); params.put("token", token); return params; } }; AppController.getInstance().addToRequestQueue(stringRequest); } } |
- Now create class GCMTokenRefreshListenerService inside gcm package and write the following codes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package net.simplifiedcoding.simplifiedcodingchat.gcm; import android.content.Intent; import com.google.android.gms.iid.InstanceIDListenerService; /** * Created by Belal on 4/15/2016. */ public class GCMTokenRefreshListenerService extends InstanceIDListenerService { //If the token is changed registering the device again @Override public void onTokenRefresh() { Intent intent = new Intent(this, GCMRegistrationIntentService.class); startService(intent); } } |
- The last class we need to create in gcm package is GCMPushReceiverService. This class will actually receive the messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package net.simplifiedcoding.simplifiedcodingchat.gcm; import android.app.ActivityManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.NotificationCompat; import android.util.Log; import com.google.android.gms.gcm.GcmListenerService; import net.simplifiedcoding.simplifiedcodingchat.R; import net.simplifiedcoding.simplifiedcodingchat.helper.Constants; import net.simplifiedcoding.simplifiedcodingchat.helper.Message; import net.simplifiedcoding.simplifiedcodingchat.helper.NotificationHandler; import java.util.List; /** * Created by Belal on 4/15/2016. */ public class GCMPushReceiverService extends GcmListenerService { @Override public void onMessageReceived(String from, Bundle data) { String message = data.getString("message"); String title = data.getString("title"); String id = data.getString("id"); sendNotification(message, title, id); } private void sendNotification(String message, String title, String id) { //Creating a broadcast intent Intent pushNotification = new Intent(Constants.PUSH_NOTIFICATION); //Adding notification data to the intent pushNotification.putExtra("message", message); pushNotification.putExtra("name", title); pushNotification.putExtra("id", id); //We will create this class to handle notifications NotificationHandler notificationHandler = new NotificationHandler(getApplicationContext()); //If the app is in foreground if (!NotificationHandler.isAppIsInBackground(getApplicationContext())) { //Sending a broadcast to the chatroom to add the new message LocalBroadcastManager.getInstance(this).sendBroadcast(pushNotification); } else { //If app is in foreground displaying push notification notificationHandler.showNotificationMessage(title, message); } } } |
Creating Chat Room
- The final step is we will code the ChatRoomActivity. So come inside ChatRoomActivity.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
package net.simplifiedcoding.simplifiedcodingchat.activities; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.android.volley.AuthFailureError; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.RetryPolicy; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import net.simplifiedcoding.simplifiedcodingchat.R; import net.simplifiedcoding.simplifiedcodingchat.gcm.GCMRegistrationIntentService; import net.simplifiedcoding.simplifiedcodingchat.helper.AppController; import net.simplifiedcoding.simplifiedcodingchat.helper.Constants; import net.simplifiedcoding.simplifiedcodingchat.helper.Message; import net.simplifiedcoding.simplifiedcodingchat.helper.NotificationHandler; import net.simplifiedcoding.simplifiedcodingchat.helper.ThreadAdapter; import net.simplifiedcoding.simplifiedcodingchat.helper.URLs; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; public class ChatRoomActivity extends AppCompatActivity implements View.OnClickListener { //Broadcast receiver to receive broadcasts private BroadcastReceiver mRegistrationBroadcastReceiver; //Progress dialog private ProgressDialog dialog; //Recyclerview objects private RecyclerView recyclerView; private RecyclerView.LayoutManager layoutManager; private RecyclerView.Adapter adapter; //ArrayList of messages to store the thread messages private ArrayList<Message> messages; //Button to send new message on the thread private Button buttonSend; //EditText to send new message on the thread private EditText editTextMessage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_chat_room); //Adding toolbar to activity Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(AppController.getInstance().getUserName()); setSupportActionBar(toolbar); //Displaying dialog while the chat room is being ready dialog = new ProgressDialog(this); dialog.setMessage("Opening chat room"); dialog.show(); //Initializing recyclerview recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setHasFixedSize(true); layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); //Initializing message arraylist messages = new ArrayList<>(); //Calling function to fetch the existing messages on the thread fetchMessages(); //initializing button and edittext buttonSend = (Button) findViewById(R.id.buttonSend); editTextMessage = (EditText) findViewById(R.id.editTextMessage); //Adding listener to button buttonSend.setOnClickListener(this); //Creating broadcast receiver mRegistrationBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(GCMRegistrationIntentService.REGISTRATION_SUCCESS)) { //When gcm registration is success do something here if you need } else if (intent.getAction().equals(GCMRegistrationIntentService.REGISTRATION_TOKEN_SENT)) { //When the registration token is sent to ther server displaying a toast Toast.makeText(getApplicationContext(), "Chatroom Ready...", Toast.LENGTH_SHORT).show(); //When we received a notification when the app is in foreground } else if (intent.getAction().equals(Constants.PUSH_NOTIFICATION)) { //Getting message data String name = intent.getStringExtra("name"); String message = intent.getStringExtra("message"); String id = intent.getStringExtra("id"); //processing the message to add it in current thread processMessage(name, message, id); } } }; //if the google play service is not in the device app won't work int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext()); if (ConnectionResult.SUCCESS != resultCode) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { Toast.makeText(getApplicationContext(), "Google Play Service is not install/enabled in this device!", Toast.LENGTH_LONG).show(); GooglePlayServicesUtil.showErrorNotification(resultCode, getApplicationContext()); } else { Toast.makeText(getApplicationContext(), "This device does not support for Google Play Service!", Toast.LENGTH_LONG).show(); } } else { Intent itent = new Intent(this, GCMRegistrationIntentService.class); startService(itent); } } //This method will fetch all the messages of the thread private void fetchMessages() { StringRequest stringRequest = new StringRequest(Request.Method.GET, URLs.URL_FETCH_MESSAGES, new Response.Listener<String>() { @Override public void onResponse(String response) { dialog.dismiss(); try { JSONObject res = new JSONObject(response); JSONArray thread = res.getJSONArray("messages"); for (int i = 0; i < thread.length(); i++) { JSONObject obj = thread.getJSONObject(i); int userId = obj.getInt("userid"); String message = obj.getString("message"); String name = obj.getString("name"); String sentAt = obj.getString("sentat"); Message messagObject = new Message(userId, message, sentAt, name); messages.add(messagObject); } adapter = new ThreadAdapter(ChatRoomActivity.this, messages, AppController.getInstance().getUserId()); recyclerView.setAdapter(adapter); scrollToBottom(); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); AppController.getInstance().addToRequestQueue(stringRequest); } //Processing message to add on the thread private void processMessage(String name, String message, String id) { Message m = new Message(Integer.parseInt(id), message, getTimeStamp(), name); messages.add(m); scrollToBottom(); } //This method will send the new message to the thread private void sendMessage() { final String message = editTextMessage.getText().toString().trim(); if (message.equalsIgnoreCase("")) return; int userId = AppController.getInstance().getUserId(); String name = AppController.getInstance().getUserName(); String sentAt = getTimeStamp(); Message m = new Message(userId, message, sentAt, name); messages.add(m); adapter.notifyDataSetChanged(); scrollToBottom(); editTextMessage.setText(""); StringRequest stringRequest = new StringRequest(Request.Method.POST, URLs.URL_SEND_MESSAGE, new Response.Listener<String>() { @Override public void onResponse(String response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<>(); params.put("id", String.valueOf(AppController.getInstance().getUserId())); params.put("message", message); params.put("name", AppController.getInstance().getUserName()); return params; } }; //Disabling retry to prevent duplicate messages int socketTimeout = 0; RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); stringRequest.setRetryPolicy(policy); AppController.getInstance().addToRequestQueue(stringRequest); } //method to scroll the recyclerview to bottom private void scrollToBottom() { adapter.notifyDataSetChanged(); if (adapter.getItemCount() > 1) recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null, adapter.getItemCount() - 1); } //This method will return current timestamp public static String getTimeStamp() { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return format.format(new Date()); } //Registering broadcast receivers @Override protected void onResume() { super.onResume(); Log.w("MainActivity", "onResume"); LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(GCMRegistrationIntentService.REGISTRATION_SUCCESS)); LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(GCMRegistrationIntentService.REGISTRATION_ERROR)); LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(GCMRegistrationIntentService.REGISTRATION_TOKEN_SENT)); LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(Constants.PUSH_NOTIFICATION)); } //Unregistering receivers @Override protected void onPause() { super.onPause(); Log.w("MainActivity", "onPause"); LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver); } //Sending message onclick @Override public void onClick(View v) { if (v == buttonSend) sendMessage(); } //Creating option menu to add logout feature @Override public boolean onCreateOptionsMenu(Menu menu) { //Adding our menu to toolbar getMenuInflater().inflate(R.menu.menu, menu); return true; } //Adding logout option here @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.menuLogout) { AppController.getInstance().logout(); finish(); startActivity(new Intent(this, MainActivity.class)); } return super.onOptionsItemSelected(item); } } |
- The coding is done now.
Reveiwing AndroidManifest.xml
- Inside AndroidManifest.xml we have to define the GCM Services and some permissions. So here is my AndroidManifest.xml. Review your manifest according to this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.simplifiedcoding.simplifiedcodingchat"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <permission android:name="net.simplifiedcoding.androidgcm.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="net.simplifiedcoding.androidgcm.permission.C2D_MESSAGE" /> <application android:name=".helper.AppController" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".activities.MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- GCM Receiver --> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="com.gnirt69.gcmexample" /> </intent-filter> </receiver> <!-- GCM Receiver Service --> <service android:name=".gcm.GCMPushReceiverService" android:exported="false"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> </intent-filter> </service> <!-- GCM Registration Intent Service --> <service android:name=".gcm.GCMRegistrationIntentService" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.iid.InstanceID" /> </intent-filter> </service> <activity android:name=".activities.ChatRoomActivity"></activity> </application> </manifest> |
- Thats it now run your application and you will see the following output. Just run your app twice using two different emulators.
Create Chat Application in Android Source Code and Video
- You can check this video to see the actual output of the application.
- You can download the working apk that I built for this Create Chat Application in Android Tutorial.
- You can also download my source code from GitHub. Just go to the link given below.
[sociallocker id=1372] Download Chat App Source Code [/sociallocker]
Final Words
So thats all for this Create Chat Application in Android using GCM friends.  This post was very lengthy so follow it carefully if you want to make it work. If you are facing trouble try with my source code. And you can also get my working APK of this Create Chat Application in Android Tutorial.
And please do like and share this post if you find it helpful. And don’t hesitate to ask with your comments if having any confusions or doubts. Thank You 🙂