Image Source: Link

Introduction

My name is Moses N. I am a WordPress developer based in Kenya. Before I proceed, I know you are curious how come am a WordPress developer and am writing about Firebase, nevertheless, am currently venturing into android application development, and in this tutorial will be my pleasure to show you how to generate real-time reports using Firebase.

How to generate real-time reports using Firebase will be a continuation of How to create an android two-step authentication signup system using Firebase. So I would urge you to look at it before we continue. What will be actually doing in this tutorial is:

  1. Will be adding a button “Report” to our home activity.
  2. Button report will be used to save reports on our android phone and also display.
  3. iText Pdf Library will help us create PDF.
  4. Handle runtime permission.
  5. We will be retrieving information from the Firebase database.
  6. Will be designing our reports in a table format.
  7. Will be allowing write and read permission from our storage.

Get the complete project from GitHub
Enough intro? Let’s dig in now.

Photo Preview

Glossary

  • Reports A report is a document that presents information in an organized format for a specific audience and purpose.
  • Firebase – is a Backend-as-a-Service (Baas) because It provides developers with a variety of tools. Also, services to help them develop quality apps, grow their user base, and earn a profit.
  • Real-timethe actual time during which a process or event occurs.

In conclusion, I believe we are on the same page now. Therefore, let’s take our time to talk about the Project Requirement for Firebase Real-time Reports.

Firebase Real-time Reports project requirement.

  1. Android Phone – you will require your android phone to act as an emulator for running the project. Alternatively, you can download Memu. Also, you can install the emulator from your android studio.
  2. Editor – We will need an editor to write our codes with. You can go online and check out any text editors but I recommend we stick to Android Studio.
  3. Internet Connectivity – we will require the internet all through our project for installing dependencies and accessing Firebase Database.
  4. Git – This is kinda optional but I still recommend having git installed. This will prove useful if you ever want to deploy your code or push to a remote repository. You can download and install git through Git.

In short, that’s our project requirement. Let’s begin coding!

Steps to Firebase Real-time Reports:

Step 1: Adding Report Button.

Since we had designed our home activity in the previous blog we are going to change only a few things to make look at the photo preview below.

How to generate real-time reports using Firebase

Below is the Home Activity code.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<Button
android:id="@+id/button_disable_report"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:layout_margin="8dp"
android:background="@drawable/button"
android:onClick="previewDisabledUsersReport"
android:padding="8dp"
android:text="@string/disabled_users_report"
android:textAllCaps="false"
style="?android:buttonBarButtonStyle"
android:textColor="@android:color/white"
android:textSize="14sp" />
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/payment_pdf_viewer"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
view raw activity_main.xml hosted with ❤ by GitHub

Step 2: Adding Firebase Real-time Reports Project dependencies.

We will be using the iText PDF Library to create PDF. You can get the library from here. To view the PDF we will need another library barteksc PDF viewer. You can get from here.

//for pdf
    implementation 'com.itextpdf:itextg:5.5.10'
    implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'

Step 3: Allowing Read and Write permission.

How to generate real-time reports using Firebase

