Tag

android

Browsing

In this post, we gonna talk about firebase in-app messaging in android.

Overview

Firebase In-App Messaging helps you engage your app’s active users by sending them targeted, contextual message. Encourage them to use key app features. For example, you can send an in-pp message to get users to subscribe, watch a video, complete a level, or buy an items. I’m sure you guys familiar. If you had android app you often get in-app message.

You can customized message as card, banners, models, or images. You can also set up a trigger so that they appear exactly when they’d benefit. It is very similar to cloud messaging, except for messages sent to the app, not a device. So if you talk about cloud messaging.

Uses of In-App Messaging

You should use Firebase In-App Messaging to encourage exploration and discovery. Highlight a sale or coupon in your eCommerce app. Give clues or tips in your game. Prompt a like or share in your social media app. These types of things, So kind of different use case or messaging.

Key Capabilities of In App Messaging

  • Send relevant, engaging messages
  • Sends messages when they are most needed, while users are actually in your app.
  • Promote a big sale when users visit your In-app store. etc.
  • Target messages by audience or behavior.
    • Work with Analytics and Predictions to give you tools to deliver the message to the user you would most like to reach
    • Send messages based on user’s demographics, past behaviors, or even predictions of their future behaviors.
  • Create flexible, custom alerts –
    • You can create a flexible, custom alert and have the ability to customize your style appearance display triggers and content.
    • These will help you do everything from sending promotional offers to getting users to update a new version of the app.

Implementations Step

Now I want to show you, how you can setup and configure to use In App Messaging for Firebase.

  • Connect your app – Start by adding Firebase to your app in the firebase console
  • Integrates the SDK – Add the firebase In-App Messaging SDK to your app via Gradle.
  • Create your first message – Visit the Firebase console to write, customize, and target your first message.

Connect your app

Let’s open android studio, and create a simple project. For now It doesn’t have anything extra on it. It just MainActivity that’s empty.

The first thing we’re gonna to do we’re going to add this project to Firebase. Fo doing that we need to know is the package name, In this example, I’m using com.firebaseinappmessaging .

Now let’s go to the firebase console and go to the project. Then just add the app and go through the steps the adding an app by entering package name. Still, you are facing any issue, follow this article.

Now you have to download json file, So go to settings and download on google-service.json file in app folder.

Integrates the SDK

Now back to the Android Studio, Now we have to update Gradle file. So go to the project build.gradle file and add these dependencies. Something like below

    // Import the Firebase BoM
    implementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.5'
    implementation 'com.google.firebase:firebase-analytics-ktx:18.0.2'

Let’s sync the project, That all about configuration. For sending a test message you have to need AppInstaceId, Basically firebase console allow us send messaging to specific device.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="16dp"
        android:text="@string/warning_fresh_install"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/instanceIdText"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/instanceIdText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:text="@string/warning_fresh_install"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2"
        tools:text="Device Instance ID: 1234" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/eventTriggerButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@color/purple_200"
        android:text="@string/button_text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.firebaseinappmessaging

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.google.android.gms.tasks.OnSuccessListener
import com.google.firebase.inappmessaging.FirebaseInAppMessaging
import com.google.firebase.inappmessaging.display.ktx.FirebaseInAppMessagingDisplayKtxRegistrar
import com.google.firebase.installations.FirebaseInstallations
import com.google.firebase.ktx.Firebase
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private lateinit var firebaseIam: FirebaseInAppMessaging
    //private lateinit var firebaseAnalytics: FirebaseAnalytics
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // firebaseAnalytics = FirebaseAnalytics.getInstance(this)
        firebaseIam = FirebaseInAppMessaging.getInstance()

        firebaseIam.isAutomaticDataCollectionEnabled = true
        firebaseIam.setMessagesSuppressed(false)

        eventTriggerButton.setOnClickListener { view ->
            //firebaseAnalytics.logEvent("engagement_party", Bundle())
            firebaseIam.triggerEvent("engagement_party")
        }

        // Get and display/log the Instance ID
        FirebaseInstallations.getInstance().id.addOnSuccessListener {
            instanceIdText.text = getString(R.string.instance_id_fmt, it)
            Log.d(TAG, "InstanceId: $it")
        }
//            .addOnSuccessListener(object : OnSuccessListener<InstanceIdResult> {
//                override fun onSuccess(instanceIdResult: InstanceIdResult) {
//                    val instanceId = instanceIdResult.id
//                    instanceIdText.text = getString(R.string.instance_id_fmt, instanceId)
//                    Log.d(TAG, "InstanceId: $instanceId")
//                }
//            })

        addClickListener()
    }
    private fun addClickListener() {
        val listener = InAppMessageClickListener()
        firebaseIam.addClickListener(listener)
    }

    private fun suppressMessages() {
        firebaseIam.setMessagesSuppressed(true)
    }

    private fun enableDataCollection() {
        // Only needed if firebase_inapp_messaging_auto_data_collection_enabled is set to
        // false in AndroidManifest.xml
        firebaseIam.isAutomaticDataCollectionEnabled = true
    }

    companion object {

        private const val TAG = "FirebaseInAppMessaging"
    }
}
package com.example.firebaseinappmessaging

import android.util.Log
import com.google.firebase.inappmessaging.FirebaseInAppMessagingClickListener
import com.google.firebase.inappmessaging.model.Action
import com.google.firebase.inappmessaging.model.InAppMessage


class InAppMessageClickListener : FirebaseInAppMessagingClickListener {

    override fun messageClicked(inAppMessage: InAppMessage, action: Action) {
        // Determine which URL the user clicked
        val url = action.actionUrl

        // Get general information about the campaign
        val metadata = inAppMessage.campaignMetadata

        Log.d("AppTest", "URL is: " + url)
        Log.d("AppTest", "Meta Data: " + metadata)
    }
}

Hello folks! In this article, We’ll learn the best practices of SharedPreferences in Android(Kotlin). I’ll show you, how we can store and retrieve values in SharedPreferences. For better understanding, I’ll create an android SharedPreferences example (Sample app) and take an example of Writing and Reading Values in SharedPreferences. So let started

What are SharePreferences?

SharedPreferences is an android API that stores app data using key-value pairs and provides simple methods to read and write them.

Android system provides several options for you to save your data. These options are App-specific storage, Shared storage, Preferences, Databases. SharePreferences comes in Preference. It offers a framework to save private, primitive data in key-value pairs.

Why SharePreferences?

They’re mostly used to store user states when it comes to user settings or keeps a piece of small information(User details etc.) without needing storage permission. As per my opinion, you should store small primitive value in Preferences such as booleans, ints, longs, floats, and strings.

Modes in SharePreferences

SharedPreferences have different MODE these are below

1. Create a android application

Let take an example, open android studio, and create a new project. Now create a interface named is IPreferenceHelper. In this Interface we are defining some getter setter for storing or retrieving preference value. such as ApiKey and UserId etc.

package com.sharedpreferencesexample

interface IPreferenceHelper {

    fun setApiKey(apiKey: String)

    fun getApiKey(): String

    fun setUserId(userId: String)

    fun getUserId(): String

    fun clearPrefs()

}

2. Create a singleton class for managing Preferences

Ideally SharedPreferences store the app level value, So the SharedPreferences instance should be single threw out the app. It should be a singleton. Let create a Singletone class named is PreferenceManager and implement IPreferenceHelper. Just like below

open class PreferenceManager constructor(context: Context) : IPreferenceHelper {
    private val PREFS_NAME = "SharedPreferenceDemo"
    private var preferences: SharedPreferences

    init {
        preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    }

    override fun setApiKey(apiKey: String) {
        preferences[API_KEY] = apiKey
    }

