Skip to main content

Speak Out FCM Notification using Text to Speech (TTS)

Hello everyone! hope you are doing well .Here is another article on Speak out the notification received from Firebase .Basically we will use Text to Speech Service to achieve this. Before going further lets discuss something about FCM behavior.

There are two types of messages in FCM (Firebase Cloud Messaging):

Display Messages: These messages trigger the onMessageReceived() callback only when your app is in foreground.

Data Messages: Theses messages trigger the onMessageReceived() callback even if your app is in foreground/background/killed.

So we can say that we will not receive data messages from Firebase console when app is in background or killed. To solve this problem we have to send FCM notification using our Server or we can also use Postman for sending notification as a Server.

Here are some steps to follow for send notification using Postman.

  • Copy Legacy Server Key from Firebase Console > Project Settings > Cloud Messaging 
  • In Postman Select POST. Enter request URL as https://fcm.googleapis.com/fcm/send
  • Add Headers Authorization: key=<legacy_server_key> OR Authorization: key=<server_key>and Content-Type: application/json.

  • Now Select Body > raw > JSON (application/json) and add following code:
 {  
  "to" : "YOUR_FCM_TOKEN_WILL_BE_HERE",  
  "notification" : {  
    "body" : "Body of Your Notification",  
    "title": "Title of Your Notification"  
  },  
  "data" : {  
    "body" : "Body of Your Notification",  
    "title": "Title of Your Notification",  
    "message" : "The content here which is about to speak out",  
  }  
 }  

 Now that's it send from Postman using send button.

via GIPHY

But that's not our main motto .lets come to coding part for our main task which is speak out our notification .So lets move step by step:-

Step 1: Create FirebaseDataReceiver.java file 


package com.FCMVoice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;


public class FirebaseDataReceiver extends BroadcastReceiver {

    private final String TAG = "FirebaseDataReceiver";

    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
          
           String msg=bundle.get("message").toString();

           try{

               if(msg!=null) {

                   Intent speechIntent=new Intent();
                   speechIntent.putExtra("voicedata",msg);
                   MySpeakService.enqueueWork(context, speechIntent);

               }

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


        }
    }




}

here "mesage" is which we will receive from FCM data .We can not call our Text to Speech here because TTS(Text to Speech) is a service which we can not call to Broadcast Receiver class .So here we use JobIntentService which is subclass of Service .

There is one question in your mind that why we not using service class or foregroundservice here .The answer is that service will automatically stop after sometime when app goes into background and for the case of foregroundservice  we have to notify use a Service Notification all time ,which many users don't like this.


We can also use WorkManager class here which is very latest and useful but here we will use JobIntentService class.

JobIntentService is a modern way to run the background service from the background application. JobIntentService works in the same way as a Service however it enqueues the work into the JobScheduler on compatible Android targets( SDK 26 or more).


Step 2: Create MySpeakService.java class

package com.FCMVoice;

import android.content.Context;
import android.content.Intent;
import android.speech.tts.TextToSpeech;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;

import java.util.Locale;

public class MySpeakService extends JobIntentService {

    private TextToSpeech mySpeakTextToSpeech = null;
    private boolean isSafeToDestroy = false;

    public static void enqueueWork(Context context, Intent intent) {
        enqueueWork(context, MySpeakService.class, 1, intent);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        final String message = intent.getStringExtra("voicedata");

        mySpeakTextToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                try {
                    if (mySpeakTextToSpeech != null && status == TextToSpeech.SUCCESS) {
                        Log.d("spoken text",message);
                        mySpeakTextToSpeech.setLanguage(new Locale("hi"));
                        mySpeakTextToSpeech.setPitch(1.0f);
                        mySpeakTextToSpeech.setSpeechRate(1.0f);
                        mySpeakTextToSpeech.speak(message, TextToSpeech.QUEUE_ADD, null);
                    }
                } catch (Exception ex) {
                    Log.d("Exception spoken text",message);
                    System.out.print("Error handling TextToSpeech GCM notification " + ex.getMessage());
                }
                while (mySpeakTextToSpeech.isSpeaking()) {

                }
                isSafeToDestroy = true;
            }
        });
    }

    @Override
    public void onDestroy() {
        if (isSafeToDestroy) {
            if (mySpeakTextToSpeech != null) {
                mySpeakTextToSpeech.shutdown();
            }
            super.onDestroy();
        }
    }
}


Step 3: Now add some important lines in AndroidManifest.xml 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.FCMVoice">

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

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


    <application
        android:name="com.FCMVoice.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
        <activity
            android:name="com.FCMVoice.Splash"
            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
        <service android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>


        <receiver
            android:name=".FirebaseDataReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter android:directBootAware="true">
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>



        <service android:name=".MySpeakService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:enabled="true"
            android:exported="true"/>



        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_launcher_round" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/colorPrimaryDark" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="FCMVoice_01" />


    </application>

</manifest>


Now that's all, Thank you guys  .Clap clap clapπŸ‘πŸ‘πŸ‘ 

Comments

Popular posts from this blog

How to Download Apk file from Url and Install Programmatically

In this post we learn about download apk file from server or website and then install it Programmatically in Phone. Sometimes we have to download external apk file from server and then install if downloading successfully finished.For this we use AsyncTask class  for background process. So here is Code Snippet for this task.Lets Start :- Before this we have to add these Permissions in Manifest.xml file : <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> DownloadNewVersion.java class DownloadNewVersion extends AsyncTask<String,Integer,Boolean> { @Override protected void onPreExecute() { super.onPreExecute(); bar = new ProgressDialog(getActivity()); bar.setCancelable(false); bar.setMessage("Downl

How to open pdf file url using webview in Android

 Sometimes we have requirement of showing pdf file in our Android Application. Although there are many third party gradle dependencies available online by which you can show your pdf file easily but one of the major drawback of using these libraries are they will increase you apk size .In some cases they will increase apk size upto ~14 MB. Alternatively you can access and show pdf file using assets and from storage options. This can take less size than any third party library. Here we use pdf using url and if you directly open your pdf file url in webview you will get no result because it will start downoad if you open this link in any web browser.  So in this article we will learn how we can open our pdf url using webview and without using any third party library. So lets Start step by Step:- Lets Suppose you have a pdf file url something like   http://yourwebsite.com/files/mydocumentfile.pdf Step 1: So we you this pdf file url to embed in our webview .First of all you have to host yo

How to use UPI Deep Linking in Android

 In this Article we will discuss about the UPI Deep linking. By this Deep linking we can perform UPI Payments through intent .Basically it open the All UPI supported Application in our mobile then user choose their preference and initiate the Payment and through this we get the payment credentials like payment id ,transaction id ,etc. without any payment gateway. So lets start with what is UPI? Unified Payments Interface(UPI) is an instant real-time payment system developed by National Payments Corporation of India facilitating inter-bank transactions. The interface is regulated by the Reserve Bank of India and works by instantly transferring funds between two bank accounts on a mobile platform. (from Wikipedia) Coding part: package com.example.droidmedium; import android.content.Intent; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Butt