In order to save our PDF report in our phone storage, we will need to allow permission from the manifest. We will also allow handle runtime permission.

  • Manifest permission.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • Handling runtime permission.
    public static String[] PERMISSIONS = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    public static int PERMISSION_ALL = 12;
 public boolean hasPermissions(Context context, String... permissions) {
        if (context != null && permissions != null) {
            for (String permission : permissions) {
                if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
        }
        return true;
    }
 public void previewDisabledUsersReport()
    {
        if (hasPermissions(this, PERMISSIONS)) {
            DisplayReport();
        } else {
            ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
        }
    }

Step 4: Creating setters and getters.

We are going to create a java class to hold all the setters and getters. The getters will enable us to retrieve data from the Firebase database and the setters will help set the retrieved data in the report.

package com.example.twostepauthentication;
public class Constants
{
public String First_Name,Other_Name,Phone;
public String getFirst_Name() {
return First_Name;
}
public void setFirst_Name(String first_Name) {
First_Name = first_Name;
}
public String getOther_Name() {
return Other_Name;
}
public void setOther_Name(String other_Name) {
Other_Name = other_Name;
}
public String getPhone() {
return Phone;
}
public void setPhone(String phone) {
Phone = phone;
}
}
view raw Constants.java hosted with ❤ by GitHub

Step 5: Creating the PDF report

Here we are going to create a method that will allow us to design the Firebase Real-time Reports. We will determine the number of columns it has from the data we are fetching from the database. We will also add a header and a footer. Now with that said let’s design the report to look like the image below.

How to generate real-time reports using Firebase
private void createPaymentReport( List<Constants> paymentUsersList) throws DocumentException, FileNotFoundException{
BaseColor colorWhite = WebColors.getRGBColor("#ffffff");
BaseColor colorBlue = WebColors.getRGBColor("#056FAA");
BaseColor grayColor = WebColors.getRGBColor("#425066");
Font white = new Font(Font.FontFamily.HELVETICA, 15.0f, Font.BOLD, colorWhite);
FileOutputStream output = new FileOutputStream(pFile);
Document document = new Document(PageSize.A4);
PdfPTable table = new PdfPTable(new float[]{6, 25, 20, 20});
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setFixedHeight(50);
table.setTotalWidth(PageSize.A4.getWidth());
table.setWidthPercentage(100);
table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
Chunk noText = new Chunk("No.", white);
PdfPCell noCell = new PdfPCell(new Phrase(noText));
noCell.setFixedHeight(50);
noCell.setHorizontalAlignment(Element.ALIGN_CENTER);
noCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk nameText = new Chunk("First Name", white);
PdfPCell nameCell = new PdfPCell(new Phrase(nameText));
nameCell.setFixedHeight(50);
nameCell.setHorizontalAlignment(Element.ALIGN_CENTER);
nameCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk phoneText = new Chunk("Other Names", white);
PdfPCell phoneCell = new PdfPCell(new Phrase(phoneText));
phoneCell.setFixedHeight(50);
phoneCell.setHorizontalAlignment(Element.ALIGN_CENTER);
phoneCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk amountText = new Chunk("Phone Number", white);
PdfPCell amountCell = new PdfPCell(new Phrase(amountText));
amountCell.setFixedHeight(50);
amountCell.setHorizontalAlignment(Element.ALIGN_CENTER);
amountCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk footerText = new Chunk("Moses Njoroge - Copyright @ 2020");
PdfPCell footCell = new PdfPCell(new Phrase(footerText));
footCell.setFixedHeight(70);
footCell.setHorizontalAlignment(Element.ALIGN_CENTER);
footCell.setVerticalAlignment(Element.ALIGN_CENTER);
footCell.setColspan(4);
table.addCell(noCell);
table.addCell(nameCell);
table.addCell(phoneCell);
table.addCell(amountCell);
table.setHeaderRows(1);
PdfPCell[] cells = table.getRow(0).getCells();
for (PdfPCell cell : cells) {
cell.setBackgroundColor(grayColor);
}
for (int i = 0; i < paymentUsersList.size(); i++) {
Constants pay = paymentUsersList.get(i);
String id = String.valueOf(i + 1);
String name = pay.getFirst_Name();
String sname = pay.getOther_Name();
String phone = pay.getPhone();
table.addCell(id + ". ");
table.addCell(name);
table.addCell(sname);
table.addCell(phone);
}
PdfPTable footTable = new PdfPTable(new float[]{6, 25, 20, 20});
footTable.setTotalWidth(PageSize.A4.getWidth());
footTable.setWidthPercentage(100);
footTable.addCell(footCell);
PdfWriter.getInstance(document, output);
document.open();
Font g = new Font(Font.FontFamily.HELVETICA, 25.0f, Font.NORMAL, grayColor);
document.add(new Paragraph(" How to generate real-time reports using Firebase\n\n", g));
document.add(table);
document.add(footTable);
document.close();
}
view raw CreatReport.java hosted with ❤ by GitHub

Step 6: Fetching data from Firebase.

In this stage, we will fetch data from the Firebase database using getters. Then we will display the data fetched in the report using setters.

//function to fetch payment data from the database
private void fetchPaymentUsers()
{
payRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
//creating an object and setting to displlay
Constants pays = new Constants();
pays.setFirst_Name(snapshot.child("FirstName").getValue().toString());
pays.setOther_Name(snapshot.child("OtherName").getValue().toString());
pays.setPhone(snapshot.child("Phone").getValue().toString());
//this just log details fetched from db(you can use Timber for logging
Log.d("Payment", "Name: " + pays.getFirst_Name());
Log.d("Payment", "othername: " + pays.getOther_Name());
Log.d("Payment", "phone: " + pays.getPhone());
/* The error before was cause by giving incorrect data type
You were adding an object of type PaymentUsers yet the arraylist expects obejct of type DisabledUsers
*/
paymentUsersList.add(pays);
}
//create a pdf file and catch exception beacause file may not be created
try {
createPaymentReport(paymentUsersList);
} catch (DocumentException | FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
view raw FechData.java hosted with ❤ by GitHub

Finally, we will save the report in internal storage.
paymentUsersList = new ArrayList<>();
//create files in reports care folder
payfile = new File("/storage/emulated/0/Report/");
//check if they exist, if not create them(directory)
if ( !payfile.exists()) {
payfile.mkdirs();
}
pFile = new File(payfile, "PaymentUsers.pdf");
fetchPaymentUsers();
}
view raw SaveReport.java hosted with ❤ by GitHub

Step 7:Display report.

Finally lets display the report on click or the report button.

private void DisplayReport()
{
pdfView.fromFile(pFile)
.pages(0,2,1,3,3,3)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.load();
}
Button reportButton = findViewById(R.id.button_disable_report);
reportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
previewDisabledUsersReport();
}
});
view raw DisplayReport.java hosted with ❤ by GitHub
.