    override fun getApiKey(): String {
        return preferences[API_KEY] ?: ""
    }

    override fun setUserId(userId: String) {
        preferences[USER_ID] = userId
    }

    override fun getUserId(): String {
        return preferences[USER_ID] ?: ""
    }

    override fun clearPrefs() {
        preferences.edit().clear().apply()
    }

    companion object {
        const val API_KEY = "api_key"
        const val USER_ID = "user_id"
    }
}

3. Write into your SharedPreferences

Normally, writing into SharedPreferences is simple. But I’m going to write a Kotlin extension, This extension is make writing very simple and reduce boilerplate code.

/**
 * SharedPreferences extension function, to listen the edit() and apply() fun calls
 * on every SharedPreferences operation.
 */
private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
    val editor = this.edit()
    operation(editor)
    editor.apply()
}

/**
 * puts a key value pair in shared prefs if doesn't exists, otherwise updates value on given [key]
 */
private operator fun SharedPreferences.set(key: String, value: Any?) {
    when (value) {
        is String? -> edit { it.putString(key, value) }
        is Int -> edit { it.putInt(key, value) }
        is Boolean -> edit { it.putBoolean(key, value) }
        is Float -> edit { it.putFloat(key, value) }
        is Long -> edit { it.putLong(key, value) }
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

4.  Read from SharedPreferences

Reading a value from SharedPreferences is also straightforward. I’m going to write another useful extension that provides more control over retrieving a value from SharedPreferences. Let check below code

/**
 * finds value on given key.
 * [T] is the type of value
 * @param defaultValue optional default value - will take null for strings, false for bool and -1 for numeric values if [defaultValue] is not specified
 */
private inline operator fun <reified T : Any> SharedPreferences.get(
    key: String,
    defaultValue: T? = null
): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

5. Finally your PreferenceManager class look like below

package com.sharedpreferencesexample

import android.content.Context
import android.content.SharedPreferences

open class PreferenceManager constructor(context: Context) : IPreferenceHelper {
    private val PREFS_NAME = "SharedPreferenceDemo"
    private var preferences: SharedPreferences

    init {
        preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    }

    override fun setApiKey(apiKey: String) {
        preferences[API_KEY] = apiKey
    }

    override fun getApiKey(): String {
        return preferences[API_KEY] ?: ""
    }

    override fun setUserId(userId: String) {
        preferences[USER_ID] = userId
    }

    override fun getUserId(): String {
        return preferences[USER_ID] ?: ""
    }

    override fun clearPrefs() {
        preferences.edit().clear().apply()
    }

    companion object {
        const val API_KEY = "api_key"
        const val USER_ID = "user_id"
    }
}


/**
 * SharedPreferences extension function, to listen the edit() and apply() fun calls
 * on every SharedPreferences operation.
 */
private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
    val editor = this.edit()
    operation(editor)
    editor.apply()
}

/**
 * puts a key value pair in shared prefs if doesn't exists, otherwise updates value on given [key]
 */
private operator fun SharedPreferences.set(key: String, value: Any?) {
    when (value) {
        is String? -> edit { it.putString(key, value) }
        is Int -> edit { it.putInt(key, value) }
        is Boolean -> edit { it.putBoolean(key, value) }
        is Float -> edit { it.putFloat(key, value) }
        is Long -> edit { it.putLong(key, value) }
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

/**
 * finds value on given key.
 * [T] is the type of value
 * @param defaultValue optional default value - will take null for strings, false for bool and -1 for numeric values if [defaultValue] is not specified
 */
private inline operator fun <reified T : Any> SharedPreferences.get(
    key: String,
    defaultValue: T? = null
): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

6. Access PreferenceManager into your presentation layers

Yes, Now your PreferenceManager class is ready for use. You can initialize PreferenceManager class into your ViewModel and Activity/Fragment, Make sure the context should be applicationContext.

7. Now open the activity_main.xml and paste below code.

For making interesting example I have added two edit text and one button in this layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Hello World!" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="User Id"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="API Key"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Show Preference Data"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText2" />

</androidx.constraintlayout.widget.ConstraintLayout>

8. Let access PreferenceManager class in your source file

Let’s check the below code This way you can easily read and write the value in SharePreferences

package com.sharedpreferencesexample

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val preferenceHelper: IPreferenceHelper by lazy { PreferenceManager(applicationContext) }

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // display saved data
        textView.text =
            " API Key - > ${preferenceHelper.getApiKey()} \n User Id -> ${preferenceHelper.getUserId()}"
        button.setOnClickListener {
            // Update data in SharedPreference
            preferenceHelper.setApiKey(editText.text.toString())
            preferenceHelper.setUserId(editText2.text.toString())
            // display saved data
            textView.text =
                " API Key - > ${preferenceHelper.getApiKey()} \n User Id -> ${preferenceHelper.getUserId()}"
        }

    }
}

7. Build & Test

Let run the app, in a movement your app will up and run, Now enter few value these EditText and click button. The value will display on TextView. This way you can read and write small amount of data in key-value pairs!

Conclusion

In this android SharedPreferences example, we’ll learn how we can save and retrieve value in SharedPreferences. I try to follow best practices for android development. Still, you want to improve… Most Welcome

Follow this article to detect network change in Android!

In this blog, I’ll show how to check internet connection in android programmatically. While we are developing a professional app, you may need to check internet available or not. For example, while you are calling APIs you may need to check internet connection several times in an app. In this example, we’ll learn how we can check internet connections any place and anywhere.

I’m going to create a demo application, This app will automatically detect the internet changes using an internet connection listener. For the demonstration, I’ll create a sample app that app will capable of continuously check internet connection with android. So let started.

Create Android Project

Let move to Android Studio, and create a fresh project with some default template. We are going to use java 1.8 stuff in our project so lets set java version in app build.gradle file

  compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }  

Add ACCESS_NETWORK_STATE permission in Manifest

For detecting network permission we required some permission so let open the AndroidManifest and add below permission.

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Write a ConnectivityProvider interface

I’m going to write complete solution for check internet connection for pre and post LOLLIPOP devices solution in a single interface. Please have a look

package com.detectnetworkchange.connectivity.base

import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.ConnectivityProviderImpl
import com.detectnetworkchange.connectivity.ConnectivityProviderLegacyImpl

interface ConnectivityProvider {

    fun subscribe()

    fun getNetworkState(): NetworkState

    @Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
    sealed class NetworkState {
        object NotConnectedState : NetworkState()

        sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {

            @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
            data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
                    capabilities.hasCapability(NET_CAPABILITY_INTERNET)
            )

            @Suppress("DEPRECATION")
            data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
                    networkInfo.isConnectedOrConnecting
            )
        }
    }

    companion object {
        @JvmStatic
        fun createProvider(context: Context): ConnectivityProvider {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                ConnectivityProviderImpl(cm)
            } else {
                ConnectivityProviderLegacyImpl(context, cm)
            }
        }
    }
}

Extend ConnectivityProvider interface

Now create a abstract class named ConnectivityProviderBaseImpl which extends ConnectivityProvider interface, like below

package com.detectnetworkchange.connectivity.base

import com.detectnetworkchange.CONNECTED
import com.detectnetworkchange.DISCONNECTED
import com.detectnetworkchange.NetWorkManger
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState

abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
    override fun subscribe() {
        subscribeListener()
        //init status
        dispatchChange(getNetworkState())
    }

    protected fun dispatchChange(state: NetworkState) {
        val networkState = if (state.hasInternet()) CONNECTED else DISCONNECTED
        if (networkState != NetWorkManger.networkStatus.value) {
            NetWorkManger.networkStatus.postValue(networkState)
        }
    }

    private fun NetworkState.hasInternet(): Boolean {
        return (this as? NetworkState.ConnectedState)?.hasInternet == true
    }

    protected abstract fun subscribeListener()
}

