Create Android App From Scratch 2: Convert Contacts To Excel

In this second part of our series on how to build an Android Excel Converter app from scratch, we will focus on android contacts to Excel converter feature.

If you have not seen the first part of this series, I suggest you go through it. It details the scope of the project and step-by-step processes involved in creating an Android project from scratch.

Download the sample app example on the Google Play Store.

Android Contacts to Excel Feature

Converting Android contacts into Excel format involves transforming contact information from its original form into a structured and organised format.

Android contacts to excel converter feature helps app users to achieve the following on the app.

  1. Select any of your Android device contacts or all.
  2. Add the name of the Excel file you want to create.
  3. Click on the convert button to convert the selected contacts to Excel.

Android Contacts to Excel Converter Structure

To better understand what we will cover in this tutorial, I have listed the below topics for easy comprehension.

  • Create an Option / Menu Page.
  • Create a Contact Page.
  • Open the Android device contact list using a thirty-party library.
  • Display contact list in Android Recyclcerview.
  • Select and deselect Android contacts.
  • Convert selected contacts to Excel.
  • View the created Excel view.
  • Share and Export Excel File.

Now that we have explained what we will learn, we will create a new menu page for the app.

Create an Option / Menu Page

We will create a new Tabbed Activity page. The tabbed page will contain 2 Fragments.

  1. Features Page – List of all the formats to convert to Excel
  2. Spreadsheet Page – List of all the Excel files on your device.

Create a new Tabbed Activity page and use a name of your choice.

Page Name: HomeActivity.java

Open the activity page and paste the code below.

You can see from the code that Android Studio has generated most of the Tabbed code and the corresponding Fragment pages.

We have added two more methods on the page.

  1. checkHardwarePermission()– To check if Read and Write Permissions.
  2. Override onBackPressed() – add an option to close the app when the user clicks the back button three times.
public class HomeActivity extends AppCompatActivity implements BottomNavigationView.OnItemSelectedListener {

    private ActivityHomeBinding binding;

    private int backCounter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityHomeBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

 
        BottomNavigationView navView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_home);
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(binding.navView, navController);
        binding.navView.setOnItemSelectedListener(this);

    }


    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        int linkId = item.getItemId();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_home);
        if(linkId == R.id.navigation_home){
             navController.navigate(R.id.navigation_home);
        }
        if(linkId == R.id.navigation_dashboard){
            navController.navigate(R.id.navigation_dashboard);
        }
        if(linkId == R.id.navigation_notifications){
            navController.navigate(R.id.navigation_notifications);
        }
        return true;
    }

    @Override
    public void onBackPressed() {
        backCounter++;
        if(backCounter < 3){
            DisplayUtils.showToast(HomeActivity.this, backCounter + " you need 3 clicks to leave");
        }else{
            //super.onBackPressed();
            Intent startMain = new Intent(Intent.ACTION_MAIN);
            startMain.addCategory(Intent.CATEGORY_HOME);
            startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(startMain);
            finish();
        }
    }

    private void checkHardwarePermission(){
        Dexter.withContext(HomeActivity.this)
                .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        if (!report.areAllPermissionsGranted()){
                            Toast.makeText(HomeActivity.this, "All permission is needed for the app to work well", Toast.LENGTH_SHORT).show();
                        }
                    }
                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                    }
                }).check();
    }

}

Create activity_home.xml Layout File

The layout file is simple and does not need any explanation.

<?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"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/intro_page_overlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent">
    
        <RelativeLayout
            android:id="@+id/main_page_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/nav_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="0dp"
                android:layout_marginEnd="0dp"
                android:background="?android:attr/windowBackground"
                android:layout_alignParentBottom="true"
                app:menu="@menu/bottom_nav_menu" />
    
            <fragment
                android:id="@+id/nav_host_fragment_activity_home"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentTop="true"
                app:defaultNavHost="true"
                app:navGraph="@navigation/mobile_navigation" />
    
        </RelativeLayout>
    
    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Now that we have done with the Tabbed Page, we will move further to create the list of features the app will contain. We will add a RecyclerView to the fragment page layout file.

