com.owncloud.android.ui.activity.ContactListFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.owncloud.android.ui.activity.ContactListFragment.java

Source

/**
 * Nextcloud Android client application
 *
 * @author Tobias Kaminsky
 * Copyright (C) 2017 Tobias Kaminsky
 * Copyright (C) 2017 Nextcloud GmbH.
 * <p>
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 * <p>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.owncloud.android.ui.activity;

import android.Manifest;
import android.accounts.Account;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ImageView;

import com.evernote.android.job.JobRequest;
import com.evernote.android.job.util.support.PersistableBundleCompat;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.services.ContactsImportJob;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.PermissionUtil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.property.StructuredName;

/**
 * This fragment shows all contacts from a file and allows to import them.
 */

public class ContactListFragment extends FileFragment {
    public static final String TAG = ContactListFragment.class.getSimpleName();

    public static final String FILE_NAME = "FILE_NAME";
    public static final String ACCOUNT = "ACCOUNT";

    private RecyclerView recyclerView;
    private Set<Integer> checkedVCards;

    public static ContactListFragment newInstance(OCFile file, Account account) {
        ContactListFragment frag = new ContactListFragment();
        Bundle arguments = new Bundle();
        arguments.putParcelable(FILE_NAME, file);
        arguments.putParcelable(ACCOUNT, account);
        frag.setArguments(arguments);

        return frag;
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.contactlist_fragment, null);
        setHasOptionsMenu(true);

        ArrayList<VCard> vCards = new ArrayList<>();
        checkedVCards = new HashSet<>();

        try {
            OCFile ocFile = getArguments().getParcelable(FILE_NAME);
            setFile(ocFile);
            Account account = getArguments().getParcelable(ACCOUNT);

            if (!ocFile.isDown()) {
                Intent i = new Intent(getContext(), FileDownloader.class);
                i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
                i.putExtra(FileDownloader.EXTRA_FILE, ocFile);
                getContext().startService(i);
            } else {
                File file = new File(ocFile.getStoragePath());
                vCards.addAll(Ezvcard.parse(file).all());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        final Button restoreContacts = (Button) view.findViewById(R.id.contactlist_restore_selected);
        restoreContacts.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (checkAndAskForContactsWritePermission()) {
                    getAccountForImport();
                }
            }
        });

        recyclerView = (RecyclerView) view.findViewById(R.id.contactlist_recyclerview);

        ContactListAdapter.OnVCardClickListener vCardClickListener = new ContactListAdapter.OnVCardClickListener() {
            private void setRestoreButton() {
                if (checkedVCards.size() > 0) {
                    restoreContacts.setEnabled(true);
                    restoreContacts
                            .setBackgroundColor(getResources().getColor(R.color.primary_button_background_color));
                } else {
                    restoreContacts.setEnabled(false);
                    restoreContacts.setBackgroundColor(getResources().getColor(R.color.standard_grey));
                }
            }

            @Override
            public void onVCardCheck(int position) {
                checkedVCards.add(position);
                Log_OC.d(TAG, position + " checked");

                setRestoreButton();
            }

            @Override
            public void onVCardUncheck(int position) {
                checkedVCards.remove(position);
                Log_OC.d(TAG, position + " unchecked");

                setRestoreButton();
            }
        };

        ContactListAdapter contactListAdapter = new ContactListAdapter(getContext(), vCards, vCardClickListener);
        recyclerView.setAdapter(contactListAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        return view;
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        menu.findItem(R.id.action_search).setVisible(false);
        menu.findItem(R.id.action_sync_account).setVisible(false);
        menu.findItem(R.id.action_sort).setVisible(false);
        menu.findItem(R.id.action_switch_view).setVisible(false);
    }

    static class ContactItemViewHolder extends RecyclerView.ViewHolder {
        private ImageView badge;
        private CheckedTextView name;

        ContactItemViewHolder(View itemView) {
            super(itemView);

            badge = (ImageView) itemView.findViewById(R.id.contactlist_item_icon);
            name = (CheckedTextView) itemView.findViewById(R.id.contactlist_item_name);

            itemView.setTag(this);
        }

        public void setVCardListener(View.OnClickListener onClickListener) {
            itemView.setOnClickListener(onClickListener);
        }

        public ImageView getBadge() {
            return badge;
        }

        public void setBadge(ImageView badge) {
            this.badge = badge;
        }

        public CheckedTextView getName() {
            return name;
        }

        public void setName(CheckedTextView name) {
            this.name = name;
        }
    }

    private void importContacts(ContactAccount account) {
        int[] intArray = new int[checkedVCards.size()];

        int i = 0;
        for (Integer checkedVCard : checkedVCards) {
            intArray[i] = checkedVCard;
            i++;
        }

        PersistableBundleCompat bundle = new PersistableBundleCompat();
        bundle.putString(ContactsImportJob.ACCOUNT_NAME, account.name);
        bundle.putString(ContactsImportJob.ACCOUNT_TYPE, account.type);
        bundle.putString(ContactsImportJob.VCARD_FILE_PATH, getFile().getStoragePath());
        bundle.putIntArray(ContactsImportJob.CHECKED_ITEMS_ARRAY, intArray);

        new JobRequest.Builder(ContactsImportJob.TAG).setExtras(bundle).setExecutionWindow(3_000L, 10_000L)
                .setRequiresCharging(false).setPersisted(false).setUpdateCurrent(false).build().schedule();

        Snackbar.make(recyclerView, R.string.contacts_preferences_import_scheduled, Snackbar.LENGTH_LONG).show();
    }

    private void getAccountForImport() {
        final ArrayList<ContactAccount> accounts = new ArrayList<>();

        // add local one
        accounts.add(new ContactAccount("Local contacts", null, null));

        Cursor cursor = null;
        try {
            cursor = getContext().getContentResolver()
                    .query(ContactsContract.RawContacts.CONTENT_URI, new String[] {
                            ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE },
                            null, null, null);

            if (cursor != null && cursor.getCount() > 0) {
                while (cursor.moveToNext()) {
                    String name = cursor
                            .getString(cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_NAME));
                    String type = cursor
                            .getString(cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE));

                    ContactAccount account = new ContactAccount(name, name, type);

                    if (!accounts.contains(account)) {
                        accounts.add(account);
                    }
                }

                cursor.close();
            }
        } catch (Exception e) {
            Log_OC.d(TAG, e.getMessage());
        } finally {
            cursor.close();
        }

        if (accounts.size() == 1) {
            importContacts(accounts.get(0));
        } else {

            ArrayAdapter adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, accounts);
            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            builder.setTitle(R.string.contactlist_account_chooser_title)
                    .setAdapter(adapter, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            importContacts(accounts.get(which));
                        }
                    }).show();
        }
    }

    private boolean checkAndAskForContactsWritePermission() {
        // check permissions
        if (!PermissionUtil.checkSelfPermission(getContext(), Manifest.permission.WRITE_CONTACTS)) {
            PermissionUtil.requestWriteContactPermission(this);
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == PermissionUtil.PERMISSIONS_WRITE_CONTACTS) {
            for (int index = 0; index < permissions.length; index++) {
                if (Manifest.permission.WRITE_CONTACTS.equalsIgnoreCase(permissions[index])) {
                    if (grantResults[index] >= 0) {
                        getAccountForImport();
                    } else {
                        Snackbar.make(getView(), R.string.contactlist_no_permission, Snackbar.LENGTH_LONG).show();
                    }
                    break;
                }
            }
        }
    }

    private class ContactAccount {
        private String displayName;
        private String name;
        private String type;

        ContactAccount(String displayName, String name, String type) {
            this.displayName = displayName;
            this.name = name;
            this.type = type;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ContactAccount) {
                ContactAccount other = (ContactAccount) obj;
                return this.name.equalsIgnoreCase(other.name) && this.type.equalsIgnoreCase(other.type);
            } else {
                return false;
            }
        }

        @Override
        public String toString() {
            return displayName;
        }
    }
}