Write a actual implementation of ConnectivityProvider

package com.detectnetworkchange.connectivity

import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.Connected
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
        ConnectivityProviderBaseImpl() {

    private val networkCallback = ConnectivityCallback()

    override fun subscribeListener() {
        cm.registerDefaultNetworkCallback(networkCallback)
    }

    override fun getNetworkState(): NetworkState {
        val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
        return if (capabilities != null) {
            Connected(capabilities)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityCallback : NetworkCallback() {

        override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
            dispatchChange(Connected(capabilities))
        }

        override fun onLost(network: Network) {
            dispatchChange(NotConnectedState)
        }
    }
}
package com.detectnetworkchange.connectivity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NETWORK_INFO
import android.net.NetworkInfo
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.ConnectedLegacy
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@Suppress("DEPRECATION")
class ConnectivityProviderLegacyImpl(
        private val context: Context,
        private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {

    private val receiver = ConnectivityReceiver()

    override fun subscribeListener() {
        context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
    }

    override fun getNetworkState(): NetworkState {
        val activeNetworkInfo = cm.activeNetworkInfo
        return if (activeNetworkInfo != null) {
            ConnectedLegacy(activeNetworkInfo)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityReceiver : BroadcastReceiver() {
        override fun onReceive(c: Context, intent: Intent) {
            // on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
            val networkInfo = cm.activeNetworkInfo
            val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
            // a set of dirty workarounds
            val state: NetworkState =
                    if (networkInfo?.isConnectedOrConnecting == true) {
                        ConnectedLegacy(networkInfo)
                    } else if (networkInfo != null && fallbackNetworkInfo != null &&
                            networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
                    ) {
                        ConnectedLegacy(fallbackNetworkInfo)
                    } else {
                        val state = networkInfo ?: fallbackNetworkInfo
                        if (state != null) ConnectedLegacy(state) else NotConnectedState
                    }
            dispatchChange(state)
        }
    }
}

Let’s create a NetWorkManger class

In this class we have one live data object which hold the internet state, It can be accessible threw out the application.

package com.detectnetworkchange

import androidx.lifecycle.MutableLiveData


const val DISCONNECTED = 0
const val CONNECTED = 1

object NetWorkManger {
    val networkStatus = MutableLiveData<Int>()

    fun isDisconnected(): Boolean {
        return networkStatus.value == DISCONNECTED
    }
}

class NetWorkDisconnectedException : Throwable()

Finally subscribe the ConnectivityProvider instance in application class

package com.detectnetworkchange

import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Process
import com.detectnetworkchange.connectivity.base.ConnectivityProvider

class DetectNetworkChangeDemoApp : Application() {
    override fun onCreate() {
        super.onCreate()
        if (isMainProcess()) {
            ConnectivityProvider.createProvider(this).subscribe()
        }
    }

    // your package name is the same with your main process name
    private fun isMainProcess(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            packageName == getProcessName()
        } else packageName == getProcessNameLegacy()
    }

    // you can use this method to get current process name, you will get
    private fun getProcessNameLegacy(): String? {
        val mypid = Process.myPid()
        val manager =
            getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val infos = manager.runningAppProcesses
        for (info in infos) {
            if (info.pid == mypid) {
                return info.processName
            }
        }
        // may never return null
        return null
    }
}

This way you can observe network changes

package com.detectnetworkchange

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Suppose you want to check network status before calling APIs then use this way
        Log.d("MainActivity","Network connected "+!NetWorkManger.isDisconnected())
        // if you want observe network status then use this way
        NetWorkManger.networkStatus.observe(this, Observer {
            when (it) {
                CONNECTED -> status.text ="Internet is connected"
                DISCONNECTED -> status.text ="Internet disconnected"
            }
        })


    }
}

In this post, I’ll show you how we can write double tap listener in android. For doing that I’ll create one demo project and will implement it. So Lets started

Write a DoubleClickListener

Create an abstract class named is DoubleClickListener which extends native View.OnClickListener. Technically nothing we are doing. Simply observe the normal click If the second click happens with delta time then we triggered onDoubleClick event. Just like below

package com.doubletaplistener

import android.view.View

abstract class DoubleClickListener : View.OnClickListener {
    private var lastClickTime: Long = 0
    override fun onClick(v: View) {
        val clickTime = System.currentTimeMillis()
        if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA) {
            onDoubleClick(v)
            lastClickTime = 0
        }
        lastClickTime = clickTime
    }

    abstract fun onDoubleClick(v: View)

    companion object {
        private const val DOUBLE_CLICK_TIME_DELTA: Long = 300 //milliseconds
    }
}

Lets come to the implementation

For implementation double tap listener just create an android sample project. You can apply double click listener is anywhere. In this demo, I’m taking one button. On this button, I will set double click listener, for verifying this I’ll show the toast.

package com.doubletaplistener

import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // handle double tap event
        doubleTap.setOnClickListener(object : DoubleClickListener() {
            override fun onDoubleClick(v: View) {
               Toast.makeText(applicationContext,"Double Clicked Attempts",Toast.LENGTH_SHORT).show()
            }
        })
    }
}

Conclusion

In this android app Example, I show you Double Tap Listener Android Example. I hope it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.

Read our new article on Kotlin String Template

In this article, I’ll show how we can send an FCM message from an android device. in other words, you can say, will tell send android firebase push notifications device to device. How to do that, Let’s get started.

Create a new application.

Let’s open the Android Studio and create a new project with the default template.

Add libraries in app-level build.gradle file

In this example, we are using followings libraries for making network call

  //  Add these line in your project
  implementation 'com.squareup.retrofit2:retrofit:2.7.1'
  implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
  implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
  implementation "com.squareup.okhttp3:logging-interceptor:4.3.1"
Add Base URL and FCM SERVER KEY in build config field your project build.gradle

Let add below variables inside gradle file. Now create a project on firebase. After that Replace FCM_SERVER_KEY ID with your server id.