Create fragment_home.xml

Open the fragment_home.xml file, copy and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true"
    android:focusable="true"
    android:background="#4C53B5"
    android:paddingBottom="48dp"
    tools:context=".ui.home.HomeFragment">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="8dp"
                android:orientation="horizontal">

                <androidx.cardview.widget.CardView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    app:cardElevation="3dp"
                    android:layout_weight="1"
                    android:layout_margin="12dp"
                    app:cardCornerRadius="4dp"
                    app:cardUseCompatPadding="true">

                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:padding="12dp"
                        android:gravity="center"
                        android:background="#DCEED1"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/contacts_to_excel"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/contactbook"
                            android:text="Contacts To Excel"
                            android:textStyle="bold"
                            android:textSize="13sp"
                            android:layout_marginTop="8dp"
                            android:layout_marginBottom="8dp"
                            android:drawablePadding="12dp"/>

                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.cardview.widget.CardView>


                <androidx.cardview.widget.CardView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    app:cardElevation="3dp"
                    android:layout_weight="1"
                    android:layout_margin="12dp"
                    app:cardCornerRadius="4dp"
                    app:cardUseCompatPadding="true">

                    <androidx.appcompat.widget.LinearLayoutCompat
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:padding="12dp"
                        android:gravity="center"
                        android:background="#ffe8d6"
                        android:orientation="vertical">

                        <androidx.appcompat.widget.AppCompatTextView
                            android:id="@+id/import_excel"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/downloadexcel"
                            android:text="Import Excel"
                            android:textStyle="bold"
                            android:textSize="13sp"
                            android:layout_marginTop="8dp"
                            android:layout_marginBottom="8dp"
                            android:drawablePadding="12dp"/>

                    </androidx.appcompat.widget.LinearLayoutCompat>

                </androidx.cardview.widget.CardView>


            </androidx.appcompat.widget.LinearLayoutCompat>


            <View
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:background="#b388eb"
                android:layout_marginStart="16dp"
                android:layout_marginEnd="16dp"
                android:layout_marginBottom="18dp"/>


            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/excel_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginStart="12dp"
                android:layout_marginEnd="12dp"
                android:layout_marginBottom="12dp"/>

        </androidx.appcompat.widget.LinearLayoutCompat>


    </androidx.core.widget.NestedScrollView>

</androidx.appcompat.widget.LinearLayoutCompat>

HomeFragment.java Page

We will get the instances of the UI Views we add in the fragment_home.xml layout file.

For the RecyclerView adapter, we will use a third-party library named SmartRecyclerAdapter. Add the code to your project build.gradle file.

implementation 'io.github.manneohlund:smart-recycler-adapter:3.0.0'

With the RecyclerView adapter added, we will create a model class and a ViewHolder class. The adapter class uses these classes to populate and manage our RecyclerView.

Open the HomeFragment file and add the below code to it.

public class HomeFragment extends Fragment {

    @BindView(R.id.excel_list)
    RecyclerView excelList;

