--

Tuesday 29 November 2016

Push notification using Firebase Cloud Messaging (FCM)


         Bye, Bye GCM. Yes some features of GCM is already depreciated and now in coming days GCM are going to fully deprecated. A warm welcome to FCM, is a cloud-based messaging service having all features of GCM with some additional features also.

         Google recommending this,  "Firebase is known for being cross platform, so FCM now makes a natural fit in the Firebase suite of features designed for Android, iOS, and mobile web". FCM is completely free and there are no limitations.


 Vital Features 

1. Send notification messages or data messages

          Displayed to your user. Or send data messages and determine completely what happens in your application code. See Message Types

      1.1 Notification Message:

         Notification messages are handled by firebase SDK itself. Typically the notification message contains title, message, icon etc., In order to send the notification message, you need to use notification key in the JSON data. An example of the notification message is given below.

{
    "to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon"
    }
}

      1.2 Data Message:

           Data messages have to be handled by the android app. You can add this kind of messages if you want to send some additional data along with the notification. But sending these messages through firebase console is not possible. You need to have a server-side logic to send the notification using Firebase API. You need to use data key when sending this message.
An example of data message json is given below.
{
   "to" : "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
   "data" : {
     "name" : "LG LED TV S15",
     "product_id" : "123",
     "final_price" : "2500"
   }
 }

       1.3 Messages with both notification and data payload:

          A message can also contain both notification and data payload. When these kinds of messages are sent, it will be handled in two scenarios depending upon app state (background / foreground). For these messages, we can use both notification and data keys.
When in the background – Apps receive the notification payload in the notification tray and only handle the data payload when the user taps on the notification.
When in the foreground – App receives a message object with both payloads available.
An example of notification & data payload message will be
{
    "to" : "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon"
    },
    "data" : {
     "name" : "LG LED TV S15",
     "product_id" : "123",
     "final_price" : "2500"
   }
}

Receiving messages from multiple senders

 Case Study : The client app is an article aggregator with multiple contributors, and each of them should be able to send a message when they publish a new article. This message might contain a URL so that the client app can download the article.

Solution :
The sender ID is uniquely generated by the sender. The client app produces multiple tokens with different sender ID while registration. The registration token is shared with the corresponding app servers (to complete the FCM registration client/server handshake), and finally they'll be able to send messages to the client app using their own authentication keys up to 100 multiple senders.


2. Versatile message targeting 

          Distribute messages to your client app in any of three ways — to single devices, to groups of devices, or to devices subscribed to topics.

Targeted audienceDescriptionMessage JSON format
Sending to Single UserWhen a single user targeted, the firebase registration id is used to identify the device. The reg id has to be mentioned in 'to' field JSON.{
"to": "e1w6hEbZn-8:APA91bEUIb2Je.......",
"data": {
"message": "To Single user Message!",
}
}
Sending to Multiple UserBy adding multiple registration id in 'to'  field.{
"to": "e1wZn-8:APA9....&&d4ffsdsdfdf....&&ffasd.. ",
"data": {
"message": "Multiple user Message!",
}
}
Topic MessagingTopic messaging is useful when segment of users targeted for messaging. For this all the users has to subscribe to firebase topic.
The request format of topic messaging is given below. In the to filed you need to mention the topic name.
{
"to": "/topics/news",
"data": {
"message": "Cloud Messaging Topic Message!",
}
}

3. Send messages from client apps

          Send acknowledgments, chats, and other messages from devices back to your server over FCM’s reliable and battery-efficient connection channel.

FCM Android Implementation

Step 1:

Create a project in Firebase (http://console.firebase.google.com/). Providing Android Studio application`s package name in Firebase project which connects with App.

Step 2:

Download Config file i.e.  google-services.json file from project settings. Add this file to Android App`s \app folder of the project.

Step 3:

Now open the build.gradle located in project’s home directory and add firebase dependency.
dependencies {
    classpath 'com.android.tools.build:gradle:2.2.0'
    classpath 'com.google.gms:google-services:3.0.0'
    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}

 Step 4:

Open app/build.gradle and add firebase messaging dependency. At the very bottom of the file, add apply plugin: ‘com.google.gms.google-services’

 dependencies {
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.google.firebase:firebase-messaging:10.0.0'

}

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

Step 5:

A service that extends FirebaseInstanceIdService to handle the creation, rotation, and updating of registration tokens. This is required for sending to specific devices or for creating device groups.
 <service

    android:name=".AKCFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>
Must be added in the manifest.

Step 6:

A service that extends FirebaseMessagingService. This is required if you want to do any message handling beyond receiving notifications if apps run in the background. 


As shown in the screenshot, showing push notification if app is running in background

To receive notifications in foregrounded apps, to receive data payload, to send upstream messages, and so on, you must extend this service.
<service
    android:name=".AKCFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
 Must be added in the manifest.

Step 7: 

The onTokenRefresh callback fires from AKCFirebaseInstanceIDService.java whenever a new token is generated, so calling getToken in its context ensures that you are accessing a current, available registration token.

@Override
public void onTokenRefresh() {
    super.onTokenRefresh();
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();

    // Saving reg id to shared preferences
    saveRegIdPreference(refreshedToken);
            // Notify UI that registration has completed, so the progress indicator can be hidden.
            try {
        Intent registrationComplete = new Intent();
        registrationComplete.putExtra("token", refreshedToken);
        registrationComplete.setAction(Configuration.REGISTRATION_COMPLETE);
        sendBroadcast(registrationComplete);
    }catch (Exception ex){
        Log.e(TAG,"FCM Exception:"+ex.getLocalizedMessage());
    } }
Broadcast manager broadcasts the reg id to all the activities those are listening.   
 

Step 8: 


The Broadcast receiver responds to the sendBroadcast from onTokenRefresh(). Once FCM is successfully registered. We are ready to `AKC` topic subscription to receive app wide notifications.

 public class AKCFCMReceiver extends BroadcastReceiver{
    private static final String TAG = "FCMAKCReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG,"FCMReceiver onReceive");
        // checking for type intent filter
        if (intent.getAction().equals(Configuration.REGISTRATION_COMPLETE)) {
          
            FirebaseMessaging.getInstance().subscribeToTopic(Configuration.TOPIC_AKC);
            Log.d(TAG,"FCMReceiver : FCM is registered.");
        } else if (intent.getAction().equals(Configuration.PUSH_NOTIFICATION)) {
            // new push notification is received
            String message = intent.getStringExtra("message");
            Log.d(TAG,"FCMReceiver message :"+message);
            Toast.makeText(context, "Push notification: " + message, Toast.LENGTH_LONG).show();
        }
    }
}

 As shown in the screenshot, displaying toast if app is running in foreground.

Step 9:

Subscribing to Topic

When you want to subscribe to any topic, subscribeToTopic() function can be used. When a client app subscribes to a new topic name (one that does not already exist for your Firebase project), a new topic of that name is created in FCM and any client can subsequently subscribe to it.

FirebaseMessaging.getInstance().subscribeToTopic('AKC');

Unsubscribing from Topic

Similarly the client can unsubscribe from a topic by calling unsubscribeFromTopic() method.
FirebaseMessaging.getInstance().unsubscribeFromTopic('AKC');
 

Sending Notification Test messages from Firebase console

    
      Firebase gives hand to test push notification from Console itself. By Tapping 'Notification' option at the left side, Compose message window opens. 



Once send a message, it shows Status, Delivery date, Platform, Open rate, and estimated number of devices the messages reached.



I have added FCM functionalities with Authetication project. You can download the full source code from GitHub,

Kindly send your queries in the comment section.

Happy Coding !!!
Cheers...

Monday 28 November 2016

FIREBASE - Started with Authentication

           Firebase allows an app to securely save user data in the cloud and provide the same personalized experience across all of the user's devices. Firebase Authentication provides secure backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to our app.

          The ready-made Authentication methods support developers to enhance the functionality and usability of the application. I have shared the work flow video of Firebase Authentication App for better understanding,




This video portrays the user registration, updating user information like display name, profile picture, reset password, and user login using Firebase Authentication backend services. I elucidate the complete Authentication implementation further.

Step 1: User registration
Get Firebase auth instance in OnCreate()
authRegister = FirebaseAuth.getInstance(), then
and call authRegister.createUserWithEmailAndPassword(email,password).



authRegister.createUserWithEmailAndPassword(email,password).
        addOnCompleteListener(RegisterActivity.this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                showProgress(false);
                if (!task.isSuccessful()) {
                    Log.e(TAG,"Register exception:"+task.getException());
                   } else {
                    finish();
                    startActivity(new Intent(RegisterActivity.this,HomeActivity.class));
                }
            }
        });

Step 2 : User signin
By calling signInWithEmailAndPassword(email,password) when user click Sign in button. 


 authLogin.signInWithEmailAndPassword(email,password).
        addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                showProgress(false);
                if (!task.isSuccessful()) {
                    mPasswordView.setError(getString(R.string.messgae_login_fail));
                    mPasswordView.requestFocus();
                } else {
                    finish();
                    startActivity(new Intent(LoginActivity.this, HomeActivity.class));
                }
            }
        });

Step 3: Update user information
Creating UserProfileChangeRequest by adding display name and profile picture.

UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
        .setDisplayName(etxtDisplayName.getText().toString())
        .setPhotoUri(photoUri)
        .build();



By calling updateProfile(UserProfileChangeRequest) method to update user information.
existingUser.updateProfile(profileUpdates)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if (task.isSuccessful()) {
                    showProgress(false);
                    Log.d(TAG, "User profile updated.");
                 }
            }
        });

Step 4: Reset Password
By calling sendPasswordResetEmail() to reset instructions sending to our given valid mail id.

  We have to click on the given link from received mail to proceed further.


Once user clicked, 'Reset your password' window opens to enter your new password.



Step 5: Update Email & password
By calling updateEmail(email) & updatePassword(password) methods to update credentials respectively. 

Step 6: Delete user account & Sign out
By calling auth.signOut() method to close existing user session.
Initialize FirebaseUser existingUserFirebaseAuth.getInstance().getCurrentUser(); in OnCreate()
By calling  existingUser.delete() to eradicate user details from cloud completely.

I have shared the complete source code in Github, 
https://github.com/JayaprakashR-Zealot/FirebaseAuthentication

Kindly share your queries in the comment section.

Happy Coding !!!
Thanks..

Accurate Geofencing optimization using Broadcast receiver

          Geofencing API triggers alert to the user when entering or exiting specified radius of certain latitude and longitude at any location. However, the existing Geofence API is often unstable when a user moves around the places by car or train ( i.e. users move fast while driving).

We should make sure the possible scenarios failed to trigger when the device enters a geofence,

⦁         If your geofence is too small or failed to fetch location inside premises. For best results, the minimum radius of the geofence should be set between 100 - 150 meters. When Wi-Fi is available location accuracy is usually between 20 - 50 meters.
⦁        If the device is not connected to the internet either WiFi or cellular data.
⦁        Alerts can be slow or delay to trigger.
⦁        Adding multiple fences inside the fence.
⦁        The maximum active geofences are 100 per device user.

  If we implement the following suggestions to achieve better-optimized Geofencing feature,

⦁        Instead of receiving the transitions using a Service, we should go for a BroadcastReceiver. If not you will not/might not get it if your app gets killed/turned off.
⦁        It is recommended to go for a boot-broadcast receiver. When you recreate your geofences after the device is rebooted.
⦁        We always get a trigger immediately for a newly created geofence, if the device discovers that you're inside the geofence when creating it.

Better battery optimization technique:

⦁        Create and connect locationclient.
⦁        In connect-callback, do adding/removing of geofence(s)
⦁        In geofence-result callback, disconnect locationclient.

Every time this happens, my location client is only connected a few seconds in total. The operating system will still produce geofence alerts and call my BroadcastReceiver whenever they happen.

         I have attached the workflow video for better understanding of this feature.


                                    
                          
This video shows that a user adds their desired latitude and longitude with the suitable title. Geofencing API triggers notification once the user enters or exits the fence.

I elucidate the following optimization approaches to trigger notification efficiently,

Step 1 :
Eradicate the Service implementation, and integrate BroadcastReceiver solution to boost the results.

<receiver
    android:name=".GeofecneBroadcastReceiver"
    android:enabled="true"
    android:exported="false" >
    <intent-filter >
        <action android:name="com.truedreamz.geofence.ACTION_RECEIVE_GEOFENCE"/>
    </intent-filter>
</receiver>

add receiver inside application tag in manifest.

Step 2:
Handling enter or exit transition in onReceive() method of BroadcastReceiver. We have to transfer data to activity for triggering the geofencing location added as pending intent.


    // Get the type of transition (entry or exit)
    int geofenceTransition = geofencingEvent.getGeofenceTransition();
    // Test that a valid transition was reported
    if ((geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
            || (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
        // Get the geofences that were triggered. A single event can trigger multiple geofences.
        List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
        for (Geofence geofence : triggeringGeofences) {
            String geofenceTransitionString = getTransitionString(geofenceTransition);
            String geofenceText=geofenceTransitionString+" : "+geofence.getRequestId();
            Log.i(TAG, "Geofence Transition:" + geofenceText);
            sendEventDetailNotificatonIntent(geofenceText);
            // Create an Intent to broadcast to the app
            broadcastIntent.setAction(GEOFENCE_ACTION)
                    .putExtra("EXTRA_GEOFENCE_ID", geofence.getRequestId())
                    .putExtra("EXTRA_GEOFENCE_TRANSITION_TYPE", geofenceTransitionString);
            LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent);
        }
    } else {
        // Always log as an error
        Log.e(TAG,
                context.getString(R.string.geofence_transition_invalid_type,
                       geofenceTransition));
    }

Step 3:

Before receiving the broadcast, we should add geofence as pending intent when the user clicks 'Add Landmark' from this project.

    String GEOFENCE_ACTION="com.truedreamz.geofence.ACTION_RECEIVE_GEOFENCE";
    if (null != mGeofencePendingIntent) {
        // Return the existing intent
        return mGeofencePendingIntent;
        // If no PendingIntent exists
    } else {
        // Create an Intent pointing to the IntentService
        Intent intent = new Intent(GEOFENCE_ACTION);
        return PendingIntent.getBroadcast(
                getApplicationContext(),
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT);
    }

Need of pending intent:

       A pending intent that that is reused when calling removeGeofences(). This pending intent is used to generate an intent when a matched geofence transition is observed.

I have attached the following screenshots for reference,

The user enters place name & description for adding landmark.



















   





The map activity shows when user tap on location icon from home screen.










The user has to enter the address that filter out based on places API and Auto-complete API.










When the user enters or exit fence, API triggers the notification.












Herewith I have shared the full working source code for Accurate Geofencing App in Github,
https://github.com/JayaprakashR-Zealot/AccurateGeofencing

Kindly raise your queries in the comment section.

Happy Coding !!!
Thanks...

Horizontal + Vertical pager - Cordinal direction swipe alike Snapchat

             I have developed cardinal direction ( Top, Bottom, Left, and Right) swiping as same like Snap chat Dashboard. Here this is the final output screen shot,


When we swipe the Home screen from top           --- Profile fragment
                                                      from bottom     --- Discover fragment
                                                      from left           --- Settings fragment 
                                                      from right         --- More fragment , populates respectively. As per below screenshot,


        Although using ViewPager the vertical swiping is easy to implement, the horizontal swiping is tricky. But we should mix up with Horizontal & vertical pager to confess the cardinal direction swiping.

To solve this issue,
       We should go for Android  event bus implementation. Otto by Square is damn easy to integrate with our Android Studio project. I recommend to keep 'otto-1.3.3.jar' file in lib folder & add it to our project. Now we are ready to utilize otto event bus library to project.


The steps involve to achieve this tasks are,

Step 1 : 

Register EventBus.getInstance() in onResume() & unregister EventBus.getInstance() in onPause() of MainActivity.java

Step 2:
Implement addOnGlobalLayoutListener to request snap with a custom duration by calling VerticalPager#snapToPage(int, int)} method in OnCreate() of MainActivity.java

Step 3:
Add custom VerticalPager in activity_main.xml with three fragments TopFragment, CentralCompositeFragment, BottomFragment

    <?xml version="1.0" encoding="utf-8"?>
    <com.truedreamz.demo.swipe.view.VerticalPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/activity_main_vertical_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <fragment
            android:id="@+id/main_top_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            class="com.truedreamz.demo.swipe.fragment.TopFragment" />

        <fragment
            android:id="@+id/main_central_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            class="com.truedreamz.demo.swipe.fragment.CentralCompositeFragment" />

        <fragment
            android:id="@+id/main_bottom_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            class="com.truedreamz.demo.swipe.fragment.BottomFragment" />

    </com.truedreamz.demo.swipe.view.VerticalPager>

Step 4:
We are implementing Horizontal ViewPager i.e. SmartViewPager in CentralCompositeFragment.

What is  SmartViewPager?

        SmartViewPager resolves scroll gesture directions more accurate than a regular ViewPager component. This will make it perfectly usable into a scroll container such as ScrollView, ListView, etc.

         Default ViewPager becomes hardly usable when it's nested into a scroll container. Such container will intercept any touch event with a minimal vertical shift from the child ViewPager. So switch the page by scroll gesture with a regular ViewPager nested into a scroll container, the user will need to move his finger horizontally without vertical shift. Which is obviously quite irritating. {@link SmartViewPager} has a much much better behavior at resolving scrolling directions.

To populate SmartViewPager in onCreateView() of CentralCompositeFragment,

    ArrayList<Class<? extends Fragment>> pages = new ArrayList<Class<? extends Fragment>>();
    pages.add(LeftFragment.class);
    pages.add(CentralFragment.class);
    pages.add(RightFragment.class);
    mCentralPageIndex = pages.indexOf(CentralFragment.class);
    mHorizontalPager.setAdapter(new FragmentsClassesPagerAdapter(getChildFragmentManager(), getActivity(), pages));

As mentioned Step 3, We already added Top & Bottom fragment in the layout of HomeScreen.

Step 5:
If we run project, we can achieve the cardinal direction swiping as below,





Step 6:

By tapping on each icon Profile, Settings, Discover, and More for swiping to the fragment.
I have uploaded the workflow video for this feature,




I have shared the complete source code for this feature in Github,
https://github.com/JayaprakashR-Zealot/SnapchatDashboard


Kindly refer the parent reference of this feature if you feel any difficulties to understand the flow,
4-Directions-swipe-navigation


You can share your queries in the comment section.

Happy Coding !!!
Thanks...