buildTypes {
    debug {
      buildConfigField("String", "FCM_BASE_URL", "\"https://fcm.googleapis.com/\"")
      buildConfigField("String", "FCM_SERVER_KEY", "\"xxxxxxxxxxxxxxxxxxxxxxxx\"")
    }
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
Add Internet permission manifest

For sending the notification, we will need to internet permission, let’s open the android manifest and add below permission.

  <uses-permission android:name="android.permission.INTERNET" />
Write a network API client

Let’s create a network provider class, In this class, we are using Retrofit and OKHHTP client for debugging.

package com.sendinganotificationmessage;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ApiClient {
  public static NotificationApiService getApiService() {
    return new Retrofit.Builder()
        .baseUrl(BuildConfig.FCM_BASE_URL)
        .client(provideClient())
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(NotificationApiService.class);
  }

  private static OkHttpClient provideClient() {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    return new OkHttpClient.Builder().addInterceptor(interceptor).addInterceptor(chain -> {
      Request request = chain.request();
      return chain.proceed(request);
    }).build();
  }
}
Now create notification API service
package com.sendinganotificationmessage;

import com.google.gson.JsonObject;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;

public interface NotificationApiService {

  @Headers({
      "Authorization: key="+BuildConfig.FCM_SERVER_KEY ,
      "Content-Type: application/json"
  })
  @POST("fcm/send")
  Call<JsonObject> sendNotification(@Body JsonObject payload);
}
Modify your main activity layout file

For taking input from the user will update the layout file that contains a few text input item for capturing device token, title and message

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout5"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textReceiverToken"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Receiver FCM Token"
        android:maxLines="1"
        android:text="fnn3DoqhPPM:APA91bHBDfHv0YC5Mpncu1Got_d28-FIRDEH1gwXj27HGB5_Qbn49cyE7M2zeKijq4FEuApsW6-lEbNGrIGwhhERKTTtGxLvz8Q5xvF_x1QlX3Um8DiKsnYjqeEMySrjAhQNeI8Kot7S"

        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout5"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Title"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout2"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Message"/>
  </com.google.android.material.textfield.TextInputLayout>
  <TextView
      android:id="@+id/textView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      android:text="Additional data you want to pass (In key-value pair)"
      android:textColor="@color/colorAccent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout2"
      />
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout3"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      app:layout_constraintEnd_toStartOf="@+id/textInputLayout4"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textKey"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Key"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout4"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toEndOf="@+id/textInputLayout3"
      app:layout_constraintTop_toTopOf="@+id/textInputLayout3"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textValue"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Value"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <Button
      android:id="@+id/buttonSendNotification"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="24dp"
      android:layout_marginEnd="16dp"
      android:background="@color/colorAccent"
      android:text="Send Notification"
      android:textColor="#ffffff"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout3"
      />


</androidx.constraintlayout.widget.ConstraintLayout>
Let’s move to main activity files

Let’s bind the views using id. As you see below code we taking the input from users and send notification using the retrofit client. We taking input like title, messaging and FCM token.

package com.sendinganotificationmessage;

import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.JsonObject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {
  Button sendNotificationButton;
  TextInputEditText receiverFdmId;
  TextInputEditText title;
  TextInputEditText message;
  TextInputEditText key;
  TextInputEditText value;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initViews();
    sendNotificationButton.setOnClickListener(view -> {
      if (validateInput()) {
        JsonObject payload = buildNotificationPayload();
        // send notification to receiver ID
        ApiClient.getApiService().sendNotification(payload).enqueue(
            new Callback<JsonObject>() {
              @Override
              public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
                if (response.isSuccessful()) {
                  Toast.makeText(MainActivity.this, "Notification send successful",
                      Toast.LENGTH_LONG).show();
                }
              }

              @Override public void onFailure(Call<JsonObject> call, Throwable t) {

              }
            });
      }
    });
  }

  private JsonObject buildNotificationPayload() {
    // compose notification json payload
    JsonObject payload = new JsonObject();
    payload.addProperty("to", receiverFdmId.getText().toString());

    // compose data payload here
    JsonObject data = new JsonObject();
    data.addProperty("title", title.getText().toString());
    data.addProperty("message", message.getText().toString());
    data.addProperty(key.getText().toString(), value.getText().toString());
    // add data payload
    payload.add("data", data);
    return payload;
  }

  private boolean validateInput() {
    if (receiverFdmId.getText().toString().isEmpty()
        || title.getText().toString().isEmpty()
        || message.getText().toString().isEmpty()
        || key.getText().toString().isEmpty()
        || value.getText().toString().isEmpty()) {
      Toast.makeText(this, "Please fill all field correctly", Toast.LENGTH_LONG).show();
      return false;
    }
    return true;
  }

  private void initViews() {
    sendNotificationButton = findViewById(R.id.buttonSendNotification);
    receiverFdmId = findViewById(R.id.textReceiverToken);
    title = findViewById(R.id.textTitle);
    message = findViewById(R.id.textMessage);
    key = findViewById(R.id.textKey);
    value = findViewById(R.id.textValue);
  }
}

Let’s run the project and see your app will run and up. Lets put device token, title and message, finally tap on send.

Conclusion

In this android app tutorial, We have learned the implementation of sending FCM message from android. I hope it’s helpful for you, let’s do a favor for me, share this post with all your friends.

Get Solution Code

Keep in touch

If you want to keep in touch so let’s follow me on Facebook or Subscribe to us. Still, if you have any queries please put your comment below.

I this post, will learn about firebase cloud messaging in android. I will show you a full demonstration with sample app. Let see how we setup firebase cloud messaging in our app

Overview
  • Firebase Cloud Messaging is a cross-platform messaging solution that lets you reliably deliver messages free of cost.
  • It just allows you to notify a client that a new email, data or other data is available to sync.
  • You can send notification messages that are displayed to the user.
  • Notification messaging is act as instant messaging. A message can transfer a payload of up to 4KB to the client.
  • You can send a message to a single device, group of the device, or to devices subscribed to topic.
Implementation step of firebase cloud messaging in your app
  • Create an android project
  • Create a firebase project on firebase console
  • Connect your app to firebase
  • Setup your android app to use the cloud messaging libraries
  • Receive the code when the app is background and foreground.
Setup your android app to use the cloud messaging libraries

Navigate your project, In project-level build.gradle file make sure to include Google maven.

build.gradle (project-level)
    // add these line
    classpath 'com.google.gms:google-services:4.2.0'
app/build.gradle
  //  Add these line
  implementation 'com.google.firebase:firebase-messaging:20.1.0'
  implementation 'android.arch.work:work-runtime:1.0.1'
Add this line on top of app/build.gradle
apply plugin: 'com.google.gms.google-services'
Add internet uses permission
  <uses-permission android:name="android.permission.INTERNET" />
Set Notification custom icon as default in manifest
    <! – Add these line -->
    <! – [START] -->
    <! – Set custom default icon -->
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_notification" />
    <! – Set color used with incoming notification messages. This is used when no color is set for the incoming notification message.-->
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/colorAccent" />
    <! –  Set fcm default channel-->
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/default_notification_channel_id" />
    <! – [END] -->

Let’s create a service class named is CloudMessagingService

In the src folder create a service class named CloudMessagingService which extends FirebaseMessagingService. We have to override two methods which are onNewToken() and onMessageReceived().

Let’s override onNewToken methods.

In this methods make own server request here using your HTTP client

  @Override
  public void onNewToken(String token) {
    super.onNewToken(token);
    Log.d(TAG, "Refreshed token: " + token);
    // make a own server request here using your http client
  }
Now override onMessageReceived method

Let’s override onMessageReceived method, in this method we received RemoteMessgage instance that contains all message details.

Message Type

Firebase cloud messing allow you to send two types of messages.

  • Notification Messages
    • It displays the notification. It’s managed by firebase SDK, FCM automatically to the end-user device on behalf of the client app.
    • Notification messages contain a predefined set of user-visible keys.
  • Data Messages
    • Data messages contain only your user defines custom key-value pair.
    • Handled by the app itself. It contains key-value pairs, based on this you can do something(such as make some event, store some data, sync some data ).

The maximum payload of both messages type is 4 KB, except when sending messaging from firebase console, which enforces a 1024 character limit.

Check Notification Messages

Check remote message contains a notification payload or not.

 // if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
      Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }
Handle DATA messages

Check remote message contains a data payload. If data payload contains more than 10 seconds job then we should run log run job using WorkManager. If the task is within 10 min then we should handle it.

  //  if remote message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
      Log.d(TAG, "Message data payload: " + remoteMessage.getData());
      Map<String, String> data = remoteMessage.getData();

      String jobType = data.get("type");
     /* Check the message contains data If needs to be processed by long running job
         so check if data needs to be processed by long running job */

      if (jobType.equalsIgnoreCase(JobType.LONG.name())) {
        // For long-running tasks (10 seconds or more) use WorkManager.
        scheduleLongRunningJob();
      } else {
        // Handle message within 10 seconds
        handleNow(data);
      }
    }