    private SmartRecyclerAdapter smartRecyclerAdapter;

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_home, container, false);
        ButterKnife.bind(this, root);

        List<ExcelModel> data = DataUtils.getConversionTypes();
        setUpConverterTypes(data);

        return root;
    }

    public void setUpConverterTypes(List<ExcelModel> excelConversionTypesDataList){
        smartRecyclerAdapter = SmartRecyclerAdapter
            .items(excelConversionTypesDataList)
            .map(ExcelModel.class, ExcelViewHolder.class)
            .setLayoutManager(new GridLayoutManager(requireActivity(), 2))

            .addViewEventListener((OnConvertFileListener) (view, actionId, position) -> {

                ExcelModel excelModel = (ExcelModel) excelConversionTypesDataList.get(position);
                String param = excelModel.getExt();

                List<String> imageExtList = Arrays.asList("jpg","jpeg","png");

                if(imageExtList.contains(param)){
                    //this.navigateToImage();
                    this.openImagePicker();
                }else if(param == "table"){
                    this.navigateToTable();
                }else {
                    this.pageNavigation(excelModel);
                }
            })
            .into(excelList);
    }

    private void openImagePicker() {
        String[] mimeTypes = {"image/*"};
        Intent imagePickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        imagePickerIntent.addCategory(Intent.CATEGORY_OPENABLE);
        imagePickerIntent.setDataAndType(Uri.parse(Environment.getExternalStorageDirectory().getPath()+ File.separator), "*/*");
        imagePickerIntent.setType("*/*");
        imagePickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        imagePickerIntent.putExtra("multi-pick", true);
        imagePickerIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        imagePickerActivityResultLauncher.launch(imagePickerIntent);
        Bungee.slideLeft(requireActivity());
    }


    ActivityResultLauncher<Intent> imagePickerActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
        if(result.getResultCode() == Activity.RESULT_OK){
            if(result.getData() != null){
                ExtractImageText extractImageText = new ExtractImageText(requireActivity(), result.getData().getData());
                extractImageText.processImageTextExtraction((success, extractedImage) -> {
                    DisplayUtils.showToast(requireActivity(),"Hello "+success+"  "+extractedImage);
                });
            }
        }
    });


    private void navigateToImage(){
        Intent dbIntent = new Intent(requireActivity(), DatabaseActivity.class);
        startActivity(dbIntent);
        Bungee.slideLeft(requireActivity());
    }

    private void navigateToTable(){
        Intent tableIntent = new Intent(requireActivity(), TableActivity.class);
        startActivity(tableIntent);
        Bungee.slideLeft(requireActivity());
    }

    private void pageNavigation(ExcelModel excelModel){
        String excelModelString = new Gson().toJson(excelModel);
        Intent extIntent = new Intent(requireActivity(), ListDeviceFileActivity.class);
        extIntent.putExtra(AppConstants.EXCEL_CONVERSION_TYPES_OBJECT, excelModelString);
        startActivity(extIntent);
        Bungee.slideLeft(requireActivity());
    }

    @OnClick(R.id.contacts_to_excel)
    public void readDeviceContact(View view){
        Intent contactIntent = new Intent(requireActivity(), ContactToExcelActivity.class);
        startActivity(contactIntent);
        Bungee.slideLeft(requireActivity());
    }

    @OnClick(R.id.import_excel)
    public void readExcelFile(View view){
        Intent importIntent = new Intent(requireActivity(), ImportExcelActivity.class);
        startActivity(importIntent);
        Bungee.slideLeft(requireActivity());
    }

}

Create ExcelModel Class

Now that we have added classes that do not exist yet, Android Studio will use a red line to highlight them. First, we will create a model class.

I will name the model ExcelModel. Feel free to choose a name of your choice. Open the create file and paste the code below.

public class ExcelModel {

    private String conversionName;

    private String ext;

    private int conversionIcon;

    public ExcelModel(String conversionName, int conversionIcon) {
        this("", conversionName, conversionIcon);
    }

    public ExcelModel(String ext, String conversionName, int conversionIcon) {
        this.ext = ext;
        this.conversionName = conversionName;
        this.conversionIcon = conversionIcon;

    }

    public String getConversionName() {
        return conversionName;
    }

    public void setConversionName(String conversionName) {
        this.conversionName = conversionName;
    }

    public int getConversionIcon() {
        return conversionIcon;
    }

    public void setConversionIcon(int conversionIcon) {
        this.conversionIcon = conversionIcon;
    }

    public String getExt() { return ext; }

    public void setExt(String ext) { this.ext = ext; }
}

Create a ViewHolder Class

Create a ViewHolder class and use a name of your choice. I will use ExcelViewHolder.java.

This class will contain instances of two Views that appear in each RecyclerView item. We will create the layout file soon.

Open the ViewHolder class and paste the code below.

public class ExcelViewHolder extends SmartViewHolder<ExcelModel> {

    private static final String TAG = ExcelViewHolder.class.getSimpleName();

    @BindView(R.id.conversion_name)
    AppCompatTextView conversionName;

    @BindView(R.id.conversion_icon)
    AppCompatImageView conversionIcon;