class ContactListAdapter extends RecyclerView.Adapter<ContactListFragment.ContactItemViewHolder> {
    private List<VCard> vCards;
    private Context context;
    private OnVCardClickListener vCardClickListener;

    ContactListAdapter(Context context, List<VCard> vCards, OnVCardClickListener vCardClickListener) {
        this.vCards = vCards;
        this.context = context;
        this.vCardClickListener = vCardClickListener;
    }

    @Override
    public ContactListFragment.ContactItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.contactlist_list_item, parent, false);

        return new ContactListFragment.ContactItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ContactListFragment.ContactItemViewHolder holder, final int position) {
        final VCard vcard = vCards.get(holder.getAdapterPosition());

        if (vcard != null) {
            // name
            StructuredName name = vcard.getStructuredName();
            if (name != null) {
                String first = (name.getGiven() == null) ? "" : name.getGiven() + " ";
                String last = (name.getFamily() == null) ? "" : name.getFamily();
                holder.getName().setText(first + last);
            } else {
                holder.getName().setText("");
            }

            // photo
            if (vcard.getPhotos().size() > 0) {
                byte[] data = vcard.getPhotos().get(0).getData();

                Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
                RoundedBitmapDrawable drawable = BitmapUtils.bitmapToCircularBitmapDrawable(context.getResources(),
                        thumbnail);

                holder.getBadge().setImageDrawable(drawable);
            } else {
                try {
                    holder.getBadge()
                            .setImageDrawable(TextDrawable.createNamedAvatar(holder.getName().getText().toString(),
                                    context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius)));
                } catch (Exception e) {
                    holder.getBadge().setImageResource(R.drawable.ic_user);
                }
            }

            // Checkbox
            holder.setVCardListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    holder.getName().setChecked(!holder.getName().isChecked());

                    if (holder.getName().isChecked()) {
                        vCardClickListener.onVCardCheck(holder.getAdapterPosition());
                    } else {
                        vCardClickListener.onVCardUncheck(holder.getAdapterPosition());
                    }
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return vCards.size();
    }

    interface OnVCardClickListener {
        void onVCardCheck(int position);

        void onVCardUncheck(int position);
    }
}