Create and show notification containing the received FCM message.
private void sendNotification(String title, String messageBody) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
        PendingIntent.FLAG_ONE_SHOT);

    String channelId = getString(R.string.default_notification_channel_id);
    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
        new NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    // Since android Oreo notification channel is needed.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Channel human readable title
      NotificationChannel channel = new NotificationChannel(channelId,
          "Cloud Messaging Service",
          NotificationManager.IMPORTANCE_DEFAULT);
      notificationManager.createNotificationChannel(channel);
    }

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
  }
Finally, your CloudMessagingService class looks like this.
package com.firebasecloudmessaging;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;

public class CloudMessagingService extends FirebaseMessagingService {
  private static final String TAG = "CloudMessagingService";

  @Override
  public void onMessageReceived(RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);

    // log the getting message from firebase
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    //  if remote message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
      Log.d(TAG, "Message data payload: " + remoteMessage.getData());
      Map<String, String> data = remoteMessage.getData();

      String jobType = data.get("type");
     /* Check the message contains data If needs to be processed by long running job
         so check if data needs to be processed by long running job */

      if (jobType.equalsIgnoreCase(JobType.LONG.name())) {
        // For long-running tasks (10 seconds or more) use WorkManager.
        scheduleLongRunningJob();
      } else {
        // Handle message within 10 seconds
        handleNow(data);
      }
    }

    // if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
      Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }
  }

  @Override
  public void onNewToken(String token) {
    super.onNewToken(token);
    Log.d(TAG, "Refreshed token: " + token);
    sendRegistrationToServer(token);
  }

  /**
   * Persist token on third-party servers using your Retrofit APIs client.
   * Modify this method to associate the user's FCM InstanceID token with any server-side account
   *
   * @param token The new token.
   */
  private void sendRegistrationToServer(String token) {
    // make a own server request here using your http client

  }

  private void handleNow(Map<String, String> data) {
    if (data.containsKey("title") && data.containsKey("message")) {
      sendNotification(data.get("title"), data.get("message"));
    }
  }

  /**
   * Schedule async work using WorkManager mostly these are one type job.
   */
  private void scheduleLongRunningJob() {
    OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(DataSyncWorker.class)
        .build();
    WorkManager.getInstance().beginWith(work).enqueue();
  }

  /**
   * Create and show notification containing the received FCM message.
   *
   * @param messageBody FCM message body received.
   */
  private void sendNotification(String title, String messageBody) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
        PendingIntent.FLAG_ONE_SHOT);

    String channelId = getString(R.string.default_notification_channel_id);
    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
        new NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    // Since android Oreo notification channel is needed.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Channel human readable title
      NotificationChannel channel = new NotificationChannel(channelId,
          "Cloud Messaging Service",
          NotificationManager.IMPORTANCE_DEFAULT);
      notificationManager.createNotificationChannel(channel);
    }

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
  }
}
Modify main activity layout file

This file I’m adding a button for logging firebase token.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >


  <Button
      android:id="@+id/logTokenButton"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Log Token"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />
</androidx.constraintlayout.widget.ConstraintLayout>
Meanwhile, open the MainActivity, and manage followings things
  • Handle possible data accompanying notification message
  • Log and show the Get new Instance ID token
package com.firebasecloudmessaging;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;

public class MainActivity extends AppCompatActivity {
  private static final String TAG = "MainActivity";

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

    // If a notification message is tapped, any data accompanying the notification
    // message is available in the intent extras.
    // Handle possible data accompanying notification message.
    if (getIntent().getExtras() != null) {
      for (String key : getIntent().getExtras().keySet()) {
        Object value = getIntent().getExtras().get(key);
        Log.d(TAG, "Key: " + key + " Value: " + value);
        // navigate the app based on param
      }
    }

    // Log and show the  Get new Instance ID token
    Button loginButton = findViewById(R.id.logTokenButton);
    loginButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(
            new OnCompleteListener<InstanceIdResult>() {
              @Override public void onComplete(@NonNull Task<InstanceIdResult> task) {
                if (!task.isSuccessful()) {
                  Log.e(TAG, "getInstanceId failed", task.getException());
                  return;
                }

                // Get new Instance ID token
                String token = task.getResult().getToken();

                Log.d(TAG, token);
                Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
              }
            });
      }
    });
  }
}
Conclusion

All done, now run the app and see your app is run and up. you able to see the token on toast and logcat as well. Now send the messaging from android another device. Let’s see your notification is visible on the screen.

In this post, we learned how to implement Firebase Cloud Messaging Android our application. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Happy coding 🙂

In this blog, I will show how to auto read OTP in android with the help of SMS User Consent API. In our previous blog, we have learned Automatic SMS Verification Android using SMS Retriever API. But it has some difficulty for example

  • SMS should start with <#> tag,
  • SMS should end with application hash code, etc.

In this article, I’m going to show you the implementation auto-read OTP using SMS User Consent API. It is complements of SMS Retriever API. Using SMS User Consent API we can achieve auto read OTP by allowing an app to prompt the user to grant access to the content of a single SMS message. When the user gives consent, the app can access the entire message to automatically complete SMS verification.

auto read otp android user consent 1
auto read otp android user consent 2
auto read otp android user consent 3

Image source google developers website.

  • Start – The first thing you have to start is listening before sending the message or OTP to the server.
  • Prompt – When the user’s device receives the SMS message containing a one-time code, Google Play services display the contents of the message to the user and asks for consent to make that text available to your app.
  • Read Message – If the user consents, the entire SMS message is made available to your app.
Message Criteria

Google play services imposed the followings SMS criteria

  • It contains a one-time password– The should message contains a 4–10 character alphanumeric string with at least one number.
  • Contacts – The message was sent by a phone number that’s not in the user’s contacts.
  • Timing – The API will look for the One Time Code for a maximum time of 5 minutes.
1. Let’s create a new project in Android Studio

Open to an android studio and create a new project. That project we will implement auto read OTP features. So I’m adding few strings in strings.xml file that we will use this project.

<resources>
  <string name="app_name">SMS verification</string>
  <string name="send_otp">Send OTP</string>
  <string name="generate_otp">Generate OTP</string>
  <string name="received_message">Received Message</string>
  <string name="verify_otp">Verify OTP</string>
</resources>

We should add below dependencies in app-level build.gradle in your project.

    // add these lines in your app build.gradle
    implementation 'com.google.android.gms:play-services-auth:17.0.0'
    implementation 'com.google.android.gms:play-services-auth-api-phone:17.1.0'
3. Listen to the incoming messages

The next step is to listen to incoming messaging. we can start listening for incoming messages using below method. We can add sender phone number, SMS User Consent API will only trigger on messages from this number. I’m adding null here

  private void startSmsUserConsent() {
    SmsRetrieverClient client = SmsRetriever.getClient(this);
    //We can add sender phone number or leave it blank
    // I'm adding null here
    client.startSmsUserConsent(null).addOnSuccessListener(new OnSuccessListener<Void>() {
      @Override
      public void onSuccess(Void aVoid) {
        Toast.makeText(getApplicationContext(), "On Success", Toast.LENGTH_LONG).show();
      }
    }).addOnFailureListener(new OnFailureListener() {
      @Override
      public void onFailure(@NonNull Exception e) {
        Toast.makeText(getApplicationContext(), "On OnFailure", Toast.LENGTH_LONG).show();
      }
    });
  }
4. Create a BroadcastReceiver named is SmsBroadcastReceiver

In SmsBroadcastReceiverListener we will catch SMS and set back using SmsBroadcastReceiverListener callback methods.

package com.smsverification;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;

public class SmsBroadcastReceiver extends BroadcastReceiver{

  SmsBroadcastReceiverListener smsBroadcastReceiverListener;