    public ExcelViewHolder(ViewGroup parentView) {
        super(LayoutInflater.from(parentView.getContext()).inflate(R.layout.convert_file_type_layout, parentView, false));
        ButterKnife.bind(this, itemView);
    }

    @Override
    public void bind(ExcelModel item) {
        conversionName.setText(item.getConversionName());
        conversionIcon.setImageResource(item.getConversionIcon());
    }

}

You can see from the code that it reference a layout file.

R.layout.convert_file_type_layout

Create a new layout file and name it convert_file_type_layout.xml file.

Open the layout file and add the code below it.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_wrapper"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="4dp"
    app:cardCornerRadius="8dp"
    app:cardUseCompatPadding="true">

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="30dp"
        android:paddingBottom="30dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:gravity="center">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/conversion_icon"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:scaleType="centerCrop"
            android:src="@drawable/excel"
            android:layout_marginEnd="5dp"/>

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/conversion_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="PDF 2 Excel"
            android:textStyle="bold"
            android:textColor="#444444"
            android:textSize="12sp"
            android:layout_marginTop="18dp"/>

    </androidx.appcompat.widget.LinearLayoutCompat>

</androidx.cardview.widget.CardView>

RecyclerView Item Click Event

We have just concluded the first part of this tutorial. If you compile your code and run it, you will see a UI similar to the screenshot below.

— Screen Shoot —

We have already added a click event listener when we worked on the HomeFragment class. Below is the code to refresh your mind. 

@OnClick(R.id.contacts_to_excel)
public void readDeviceContact(View view){
    Intent contactIntent = new Intent(requireActivity(), ContactToExcelActivity.class);
    startActivity(contactIntent);
    Bungee.slideLeft(requireActivity());
}

Clicking the Contact menu will navigate the user to a new page that lists all the contacts on the user’s device.

Create ContactToExcelActivity Page

We will create a new Activity page that will list our device contacts. Name this file ContactToExcelActivity.java or any name of your choice.

We will add a RecyclerView in the layout file. Each item in the RecyclerView will contain a TextView, which will hold the contact information and a Checkbox. The checkbox toggles to select or unselect a list of contacts to convert to Excel.

Open the new activity page and paste the code below.

public class ContactToExcelActivity extends AppCompatActivity implements Ads.IAdCallback {

    private String TAG = ContactToExcelActivity.class.getSimpleName();

    @BindView(R.id.contact_list)
    RecyclerView contactList;

    @BindView(R.id.contact_total)
    AppCompatTextView contactTotal;

    private SmartRecyclerAdapter smartRecyclerAdapter;

    private ContactData contactData;

    private List<ContactExcelModel> allContacts;

    private Spinning spanning;

    private String selectedExcelExtension = null;


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

