package com.seafile.seadroid2.util;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.SeadroidApplication;
import com.seafile.seadroid2.SeafException;
import com.seafile.seadroid2.SettingsManager;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.AccountManager;
import com.seafile.seadroid2.data.DataManager;
import com.seafile.seadroid2.data.SeafDirent;
import com.seafile.seadroid2.data.ContactsData;
import com.seafile.seadroid2.ui.activity.SettingsActivity;
import com.seafile.seadroid2.ui.dialog.TaskDialog;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import a_vcard.android.provider.Contacts;
import a_vcard.android.syncml.pim.VDataBuilder;
import a_vcard.android.syncml.pim.VNode;
import a_vcard.android.syncml.pim.vcard.ContactStruct;
import a_vcard.android.syncml.pim.vcard.VCardComposer;
import a_vcard.android.syncml.pim.vcard.VCardException;
import a_vcard.android.syncml.pim.vcard.VCardParser;
/**
* Function:
* Author: Saud
* Create: 2016/11/12
* Modtime: 2016/11/12
*/
@SuppressLint("ValidFragment")
public class ContactsDialog extends TaskDialog {
private static final String STATE_TASK_CONTACTS_TYPE = "state_task_contacts_type";
public static final int CONTACTS_BACKUP = 1;
public static final int CONTACTS_RECOVERY = 2;
private int type;
private SettingsActivity mContext;
public ContactsDialog() {
}
public ContactsDialog(Context context, int type) {
if (context instanceof SettingsActivity) {
this.mContext = (SettingsActivity) context;
this.type = type;
isProgressHorizontal = true;
}
}
@Override
public void onTaskFailed(SeafException e) {
super.onTaskFailed(e);
}
@Override
public void onTaskSuccess() {
if (type == CONTACTS_BACKUP) {
Toast.makeText(mContext, getString(R.string.contacts_backup_success), Toast.LENGTH_LONG).show();
} else if (type == CONTACTS_RECOVERY) {
Toast.makeText(mContext, getString(R.string.contacts_recovery_success), Toast.LENGTH_LONG).show();
}
super.onTaskSuccess();
}
@Override
protected void onDialogCreated(Dialog dialog) {
if (type == CONTACTS_BACKUP) {
dialog.setTitle(R.string.contacts_backup_title);
} else if (type == CONTACTS_RECOVERY) {
dialog.setTitle(R.string.contacts_recovery_title);
}
}
@Override
protected void onSaveDialogContentState(Bundle outState) {
outState.putInt(STATE_TASK_CONTACTS_TYPE, type);
}
@Override
protected View createDialogContentView(LayoutInflater inflater, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_contacts, null);
TextView countText = (TextView) view.findViewById(R.id.setting_contacts_backup);
String fileName = "";
if (type == CONTACTS_BACKUP) {
fileName = getString(R.string.contacts_dialog_backup) + " " +
ContactManager.getContactsBackupFileName();
} else if (type == CONTACTS_RECOVERY) {
fileName = getString(R.string.contacts_dialog_recovery);
}
countText.setText(fileName);
return view;
}
@Override
protected Task prepareTask() {
ContactManager contactManager = new ContactManager(mContext, type);
return contactManager;
}
}
class ContactManager extends TaskDialog.Task {
private static final String DEBUG_TAG = "ContactManager";
private final int type;
private SettingsActivity mContext;
private List<Account> mAccounts;
private String mContactsPath;
private long mMtime = 1;
private SeafDirent seafDirent;
private String mPath;
public ContactManager(Context context, int type) {
this.type = type;
if (context instanceof SettingsActivity) {
mContext = (SettingsActivity) context;
}
}
@Override
protected void runTask() {
if (type == ContactsDialog.CONTACTS_BACKUP) {
List<ContactsData> contactInfo = null;
try {
contactInfo = getContactInfo(mContext);
Log.d(DEBUG_TAG, "contacts size :" + contactInfo.size());
backupContacts(contactInfo);
//send Broadcoast to upload
mContext.uploadContacts(mContactsPath);
} catch (SeafException e) {
setTaskException(e);
e.printStackTrace();
}
} else if (type == ContactsDialog.CONTACTS_RECOVERY) {
try {
List<ContactsData> infoList = restoreContacts();
for (int i = 0; i < infoList.size(); i++) {
addContacts(mContext, infoList.get(i));
progress(100 * i / infoList.size());
}
} catch (SeafException e) {
setTaskException(e);
e.printStackTrace();
}
}
}
/**
* read contacts
*
* @param context
* @return
*/
public List<ContactsData> getContactInfo(Context context) throws SeafException {
try {
List<ContactsData> infoList = new LinkedList<>();
Cursor cur = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur != null && cur.moveToFirst()) {
do {
ContactsData contactsData = new ContactsData();
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (displayName == null || "".equals(displayName)) {
// vcard libs nonsupport no name , so wo used '*' replace name
displayName = "*";
}
contactsData.setName(displayName);
contactsData.setUserid(id);
//read contacts phone
Cursor phonesCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id, null, null);
if (phonesCursor != null) {
LinkedList<ContactsData.PhoneInfo> phoneInfos = new LinkedList<>();
if (phonesCursor.moveToFirst()) {
do {
ContactsData.PhoneInfo phoneInfo = new ContactsData.PhoneInfo();
String phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds
.Phone.NUMBER));
int type = phonesCursor.getInt(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone
.TYPE));
phoneInfo.setNumber(phoneNumber);
phoneInfo.setType(type);
phoneInfos.add(phoneInfo);
} while (phonesCursor.moveToNext());
}
phonesCursor.close();
contactsData.setPhoneList(phoneInfos);
}
//read contacts email
Cursor emailCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=" + id, null, null);
if (emailCur != null) {
LinkedList<ContactsData.EmailInfo> emailInfos = new LinkedList<>();
if (emailCur.moveToFirst()) {
do {
ContactsData.EmailInfo emailInfo = new ContactsData.EmailInfo();
String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email
.DATA1));
int type = emailCur.getInt(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
emailInfo.setEmail(email);
emailInfo.setType(type);
emailInfos.add(emailInfo);
} while (emailCur.moveToNext());
}
emailCur.close();
contactsData.setEmail(emailInfos);
}
infoList.add(contactsData);
int progress = cur.getPosition() * 100 / cur.getCount();
progress(progress);
} while (cur.moveToNext());
cur.close();
}
return infoList;
} catch (Exception e) {
throw new SeafException(0, mContext.getString(R.string.contacts_backup_fail));
}
}
private static final String CONTACTS_FILE_NAME = "contacts-%1s.vcf";
static String getContactsBackupFileName() {
return String.format(CONTACTS_FILE_NAME, Utils.translateTime());
}
/**
* write contacts to SD card
*/
public void backupContacts(List<ContactsData> infos) throws SeafException {
if (infos == null || infos.size() == 0) {
throw new SeafException(0, mContext.getString(R.string.contacts_count_zero));
}
try {
mAccounts = new AccountManager(SeadroidApplication.getAppContext()).getAccountList();
String path = new DataManager(mAccounts.get(0)).getAccountDir() + "/temp/";
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
mContactsPath = fileDir.toString() + "/" + getContactsBackupFileName();
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(mContactsPath), "UTF-8");
VCardComposer composer = new VCardComposer();
for (ContactsData contactsData : infos) {
ContactStruct contact = new ContactStruct();
contact.name = contactsData.getName();
List<ContactsData.PhoneInfo> phoneList = contactsData.getPhoneList();
if (phoneList != null && phoneList.size() > 0) {
for (ContactsData.PhoneInfo phoneInfo : phoneList) {
contact.addPhone(phoneInfo.getType(), phoneInfo.getNumber(), "", true);
}
}
List<ContactsData.EmailInfo> emailList = contactsData.getEmail();
if (emailList != null && emailList.size() > 0) {
for (ContactsData.EmailInfo emailInfo : emailList) {
contact.addContactmethod(Contacts.KIND_EMAIL, emailInfo.getType(), emailInfo.getEmail(), null, true);
}
}
String vcardString = composer.createVCard(contact, VCardComposer.VERSION_VCARD30_INT);
writer.write(vcardString);
writer.write("\n");
writer.flush();
}
writer.close();
} catch (Exception e) {
e.printStackTrace();
throw new SeafException(0, mContext.getString(R.string.contacts_backup_fail));
}
}
/**
* get contacts from vCard
*
* @return
*/
public List<ContactsData> restoreContacts() throws SeafException {
try {
List<Account> accounts = new AccountManager(SeadroidApplication.getAppContext()).getAccountList();
DataManager dataManager = new DataManager(accounts.get(0));
SettingsManager settingsManager = SettingsManager.instance();
String repoId = settingsManager.getContactsUploadRepoId();
String repoName = settingsManager.getContactsUploadRepoName();
List<SeafDirent> dirents = dataManager.getCachedDirents(repoId, "/");
if (dirents == null) {
dirents = dataManager.getDirentsFromServer(repoId, "/");
}
if (dirents != null) {
for (int i = 0; i < dirents.size(); i++) {
SeafDirent seafDirent = dirents.get(i);
if (seafDirent.isDir() && SettingsActivity.BASE_DIR.equals(seafDirent.getTitle())) {
mPath = Utils.pathJoin("/", seafDirent.getTitle());
List<SeafDirent> childDirents = dataManager.getCachedDirents(repoId, mPath);
if (childDirents != null) {
for (int j = 0; j < childDirents.size(); j++) {
SeafDirent childDirent = childDirents.get(j);
if (!childDirent.isDir()) {
String title = childDirent.getTitle();
if (title.indexOf("contacts") != -1) {
if (childDirent.mtime > mMtime) {
mMtime = childDirent.mtime;
this.seafDirent = childDirent;
}
}
}
}
}
}
}
}
final String filePath = Utils.pathJoin(mPath, seafDirent.name);
File localFile = dataManager.getLocalCachedFile(repoName, repoId, filePath, seafDirent.id);
if (localFile == null) {
mContext.txService.addDownloadTask(accounts.get(0), repoName, repoId, filePath, seafDirent.size);
localFile = dataManager.getLocalCachedFile(repoName, repoId, filePath, seafDirent.id);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(localFile), "UTF-8"));
String vcardString = "";
String line;
while ((line = reader.readLine()) != null) {
vcardString += line + "\n";
}
reader.close();
VCardParser parse = new VCardParser();
VDataBuilder builder = new VDataBuilder();
boolean parsed = parse.parse(vcardString, "UTF-8", builder);
if (!parsed) {
throw new VCardException("Could not parse vCard file:" + R.drawable.file);
}
List<VNode> pimContacts = builder.vNodeList;
List<ContactsData> contactInfoList = new ArrayList<>();
for (VNode contact : pimContacts) {
ContactStruct contactStruct = ContactStruct.constructContactFromVNode(contact, 1);
ContactsData contactsData = new ContactsData();
contactsData.setName(contactStruct.name);
// get phone numb
List<ContactStruct.PhoneData> phoneDataList = contactStruct.phoneList;
if (phoneDataList != null && phoneDataList.size() > 0) {
LinkedList<ContactsData.PhoneInfo> phoneInfos = new LinkedList<>();
for (ContactStruct.PhoneData phoneDate : phoneDataList) {
ContactsData.PhoneInfo phoneInfo = new ContactsData.PhoneInfo();
phoneInfo.setType(phoneDate.type);
phoneInfo.setNumber(phoneDate.data);
phoneInfos.add(phoneInfo);
}
contactsData.setPhoneList(phoneInfos);
}
//get email
List<ContactStruct.ContactMethod> emailList = contactStruct.contactmethodList;
if (emailList != null && emailList.size() > 0) {
LinkedList<ContactsData.EmailInfo> emailInfos = new LinkedList<>();
for (ContactStruct.ContactMethod contactMethod : emailList) {
if (Contacts.KIND_EMAIL == contactMethod.kind) {
ContactsData.EmailInfo emailInfo = new ContactsData.EmailInfo();
emailInfo.setType(contactMethod.type);
emailInfo.setEmail(contactMethod.data);
emailInfos.add(emailInfo);
}
}
contactsData.setEmail(emailInfos);
}
contactInfoList.add(contactsData);
}
return contactInfoList;
} catch (Exception e) {
e.printStackTrace();
throw new SeafException(0, mContext.getString(R.string.contacts_recover_fail));
}
}
/**
* add contacts to phone
*
* @param context
* @param info
* @throws SeafException
*/
public void addContacts(Context context, ContactsData info) throws SeafException {
try {
ContentValues values = new ContentValues();
Uri rawContactUri = context.getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
values.clear();
values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, info.getName());
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
List<ContactsData.PhoneInfo> phoneList = info.getPhoneList();
for (ContactsData.PhoneInfo phoneInfo : phoneList) {
values.clear();
values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneInfo.getNumber());
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, phoneInfo.getType());
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
List<ContactsData.EmailInfo> emailList = info.getEmail();
for (ContactsData.EmailInfo email : emailList) {
values.clear();
values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Email.DATA, email.getEmail());
values.put(ContactsContract.CommonDataKinds.Email.TYPE, email.getType());
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
} catch (Exception e) {
e.printStackTrace();
throw new SeafException(0, mContext.getString(R.string.contacts_recover_fail));
}
}
}