  @Override
  public void onReceive(Context context, Intent intent) {
    if (intent.getAction() == SmsRetriever.SMS_RETRIEVED_ACTION) {
      Bundle extras = intent.getExtras();
      Status smsRetrieverStatus = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
      switch (smsRetrieverStatus.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          Intent messageIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT);
          smsBroadcastReceiverListener.onSuccess(messageIntent);
          break;
        case CommonStatusCodes.TIMEOUT:
          smsBroadcastReceiverListener.onFailure();
          break;
      }
    }
  }

  public interface SmsBroadcastReceiverListener {
    void onSuccess(Intent intent);

    void onFailure();
  }
}

When the broadcast receiver catch any message that contains OTP, Google paly services display is contents( BottomSheet ) for asking permission. If the user allows then full messing is available to your app. So let’s register broadcast receiver.

private void registerBroadcastReceiver() {
    smsBroadcastReceiver = new SmsBroadcastReceiver();
    smsBroadcastReceiver.smsBroadcastReceiverListener =
        new SmsBroadcastReceiver.SmsBroadcastReceiverListener() {
          @Override
          public void onSuccess(Intent intent) {
            startActivityForResult(intent, REQ_USER_CONSENT);
          }

          @Override
          public void onFailure() {

          }
        };
    IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
    registerReceiver(smsBroadcastReceiver, intentFilter);
  }

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

  @Override
  protected void onStop() {
    super.onStop();
    unregisterReceiver(smsBroadcastReceiver);
  }
6. Receive message in onActivityResult()

If the user consents, the entire SMS message is made available to your app. we will catch messaging in

 @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQ_USER_CONSENT) {
      if ((resultCode == RESULT_OK) && (data != null)) {
        //That gives all message to us.
        // We need to get the code from inside with regex
        String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE);
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
        textViewMessage.setText(
            String.format("%s - %s", getString(R.string.received_message), message));

        getOtpFromMessage(message);
      }
    }
  }
7. Extract OTP from messaging.

Suppose our messaging is “Your OTP is 123456. Please do not share OTP with others “. Now you have to extract OTP from methods using below method.

  private void getOtpFromMessage(String message) {
    // This will match any 6 digit number in the message
    Pattern pattern = Pattern.compile("(|^)\\d{6}");
    Matcher matcher = pattern.matcher(message);
    if (matcher.find()) {
      otpText.setText(matcher.group(0));
    }
  }
8. I’m modifying main activity layout for demonstration

For creating a fully functional sample app, I’m adding TextView for showing messaging and edit text for showing OTP.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/verify_otp"
      android:textAllCaps="false"
      android:textSize="18sp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />
  <TextView
      android:id="@+id/textViewMessage"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="24dp"
      android:layout_marginEnd="16dp"
      android:gravity="center"
      android:textSize="16sp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/button"
      tools:text="@string/received_message"
      />
  <ImageView
      android:id="@+id/imageView"
      android:layout_width="150dp"
      android:layout_height="150dp"
      android:layout_marginTop="32dp"
      app:layout_constraintBottom_toTopOf="@+id/editTextOTP"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:srcCompat="@drawable/ic_otp"
      />
  <EditText
      android:id="@+id/editTextOTP"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginEnd="16dp"
      android:layout_marginBottom="16dp"
      android:ems="10"
      android:gravity="center"
      android:hint="OTP"
      android:inputType="number"
      app:layout_constraintBottom_toTopOf="@+id/button"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />

</androidx.constraintlayout.widget.ConstraintLayout>
9. We almost done, put all java code together in activity files.
package com.smsverification;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {
  private static final int REQ_USER_CONSENT = 200;
  SmsBroadcastReceiver smsBroadcastReceiver;
  Button verifyOTP;
  TextView textViewMessage;
  EditText otpText;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // find view by ids
    verifyOTP = findViewById(R.id.button);
    textViewMessage = findViewById(R.id.textViewMessage);
    otpText = findViewById(R.id.editTextOTP);
    startSmsUserConsent();
  }

  private void startSmsUserConsent() {
    SmsRetrieverClient client = SmsRetriever.getClient(this);
    //We can add sender phone number or leave it blank
    // I'm adding null here
    client.startSmsUserConsent(null).addOnSuccessListener(new OnSuccessListener<Void>() {
      @Override
      public void onSuccess(Void aVoid) {
        Toast.makeText(getApplicationContext(), "On Success", Toast.LENGTH_LONG).show();
      }
    }).addOnFailureListener(new OnFailureListener() {
      @Override
      public void onFailure(@NonNull Exception e) {
        Toast.makeText(getApplicationContext(), "On OnFailure", Toast.LENGTH_LONG).show();
      }
    });
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQ_USER_CONSENT) {
      if ((resultCode == RESULT_OK) && (data != null)) {
        //That gives all message to us.
        // We need to get the code from inside with regex
        String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE);
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
        textViewMessage.setText(
            String.format("%s - %s", getString(R.string.received_message), message));

        getOtpFromMessage(message);
      }
    }
  }

  private void getOtpFromMessage(String message) {
    // This will match any 6 digit number in the message
    Pattern pattern = Pattern.compile("(|^)\\d{6}");
    Matcher matcher = pattern.matcher(message);
    if (matcher.find()) {
      otpText.setText(matcher.group(0));
    }
  }

  private void registerBroadcastReceiver() {
    smsBroadcastReceiver = new SmsBroadcastReceiver();
    smsBroadcastReceiver.smsBroadcastReceiverListener =
        new SmsBroadcastReceiver.SmsBroadcastReceiverListener() {
          @Override
          public void onSuccess(Intent intent) {
            startActivityForResult(intent, REQ_USER_CONSENT);
          }

          @Override
          public void onFailure() {

          }
        };
    IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
    registerReceiver(smsBroadcastReceiver, intentFilter);
  }

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

  @Override
  protected void onStop() {
    super.onStop();
    unregisterReceiver(smsBroadcastReceiver);
  }
}

Congrats, Let’s use the SMS content API is your application

Conclusion

In this post, we learned how to auto-read OTP android using SMS content API in our application. So let’s recap the step of implementation, basically, three major steps Start Listening messaging, show prompt and Read messaging.

 I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Get Solution Code

Keep Learning 🙂

In this blog, I’m going to show you adding Google Sign In using firebase in your android app. It very easy to do just follow below step. So let’s get started.

Step of Implementation Google Authentication
  • Create an android project
  • Setup and add project on firebase console.
  • Enable Google Sign In
  • Add SHA and 256 keys to the app on firebase console. (Required step for Google Sign In )
  • Add authentication library in app-level build.gradle
  • Setup Google client
1. Create an android project

Let’s move to android studio and create a new project. In this sample application, I’m taking a package name is com.googlesigninfirebase for demonstration of Google Sign in using firebase. let’s go to next step.

2. Setup new firebase project on firebase console.

Let’s open the firebase console and add a project. For adding a project on firebase follow my previous post. Adding Firebase to Android App Manually

3. Enable Google Sign In

Select Authentication from the left panel. Go to the Sign In method and you can select Google and enable the Google SignIn. In sort ( Authentication -> Sign In Method -> Google -> Enable ).

4. Add SHA and 256 keys to the app on firebase console

This is the required step for google sign In. Now go to the android studio project. To get the signature of the app clicks the gradle on right-hand side. Now select app -> task -> android and select singingReport.

You just need to copy and paste in project setting in firebase. You have to set both keys SHA1 and SHA-256. Now come back to android studio follow next step.

Add authentication library in app-level build.gradle
 implementation 'com.firebaseui:firebase-ui-auth:4.3.1'
 // Google Sign In SDK (only required for Google Sign In)
 implementation 'com.google.android.gms:play-services-auth:17.0.0'