        setTitle("Contact To Excel");

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);


        ButterKnife.bind(this);

        spanning = new Spinning(this);
        spanning.show();

        contactData = new ContactData(this);

        this.setupContactList();

        spanning.hide();
    }

    private List<ContactExcelModel> fetchData(){
        List<Contact> contacts = Contacts.getQuery().find();
        List<ContactExcelModel> data = new ArrayList<>();
        Map<String, ContactExcelModel> dataStore = new HashMap<>();

        for (Contact contact : contacts) {
            String firstName = contact.getGivenName();
            String lastName = contact.getDisplayName();
            Long id = contact.getId();

            String phone = "";
            for(PhoneNumber nums : contact.getPhoneNumbers()){
                phone += nums.getNumber() + " ";
            }

            String email = "";
            for(Email emailContact : contact.getEmails()){
                email += emailContact + " ";
            }

            String birthday = "";
            if(contact.getBirthday() != null){
                birthday = contact.getBirthday().getStartDate();
            }

            if(phone != null || !phone.isEmpty()){
                if(firstName == null || firstName.isEmpty()){
                    firstName = "No name";
                }

                if(!dataStore.containsKey(phone)){
                    dataStore.put(phone, new ContactExcelModel(id, firstName, lastName, phone, email, birthday));
                }
            }
        }

        for (Map.Entry<String, ContactExcelModel> entry : dataStore.entrySet()) {
            data.add(entry.getValue());
        }

        return data;
    }

    private void setupContactList(){

        allContacts = this.fetchData();
        if(allContacts != null){
            int total = allContacts.size();
            contactTotal.setText("Total Contacts: " + String.valueOf(total));
        }

        smartRecyclerAdapter = SmartRecyclerAdapter
                .items(allContacts)
                .map(ContactExcelModel.class, ContactExcelViewHolder.class)
                .setLayoutManager(new LinearLayoutManager(this))
                .addViewEventListener((OnContactSelected) (view, actionId, position) -> {

                    ContactExcelModel objType = (ContactExcelModel) allContacts.get(position);

                    boolean selectBox = ((AppCompatCheckBox)view).isChecked();
                    if(selectBox){
                        contactData.addContact(objType);
                    }else{
                        contactData.removeContact(objType);
                    }
                    contactData.getContacts();
                })
                .into(contactList);
    }

    private void unSelectAll(){
        contactData.clearAll();
        for(ContactExcelModel ceModel : allContacts){
            ceModel.setChecked(false);
            contactData.addContact(ceModel);
        }
        smartRecyclerAdapter.smartNotifyDataSetChanged();
    }

    private void selectAll(){
        contactData.clearAll();
        for(ContactExcelModel ceModel : allContacts){
            ceModel.setChecked(true);
            contactData.addContact(ceModel);
        }
        smartRecyclerAdapter.smartNotifyDataSetChanged();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.contact_menu_option, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int menuId = item.getItemId();
        if(menuId == android.R.id.home){
            onBackPressed();
        }
        if(menuId == R.id.nav_select){
            this.selectAll();
            contactData.getContacts();
        }
        if(menuId == R.id.nav_unselect){
            this.unSelectAll();
            contactData.getContacts();
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        Bungee.slideRight(this);
    }

    @OnClick(R.id.contacts_to_excel_btn)
    public void onClickView(){
        DisplayUtils.showExcelExtensionPicker(ContactToExcelActivity.this, (view, position, id, item) -> {
            selectedExcelExtension = item.toString();
        }, view -> {
            if(selectedExcelExtension == null){
                DisplayUtils.showToast(ContactToExcelActivity.this, "Please select excel extension");
            }else{
                convertContactToExcel();
            }
        });
    }



    private void convertContactToExcel(){
        if(spanning != null){
            spanning.show();
        }
        MapWrapper mapWrapper = new MapWrapper();
        Map<Long, ContactExcelModel> selectedContact = contactData.getContacts();
        Map<Integer, Object[]> excelData = mapWrapper.contactToExcel(selectedContact);

        // convert data to excel
        CreateExcel createExcel = new CreateExcel(ContactToExcelActivity.this, excelData);
        StorageUtil store = new StorageUtil(ContactToExcelActivity.this);
        String folderPath = store.createFileStorageFolder("CreateExcel");
        String filePath = folderPath + File.separator + "contact_" + System.currentTimeMillis() + "."+selectedExcelExtension;

        Uri uri = Uri.fromFile(new File(filePath));

        createExcel.setUri(uri);
        createExcel.createNewExcelFile();
        
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if(spanning != null){
                    spanning.hide();
                }
            }
        }, 2000);
    }

    private void gotoViewExcel(String excelObjString){
        Intent excelIntent = new Intent(ContactToExcelActivity.this, ViewExcelActivity.class);
        excelIntent.putExtra("EXCEL_OBJ", excelObjString);
        excelIntent.putExtra("IS_PATH", "true");
        startActivity(excelIntent);
        Bungee.slideLeft(ContactToExcelActivity.this);
    }

}

There is a lot to take from the code. Below is a simple explanation to help you understand it better.

  1. We have used a third-party Contact Picker plugin. Add the below line of code to your project build.gradle file. implementation 'com.github.tamir7.contacts:contacts:1.1.7'
  2. The RecyclerView will list all the contacts on the user’s device.
  3. The checkbox toggles the select and unselect states of each item of the contacts.
  4. Other utility classes like StorageUtil, CreateExcel and more are add to clean up the code.