full code for the main activity

package com.example.twostepauthentication;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentTransaction;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.github.barteksc.pdfviewer.PDFView;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.html.WebColors;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//firebase auth to check if user is authenticated.
private FirebaseAuth mAuth;
private DatabaseReference userRef;
private DatabaseReference payRef;
//creating a list of objects constants
List<Constants> paymentUsersList;
//List all permission required
public static String[] PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static int PERMISSION_ALL = 12;
public static File pFile;
private File payfile;
private PDFView pdfView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Home");
mAuth = FirebaseAuth.getInstance();
userRef = FirebaseDatabase.getInstance().getReference().child("Users");
payRef = FirebaseDatabase.getInstance().getReference().child("Users");
pdfView = findViewById(R.id.payment_pdf_viewer);
Button reportButton = findViewById(R.id.button_disable_report);
reportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
previewDisabledUsersReport();
}
});
//
paymentUsersList = new ArrayList<>();
//create files in charity care folder
payfile = new File("/storage/emulated/0/Report/");
//check if they exist, if not create them(directory)
if ( !payfile.exists()) {
payfile.mkdirs();
}
pFile = new File(payfile, "PaymentUsers.pdf");
//fetch payment and disabled users details;
fetchPaymentUsers();
}
//function to fetch payment data from the database
private void fetchPaymentUsers()
{
payRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
//creating an object and setting to displlay
Constants pays = new Constants();
pays.setFirst_Name(snapshot.child("FirstName").getValue().toString());
pays.setOther_Name(snapshot.child("OtherName").getValue().toString());
pays.setPhone(snapshot.child("Phone").getValue().toString());
//this just log details fetched from db(you can use Timber for logging
Log.d("Payment", "Name: " + pays.getFirst_Name());
Log.d("Payment", "othername: " + pays.getOther_Name());
Log.d("Payment", "phone: " + pays.getPhone());
/* The error before was cause by giving incorrect data type
You were adding an object of type PaymentUsers yet the arraylist expects obejct of type DisabledUsers
*/
paymentUsersList.add(pays);
}
//create a pdf file and catch exception beacause file may not be created
try {
createPaymentReport(paymentUsersList);
} catch (DocumentException | FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void createPaymentReport( List<Constants> paymentUsersList) throws DocumentException, FileNotFoundException{
BaseColor colorWhite = WebColors.getRGBColor("#ffffff");
BaseColor colorBlue = WebColors.getRGBColor("#056FAA");
BaseColor grayColor = WebColors.getRGBColor("#425066");
Font white = new Font(Font.FontFamily.HELVETICA, 15.0f, Font.BOLD, colorWhite);
FileOutputStream output = new FileOutputStream(pFile);
Document document = new Document(PageSize.A4);
PdfPTable table = new PdfPTable(new float[]{6, 25, 20, 20});
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setFixedHeight(50);
table.setTotalWidth(PageSize.A4.getWidth());
table.setWidthPercentage(100);
table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
Chunk noText = new Chunk("No.", white);
PdfPCell noCell = new PdfPCell(new Phrase(noText));
noCell.setFixedHeight(50);
noCell.setHorizontalAlignment(Element.ALIGN_CENTER);
noCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk nameText = new Chunk("First Name", white);
PdfPCell nameCell = new PdfPCell(new Phrase(nameText));
nameCell.setFixedHeight(50);
nameCell.setHorizontalAlignment(Element.ALIGN_CENTER);
nameCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk phoneText = new Chunk("Other Names", white);
PdfPCell phoneCell = new PdfPCell(new Phrase(phoneText));
phoneCell.setFixedHeight(50);
phoneCell.setHorizontalAlignment(Element.ALIGN_CENTER);
phoneCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk amountText = new Chunk("Phone Number", white);
PdfPCell amountCell = new PdfPCell(new Phrase(amountText));
amountCell.setFixedHeight(50);
amountCell.setHorizontalAlignment(Element.ALIGN_CENTER);
amountCell.setVerticalAlignment(Element.ALIGN_CENTER);
Chunk footerText = new Chunk("Moses Njoroge - Copyright @ 2020");
PdfPCell footCell = new PdfPCell(new Phrase(footerText));
footCell.setFixedHeight(70);
footCell.setHorizontalAlignment(Element.ALIGN_CENTER);
footCell.setVerticalAlignment(Element.ALIGN_CENTER);
footCell.setColspan(4);
table.addCell(noCell);
table.addCell(nameCell);
table.addCell(phoneCell);
table.addCell(amountCell);
table.setHeaderRows(1);
PdfPCell[] cells = table.getRow(0).getCells();
for (PdfPCell cell : cells) {
cell.setBackgroundColor(grayColor);
}
for (int i = 0; i < paymentUsersList.size(); i++) {
Constants pay = paymentUsersList.get(i);
String id = String.valueOf(i + 1);
String name = pay.getFirst_Name();
String sname = pay.getOther_Name();
String phone = pay.getPhone();
table.addCell(id + ". ");
table.addCell(name);
table.addCell(sname);
table.addCell(phone);
}
PdfPTable footTable = new PdfPTable(new float[]{6, 25, 20, 20});
footTable.setTotalWidth(PageSize.A4.getWidth());
footTable.setWidthPercentage(100);
footTable.addCell(footCell);
PdfWriter.getInstance(document, output);
document.open();
Font g = new Font(Font.FontFamily.HELVETICA, 25.0f, Font.NORMAL, grayColor);
document.add(new Paragraph(" How to generate real-time reports using Firebase\n\n", g));
document.add(table);
document.add(footTable);
document.close();
}
public boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
//onstart method used to check if the user is registered or not
@Override
protected void onStart()
{
super.onStart();
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser ==null){
SendUserToLoginActivity();
}
else{
//checking if the user exists in the firebase database
CheckUserExistence();
}
}
private void CheckUserExistence()
{
//get the user id
final String currentUserId = mAuth.getCurrentUser().getUid();
userRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
{
if (!dataSnapshot.hasChild(currentUserId)){
//user is authenticated but but his record is not present in real time firebase database
SendUserToStepTwoAuthentication();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
private void SendUserToStepTwoAuthentication()
{
Intent steptwoIntent = new Intent(MainActivity.this, StepTwoAuthentication.class);
steptwoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(steptwoIntent);
finish();
}
private void SendUserToLoginActivity()
{
Intent loginIntent = new Intent(MainActivity.this, Login.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(loginIntent);
finish();
}
public void previewDisabledUsersReport()
{
if (hasPermissions(this, PERMISSIONS)) {
DisplayReport();
} else {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}
}
private void DisplayReport()
{
pdfView.fromFile(pFile)
.pages(0,2,1,3,3,3)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.load();
}
}
view raw MainActivity.java hosted with ❤ by GitHub
.
By this, we have completed our tutorial on how to generate real-time reports using Firebase. Click on the Run button and Run the application on your android phone but you can also install an android emulator on the android studio.

Reflective Analysis

It was a simple project for me, but I was still able to gain some deeper insights into Firebase and programming in general. Working with imported dependencies was a challenge but managed to fix by visiting stack overflow and you-tube tutorials.

Future Directions

In order to get more knowledge about Firebase Real-time Reports, I recommend that you add more rows and columns in the report. You can try using different fonts and changing the color of the report to your choice. You can also try to generate reports using SQLite.

Learning Strategies and Tools

There are a lot of learning tools online, I would recommend the following:

I used the learning tools above to create Firebase Real-time Reports. I also used PDF documentations to achieve this. Anytime I faced some bugs, I would use stack overflow to check for solutions.

It took me a total of 9 hours to finish the project and the blog.

Conclusion

In conclusion, this project mainly focuses on how to generate real-time reports using Firebase. Reports are very important in each and every organization for many reasons. I, therefore, find this project very useful. . I hope you have learned a lot from this lesson. Therefore, I will be looking forward to seeing you build something great.
Get the complete project from GitHub
Happy Coding!