Create a new activity along with layout named is LoginActivity

Open layout file and button for demonstration

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoginActivity"
    >

  <com.google.android.gms.common.SignInButton
      android:id="@+id/sign_in_button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="8dp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />

</androidx.constraintlayout.widget.ConstraintLayout>
Open LoginActvitiy and paste following code
package com.googlesigninfirebase;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;

public class LoginActivity extends AppCompatActivity {
  private static final String TAG = "LoginActivity";
  private static final int RC_SIGN_IN = 1001;

  GoogleSignInClient googleSignInClient;

  private FirebaseAuth firebaseAuth;

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

    SignInButton signInButton = findViewById(R.id.sign_in_button);
    signInButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        // Launch Sign In
        signInToGoogle();
      }
    });

    // Configure Google Client
    configureGoogleClient();
  }

  private void configureGoogleClient() {
    // Configure Google Sign In
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        // for the requestIdToken, this is in the values.xml file that
        // is generated from your google-services.json 
        .requestIdToken(getString(R.string.default_web_client_id))
        .requestEmail()
        .build();

    // Build a GoogleSignInClient with the options specified by gso.
    googleSignInClient = GoogleSignIn.getClient(this, gso);

    // Set the dimensions of the sign-in button.
    SignInButton signInButton = findViewById(R.id.sign_in_button);
    signInButton.setSize(SignInButton.SIZE_WIDE);

    // Initialize Firebase Auth
    firebaseAuth = FirebaseAuth.getInstance();
  }

  @Override
  public void onStart() {
    super.onStart();

    // Check if user is signed in (non-null) and update UI accordingly.
    FirebaseUser currentUser = firebaseAuth.getCurrentUser();

    if (currentUser != null) {
      Log.d(TAG, "Currently Signed in: " + currentUser.getEmail());
      showToastMessage("Currently Logged in: " + currentUser.getEmail());
    }
  }

  public void signInToGoogle() {
    Intent signInIntent = googleSignInClient.getSignInIntent();
    startActivityForResult(signInIntent, RC_SIGN_IN);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
      Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
      try {
        // Google Sign In was successful, authenticate with Firebase
        GoogleSignInAccount account = task.getResult(ApiException.class);
        showToastMessage("Google Sign in Succeeded");
        firebaseAuthWithGoogle(account);
      } catch (ApiException e) {
        // Google Sign In failed, update UI appropriately
        Log.w(TAG, "Google sign in failed", e);
        showToastMessage("Google Sign in Failed " + e);
      }
    }
  }

  private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
    Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());

    AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
    firebaseAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // Sign in success, update UI with the signed-in user's information
              FirebaseUser user = firebaseAuth.getCurrentUser();

              Log.d(TAG, "signInWithCredential:success: currentUser: " + user.getEmail());

              showToastMessage("Firebase Authentication Succeeded ");
              launchMainActivity(user);
            } else {
              // If sign in fails, display a message to the user.

              Log.w(TAG, "signInWithCredential:failure", task.getException());

              showToastMessage("Firebase Authentication failed:" + task.getException());
            }
          }
        });
  }

  private void showToastMessage(String message) {
    Toast.makeText(LoginActivity.this, message, Toast.LENGTH_LONG).show();
  }

  private void launchMainActivity(FirebaseUser user) {
    if (user != null) {
      MainActivity.startActivity(this, user.getDisplayName());
      finish();
    }
  }
}
Open MainActvity layout add logout and revoke access button
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >


  <Button
      android:id="@+id/buttonLogout"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginBottom="16dp"
      android:text="@string/logout"
      android:textAllCaps="false"
      app:layout_constraintBottom_toTopOf="@+id/buttonDisconnect"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />
  <Button
      android:id="@+id/buttonDisconnect"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/revoke_access"
      android:textAllCaps="false"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />
  <TextView
      android:id="@+id/textViewWelcome"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginBottom="32dp"
      android:text="@string/welcome"
      android:gravity="center"
      app:layout_constraintBottom_toTopOf="@+id/buttonLogout"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />
</androidx.constraintlayout.widget.ConstraintLayout>

Go to main activity and add logout code

package com.googlesigninfirebase;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  private static final String TAG = "MainActivity";
  private static final String ARG_NAME = "username";

  public static void startActivity(Context context, String username) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra(ARG_NAME, username);
    context.startActivity(intent);
  }

  FirebaseAuth firebaseAuth;
  GoogleSignInClient googleSignInClient;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView textView = findViewById(R.id.textViewWelcome);
    if (getIntent().hasExtra(ARG_NAME)) {
      textView.setText(String.format("Welcome - %s", getIntent().getStringExtra(ARG_NAME)));
    }
    findViewById(R.id.buttonLogout).setOnClickListener(this);
    findViewById(R.id.buttonDisconnect).setOnClickListener(this);

    googleSignInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_SIGN_IN);
    firebaseAuth = FirebaseAuth.getInstance();
  }

  @Override
  public void onClick(View view) {
    switch (view.getId()) {
      case R.id.buttonLogout:
        signOut();
        break;
      case R.id.buttonDisconnect:
        revokeAccess();
        break;
    }
  }

  private void signOut() {
    // Firebase sign out
    firebaseAuth.signOut();

    // Google sign out
    googleSignInClient.signOut().addOnCompleteListener(this,
        new OnCompleteListener<Void>() {
          @Override
          public void onComplete(@NonNull Task<Void> task) {
            // Google Sign In failed, update UI appropriately
            Log.w(TAG, "Signed out of google");
          }
        });
  }

  private void revokeAccess() {
    // Firebase sign out
    firebaseAuth.signOut();

    // Google revoke access
    googleSignInClient.revokeAccess().addOnCompleteListener(this,
        new OnCompleteListener<Void>() {
          @Override
          public void onComplete(@NonNull Task<Void> task) {
            // Google Sign In failed, update UI appropriately
            Log.w(TAG, "Revoked Access");
          }
        });
  }
}

Conclusion

With the help of this android app tutorial, We have learned Google Sign In using Firebase android. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Welcome guys, In this post I’ll show you sign in with email with FirebaseUI. Firebase provides many ways for authentication. Here, I’ll explain FirebaseUI to login using email and password. so Let’s get started.

Why should use FirebaseUI for Authentication?

FirebaseUI is an open-source library, you can also customize it because of open source. It eliminates boilerplate code and promotes android best practices with user experiences and security. FirebaseUI is all enabled single tap to enable and returning users also.

Connect your app to firebase

Let’s open an android studio and create a new android project with the empty activity template. I’m taking the package name here com.firebaseauthenticationuiexample . Once the project created, connect your app to the firebase. Please follow this article for creating a project on firebase console.

Add a new classpath in project-level build.gradle

Open the project-level build.gradle and add the below line.

//Add this line
classpath 'com.google.gms:google-services:4.3.2'
Add new plugin in app-level build.gradle

Open the app-level build.gradle and google services plugin by adding this line

// add this line
apply plugin: 'com.google.gms.google-services'
Add firebase UI auth dependency in same app level gradle file

Firebase UI auth library needs to perform a firebase auth with email.

implementation 'com.firebaseui:firebase-ui-auth:4.3.1'

After adding sync the project and make sure everything is working fine.

Enable email and password authentication on firebase console.

Go to the firebase console and enable email password authentication. So go to the Authentication option in the left panel. Once you open on authentication go to Sign In method and enable email password.

firebase login with email and password android
Create a LoginActvitiy