Create the activity_contact_to_excel.xml layout file

Open the layout file for the activity page and paste the code 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=".ui.home.contacts.ContactToExcelActivity">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/contact_notice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:gravity="center"
        android:padding="24dp"
        android:text="Select the contact(s) that will be added to excel"
        android:textSize="13sp"
        android:background="@color/notice" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/contact_total"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/contact_notice"
        android:gravity="center"
        android:padding="12dp"
        android:text="Total Contacts : 220"
        android:textStyle="bold"
        android:textColor="@color/black"
        android:textSize="13sp" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/contact_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/contact_total"
        app:layout_constraintBottom_toTopOf="@id/card_bottom"
        android:layout_margin="8dp"
        android:scrollbars="none"/>


    <androidx.cardview.widget.CardView
        android:id="@+id/card_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/contact_list"
        android:layout_marginStart="18dp"
        android:layout_marginBottom="18dp"
        android:layout_marginEnd="18dp"
        android:layout_marginTop="4dp"
        android:elevation="3dp">

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/contacts_to_excel_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/background"
            android:textColor="@color/white"
            android:text="convert to excel"/>

    </androidx.cardview.widget.CardView>


</androidx.constraintlayout.widget.ConstraintLayout>

Create the Contact List Model Class

Create a new model class and name it ContactExcelModel. Open the new file and add the code below.

public class ContactExcelModel {

    private Long id;

    private String firstName;

    private String lastName;

    private String phone;

    private String email;

    private String birthday;

    private boolean isChecked = false;

    public ContactExcelModel(Long id, String firstName, String lastName, String phone, String email, String birthday) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phone = phone;
        this.email = email;
        this.birthday = birthday;
    }

    public String getFullName(){
        return this.firstName + " " + this.lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public boolean isChecked() {
        return this.isChecked;
    }

    public void setChecked(boolean checked) {
        this.isChecked = checked;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

Create the Contact List ViewHolder Class

Create a new ViewHolder class and name it ContactExcelViewHolder. Open the new file and add the code below.

public class ContactExcelViewHolder extends SmartViewHolder<ContactExcelModel> {

    private String TAG = ContactExcelViewHolder.class.getSimpleName();

    @BindView(R.id.contact_fullname)
    AppCompatTextView fullName;

    @BindView(R.id.contact_phone)
    AppCompatTextView phone;

    @BindView(R.id.is_selected)
    AppCompatCheckBox selectContact;

    public ContactExcelViewHolder(ViewGroup parentView) {
        super(LayoutInflater.from(parentView.getContext()).inflate(R.layout.contact_item_view_layout, parentView, false));
        ButterKnife.bind(this, itemView);
    }

    @Override
    public void bind(ContactExcelModel item) {
        fullName.setText(item.getLastName());
        phone.setText(item.getPhone());
        selectContact.setChecked(item.isChecked());
    }

    @Override
    public void unbind() {
        super.unbind();
    }
}

Create the ViewHolder Layout File

Create a new layout file and name it contact_item_view_layout.xml. Open the new file and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:elevation="4dp"
    android:layout_marginBottom="2dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="12dp">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/contact_fullname"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            android:textSize="14sp"
            app:layout_constraintEnd_toStartOf="@id/is_selected"
            app:layout_constraintTop_toTopOf="parent"
            android:text="Developer Account"
            android:textStyle="bold"/>

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/contact_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="13sp"
            android:layout_marginTop="4dp"
            app:layout_constraintTop_toBottomOf="@+id/contact_fullname"
            app:layout_constraintStart_toStartOf="parent"
            android:text="079393987"
            android:textStyle="bold"/>

        <androidx.appcompat.widget.AppCompatCheckBox
            android:id="@+id/is_selected"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:checked="false"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

This marks the end of the part 2 tutorial. It is long because we have to create some rudimental page.

In the next part of the series on how to create an Android app from scratch, we will cover how to import an Excel file and convert it into a table.

If you have any questions or suggestions with this tutorial, kindly use the comment box to contact us.

Leave a Reply