I’m creating a new activity with a layout file. Here I’m adding a button for initiating login just for demonstration purposes. Let’s go to the layout file and add SignIn button just like below

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoginActivity"
    >
  <Button
      android:id="@+id/buttonSignIn"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="SignIn with Email"
      android:textAllCaps="false"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />

</androidx.constraintlayout.widget.ConstraintLayout>
Let’s go to LoginActivity.

In the LoginActivity, before initiating sign-in make sure your user is already login for not in previous session. you can check something like this.

    FirebaseAuth auth = FirebaseAuth.getInstance();
    if (auth.getCurrentUser() != null) {
      // already signed in
    } else {
      // not signed in 
    }

Create and launch sign-in intent

If the user is not signed-in then by the initiated sign-in process by creating auth intent. This you can specify service URL and include the link inside, or customized theme as well. You need to create and launch sign-in intent just like this.

    // Choose authentication providers
    List<AuthUI.IdpConfig> providers = Arrays.asList(
        new AuthUI.IdpConfig.EmailBuilder().build());

    // Create and launch sign-in intent
    startActivityForResult(
        AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .build(),
        RC_SIGN_IN);

Check Response code on Activity Result

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // RC_SIGN_IN is the request code you passed into
    if (requestCode == 1234) {

      // Successfully signed in
      if (resultCode == RESULT_OK) {
        // Successfully signed in
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        Toast.makeText(getApplicationContext(), "Successfully signed in", Toast.LENGTH_SHORT)
            .show();
        launchMainActivity(user);
      }
    } else {
      // Sign in failed. If response is null the user canceled the sign-in flow using the back button. Otherwise check
      // response.getError().getErrorCode() and handle the error.
      Toast.makeText(getApplicationContext(), "Unable to Sign in", Toast.LENGTH_SHORT).show();
    }
  }
Finally, the login activity source code look like this.
package com.firebaseauthenticationuiexample;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.firebase.ui.auth.AuthUI;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import java.util.Arrays;
import java.util.List;

public class LoginActivity extends AppCompatActivity {
  private static final int RC_SIGN_IN = 1234;

  public static void startActivity(Context context) {
    Intent intent = new Intent(context, LoginActivity.class);
    context.startActivity(intent);
  }

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

    // find view
    Button buttonSignIn = findViewById(R.id.buttonSignIn);
    // Set onclick listener
    buttonSignIn.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        FirebaseAuth auth = FirebaseAuth.getInstance();
        if (auth.getCurrentUser() != null) {
          Toast.makeText(getApplicationContext(), "User already signed in, must sign out first",
              Toast.LENGTH_SHORT).show();
          // already signed in
        } else {
          // Choose authentication providers
          List<AuthUI.IdpConfig> providers = Arrays.asList(
              new AuthUI.IdpConfig.EmailBuilder().build());

          // Create and launch sign-in intent
          startActivityForResult(
              AuthUI.getInstance()
                  .createSignInIntentBuilder()
                  .setAvailableProviders(providers)
                  .build(),
              RC_SIGN_IN);
        }
      }
    });
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // RC_SIGN_IN is the request code you passed into
    if (requestCode == 1234) {

      // Successfully signed in
      if (resultCode == RESULT_OK) {
        // Successfully signed in
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        Toast.makeText(getApplicationContext(), "Successfully signed in", Toast.LENGTH_SHORT)
            .show();
        launchMainActivity(user);
      }
    } else {
      // Sign in failed. If response is null the user canceled the sign-in flow using the back button. Otherwise check
      // response.getError().getErrorCode() and handle the error.
      Toast.makeText(getApplicationContext(), "Unable to Sign in", Toast.LENGTH_SHORT).show();
    }
  }

  private void launchMainActivity(FirebaseUser user) {
    if (user != null) {
      MainActivity.startActivity(this, user.getDisplayName());
      finish();
    }
  }
}
Implement logout in MainActivity

Your login stuff is done. Now I’m going to explain the logout part. open the main activity layout file add one button for perform logout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

  <Button
      android:id="@+id/buttonLogout"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Logout"
      android:textAllCaps="false"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"

      />
  <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginBottom="16dp"
      android:text="Welcome"
      android:textColor="@color/colorAccent"
      android:textSize="20sp"
      app:layout_constraintBottom_toTopOf="@+id/buttonLogout"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />
</androidx.constraintlayout.widget.ConstraintLayout>
Let’s open the main activity source file

Doing signout firebase auth provider gives callback onComplete methods. just like below.

package com.firebaseauthenticationuiexample;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.firebase.ui.auth.AuthUI;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

public class MainActivity extends AppCompatActivity {
  private static final String ARG_NAME = "username";

  public static void startActivity(Context context, String username) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra(ARG_NAME, username);
    context.startActivity(intent);
  }

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

    TextView textView = findViewById(R.id.textView);
    if (getIntent().hasExtra(ARG_NAME)) {
      textView.setText(String.format("Welcome - %s", getIntent().getStringExtra(ARG_NAME)));
    }

    Button logout = findViewById(R.id.buttonLogout);
    logout.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        AuthUI.getInstance()
            .signOut(MainActivity.this)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
              public void onComplete(@NonNull Task<Void> task) {
                // user is now signed out
                Toast.makeText(getApplicationContext(), "User has signed out!", Toast.LENGTH_SHORT)
                    .show();
                launchLoginActivity();
              }
            });
      }
    });
  }

  private void launchLoginActivity() {
    LoginActivity.startActivity(MainActivity.this);
    finish();
  }
}

With the help of this android app tutorial, We have learned firebaseui for authentication with email I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Keep in touch

If you want to keep in touch and get an email when I write new blog posts, follow me on facebook or subscribe usIt only takes about 10 seconds to register. 

Still, if you have any queries please put your comment below.

In this article, I’ll show you how you adding firebase to android app. We’ll discuss the possible options and recommended ways of it. Apart from this, I will tell you preliminary information for Firebase integration. For doing that, we’ll create a sample app and will add the firebase into it. So let’s started

Prerequisite

The following preliminary information that required for Firebase

  • One Google account
  • One real device or emulator for running the sample app
  • The latest Android Studio version (1.5 or later)
  • The app must use gradle 4.1 or later
There are two options for adding firebase into your project.
  • Firebase Assistant in Android Studio
    • Prebuild tool available in Android Studio
    • Using Assistant you can connect existing project or create new ones for you.
    • Assistant is automatically added and install all necessary dependencies
  • Add Firebase to your app via a firebase console manually.
    • This way you have to do all operations manually

Note – Google recommended manual way to add firebase in your app.

Create a project in Firebase console

Let’s open web browse and open firebase console. Click on add project -> enter the project name -> If you need analytics then check this option otherwise you can uncheck it. Finally, click on create a project.

Go to add firebase into android platform

Open this project and click on android icon, Then below window pop up. The big thing here is the package name. This package name has to match android app package name.

The next step is to download google-services.json file

You have to download this file and put into your app

Put this json file into app folder in your app

It’s a really important step. So let’s open your app folder -> navigate app folder – paste inside the app google-services.json. After adding it click on next.

Create a project in Android Studio with the same package name.

Let’s move to Android Studio create a new project with package name com.sampleapp. Now paste the google-services.json file in your app folder. just like below screenshot.

Add firebase SDK
Modify project-level build.gradle in Android Studio and add SDK classpath
  dependencies {
    // Add this line
    classpath 'com.google.gms:google-services:4.3.2'
  }
Open the app-level.gradle file. (<project>/<app-module>/build.gradle)
// Add this line
apply plugin: 'com.google.gms.google-services'

After modifying these files sync the project. Now your firebase setup is used. Firebase provides so many libraries that we’ll learn in the coming tutorial.

Learn our firebase android tutorial series