package org.mots.haxsync.services;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.mots.haxsync.R;
import org.mots.haxsync.provider.FacebookFQLFriend;
import org.mots.haxsync.provider.FacebookGraphFriend;
import org.mots.haxsync.provider.Status;
import org.mots.haxsync.utilities.BitmapUtil;
import org.mots.haxsync.utilities.ContactUtil;
import org.mots.haxsync.utilities.ContactUtil.Photo;
import org.mots.haxsync.utilities.DeviceUtil;
import org.mots.haxsync.utilities.FacebookUtil;
import org.mots.haxsync.utilities.RootUtil;
import org.mots.haxsync.utilities.WebUtil;
import com.jjnford.android.util.Shell.ShellException;
import android.accounts.Account;
import android.accounts.OperationCanceledException;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.SyncResult;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.RawContacts.Entity;
import android.util.Log;
public class ContactsSyncAdapterService extends Service {
private static final String TAG = "ContactsSyncAdapterService";
private static SyncAdapterImpl sSyncAdapter = null;
public static ContentResolver mContentResolver = null;
private static String UsernameColumn = ContactsContract.RawContacts.SYNC1;
private static String PhotoTimestampColumn = ContactsContract.RawContacts.SYNC2;
public ContactsSyncAdapterService() {
super();
}
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
private Context mContext;
public SyncAdapterImpl(Context context) {
super(context, true);
mContext = context;
}
@Override
public void onPerformSync(Account account, Bundle extras,
String authority, ContentProviderClient provider,
SyncResult syncResult) {
try {
ContactsSyncAdapterService.performSync(mContext, account,
extras, authority, provider, syncResult);
} catch (OperationCanceledException e) {
}
}
}
@Override
public IBinder onBind(Intent intent) {
IBinder ret = null;
ret = getSyncAdapter().getSyncAdapterBinder();
return ret;
}
private SyncAdapterImpl getSyncAdapter() {
if (sSyncAdapter == null)
sSyncAdapter = new SyncAdapterImpl(this);
return sSyncAdapter;
}
private static String matches(Set<String> phoneContacts, String fbContact, int maxdistance){
if (maxdistance == 0){
if (phoneContacts.contains(fbContact)){
return fbContact;
}
return null;
//return phoneContacts.contains(fbContact);
}
int bestDistance = maxdistance;
String bestMatch = null;
for (String contact : phoneContacts){
int distance = StringUtils.getLevenshteinDistance(contact != null ? contact.toLowerCase() : "", fbContact != null ? fbContact.toLowerCase() : "");
if( distance <= bestDistance){
//Log.i("FOUND MATCH", "Phone Contact: " + contact +" FB Contact: " + fbContact +" distance: " + distance + "max distance: " +maxdistance);
bestMatch = contact;
bestDistance = distance;
}
}
return bestMatch;
}
private static void addContact(Account account, String name, String username) {
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = ContentProviderOperation
.newInsert(RawContacts.CONTENT_URI);
builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
builder.withValue(RawContacts.SYNC1, username);
operationList.add(builder.build());
builder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(
ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID,
0);
builder.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
name);
operationList.add(builder.build());
builder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE,
"vnd.android.cursor.item/vnd.org.mots.haxsync.profile");
builder.withValue(ContactsContract.Data.DATA1, username);
builder.withValue(ContactsContract.Data.DATA2, "Facebook Profile");
builder.withValue(ContactsContract.Data.DATA3, "View profile");
operationList.add(builder.build());
try {
mContentResolver.applyBatch(ContactsContract.AUTHORITY,
operationList);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void addSelfContact(Account account, int maxSize, boolean square, boolean faceDetect, boolean force, boolean root, int rootsize, File cacheDir, boolean google) {
Uri rawContactUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
.build();
long ID = -2;
String username = null;
String email = null;
FacebookGraphFriend user = FacebookUtil.getSelfInfo();
if (user == null)
return;
Cursor cursor = mContentResolver.query(rawContactUri, new String[] {BaseColumns._ID, UsernameColumn}, null, null, null);
if (cursor.getCount() > 0){
cursor.moveToFirst();
ID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
username = cursor.getString(cursor.getColumnIndex(UsernameColumn));
cursor.close();
} else {
cursor.close();
username = user.getUserName();
email = user.getEmail();
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = ContentProviderOperation
.newInsert(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI);
builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
builder.withValue(RawContacts.SYNC1, username);
operationList.add(builder.build());
builder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(
ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID,
0);
builder.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
account.name);
operationList.add(builder.build());
builder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE,
"vnd.android.cursor.item/vnd.org.mots.haxsync.profile");
builder.withValue(ContactsContract.Data.DATA1, username);
builder.withValue(ContactsContract.Data.DATA2, "Facebook Profile");
builder.withValue(ContactsContract.Data.DATA3, "View profile");
operationList.add(builder.build());
if (email != null){
builder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
operationList.add(builder.build());
}
try {
mContentResolver.applyBatch(ContactsContract.AUTHORITY,
operationList);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
cursor = mContentResolver.query(rawContactUri, new String[] {BaseColumns._ID}, null, null, null);
if (cursor.getCount() > 0){
cursor.moveToFirst();
ID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
cursor.close();
} else{
Log.i(TAG, "NO SELF CONTACT FOUND");
return;
}
}
Log.i("self contact", "id: "+ID+" uid: "+ username);
if (ID != -2 && username != null){
updateContactPhoto(ID, 0, maxSize, square, user.getPicURL(), faceDetect, true, root, rootsize, cacheDir, google, true);
}
}
private static void updateContactStatus(long rawContactId, String status,
long timeStamp) {
if (status != null && timeStamp != 0){
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
rawContactId);
Uri entityUri = Uri.withAppendedPath(rawContactUri,
Entity.CONTENT_DIRECTORY);
Cursor c = mContentResolver.query(entityUri, new String[] {
RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE,
Entity.DATA1 }, null, null, null);
try {
while (c.moveToNext()) {
if (!c.isNull(1)) {
String mimeType = c.getString(2);
if (mimeType
.equals("vnd.android.cursor.item/vnd.org.mots.haxsync.profile")) {
ContentProviderOperation.Builder builder = ContentProviderOperation
.newInsert(ContactsContract.StatusUpdates.CONTENT_URI);
builder.withValue(
ContactsContract.StatusUpdates.DATA_ID,
c.getLong(1));
builder.withValue(
ContactsContract.StatusUpdates.STATUS, status);
builder.withValue(
ContactsContract.StatusUpdates.STATUS_RES_PACKAGE,
"org.mots.haxsync");
builder.withValue(
ContactsContract.StatusUpdates.STATUS_LABEL,
R.string.app_name);
builder.withValue(
ContactsContract.StatusUpdates.STATUS_ICON,
R.drawable.icon);
builder.withValue(
ContactsContract.StatusUpdates.STATUS_TIMESTAMP,
timeStamp);
operationList.add(builder.build());
}
}
}
} finally {
c.close();
}
try {
mContentResolver.applyBatch(ContactsContract.AUTHORITY,
operationList);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static void updateContactPhoto(long rawContactId, long timestamp, int maxSize, boolean square, String imgUrl, boolean faceDetect, boolean force, boolean root, int rootsize, File cacheDir, boolean google, boolean primary) {
if (imgUrl != null){
String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId
+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
//getting the old timestamp
String oldurl = "";
boolean newpic = force;
if (!newpic){
Cursor c1 = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.SYNC3 }, where , null, null);
if (c1.getCount() > 0){
c1.moveToLast();
if (!c1.isNull(c1.getColumnIndex(ContactsContract.Data.SYNC3))){
oldurl = c1.getString(c1.getColumnIndex(ContactsContract.Data.SYNC3));
//Log.i(TAG, "read old timestamp: " + oldTimestamp);
}
}
c1.close();
//Log.i(TAG, "Old Timestamp " +String.valueOf(oldTimestamp) + "new timestamp: " + String.valueOf(timestamp));
if (!oldurl.equals(imgUrl)){
Log.i(TAG, "OLD URL: " + oldurl);
Log.i(TAG, "NEW URL: " + imgUrl);
newpic = true;
}
}
if (newpic){
Log.i(TAG, "getting new image, "+imgUrl);
// Log.i(TAG, "Old Timestamp " +String.valueOf(oldTimestamp) + "new timestamp: " + String.valueOf(timestamp));
byte[] photo = WebUtil.download(imgUrl);
byte[] origPhoto = photo;
/*if(square)
photo = BitmapUtil.resize(photo, maxSize, faceDetect);*/
ContactUtil.Photo photoi = new Photo();
photoi.data = photo;
photoi.timestamp = timestamp;
photoi.url = imgUrl;
ContactUtil.updateContactPhoto(mContentResolver, rawContactId, photoi, primary);
if (root){
Cursor c1 = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID}, where , null, null);
if (c1.getCount() > 0){
c1.moveToLast();
String photoID = c1.getString(c1.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID));
c1.close();
if (photoID != null){
photo = BitmapUtil.resize(origPhoto, rootsize, faceDetect);
String picpath = DeviceUtil.saveBytes(photo, cacheDir);
try {
String newpath = RootUtil.movePic(picpath, photoID);
RootUtil.changeOwner(newpath);
} catch (Exception e) {
Log.e("ROOT EXCEPTION", e.getMessage());
// TODO: handle exception
}
}
}
}
Log.i("google photo sync", String.valueOf(google));
if (google){
for (long raw : ContactUtil.getRawContacts(mContentResolver, rawContactId, "com.google")){
Log.i("google rawid", String.valueOf(raw));
ContactUtil.updateContactPhoto(mContentResolver, raw, photoi, false);
}
}
}
}
}
public static class SyncEntry {
public Long raw_id = 0L;
}
private static HashMap<String, Long> loadHTCData(Context c){
mContentResolver = c.getContentResolver();
/*ArrayList<Long> contactIDs = new ArrayList<Long>();
Cursor c1 = mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, new String[] { BaseColumns._ID }, ContactsContract.Contacts.IN_VISIBLE_GROUP +" = 1", null, null);
while (c1.moveToNext()){
contactIDs.add(c1.getLong(c1.getColumnIndex(BaseColumns._ID)));
}
c1.close();*/
HashMap<String, Long> contacts = new HashMap<String, Long>();
//Cursor cursor = mContentResolver.query(ContactsContract.Data.CONTENT_URI, null, ContactsContract.Data.MIMETYPE +"= ?", ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE, null);
String noteWhere = ContactsContract.Data.MIMETYPE + " = ?";
String[] noteWhereParams = new String[]{ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE};
Cursor cursor = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] {ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.CommonDataKinds.Note.NOTE}, noteWhere, noteWhereParams, null);
while (cursor.moveToNext()) {
try{
String note = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE));
if (note != null){
if (note.startsWith("<HTCData>")){
Pattern fbPattern = Pattern.compile("<Facebook>id:(.*)/friendof.*</Facebook>", Pattern.CASE_INSENSITIVE);
Matcher fbMatcher = fbPattern.matcher(note);
while (fbMatcher.find()){
String uid = fbMatcher.group(1);
//Log.i("found HTCDATA", uid);
Long rawID = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));
contacts.put(uid, rawID);
}
//String uid = note.split("/friendof")[0].substring(22);
}
}
} catch (IllegalStateException e){
Log.e(TAG, "Error loading HTCDATA");
break;
}
}
cursor.close();
return contacts;
}
private static HashMap<String, Long> loadPhoneContacts(Context c){
mContentResolver = c.getContentResolver();
HashMap<String, Long> contacts = new HashMap<String, Long>();
Cursor cursor = mContentResolver.query(
Phone.CONTENT_URI,
new String[]{Phone.DISPLAY_NAME, Phone.RAW_CONTACT_ID},
null,
null,
null);
while (cursor.moveToNext()) {
contacts.put(cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)), cursor.getLong(cursor.getColumnIndex(Phone.RAW_CONTACT_ID)));
//names.add(cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)));
}
cursor.close();
return contacts;
}
public static HashMap<String, SyncEntry> getLocalContacts(Account account){
Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
.build();
HashMap<String, SyncEntry> localContacts = new HashMap<String, SyncEntry>();
Cursor c1 = mContentResolver.query(rawContactUri, new String[] { BaseColumns._ID, UsernameColumn, PhotoTimestampColumn }, null, null, null);
while (c1.moveToNext()) {
SyncEntry entry = new SyncEntry();
entry.raw_id = c1.getLong(c1.getColumnIndex(BaseColumns._ID));
localContacts.put(c1.getString(1), entry);
}
c1.close();
return localContacts;
}
@SuppressWarnings("unused")
private static void performSync(Context context, Account account,
Bundle extras, String authority, ContentProviderClient provider,
SyncResult syncResult) throws OperationCanceledException {
SharedPreferences prefs = context.getSharedPreferences(context.getPackageName() + "_preferences", MODE_MULTI_PROCESS);
mContentResolver = context.getContentResolver();
FacebookUtil.refreshPermissions(context);
//TODO: Clean up stuff that isn't needed anymore since Graph API
boolean cropPhotos = true;
boolean sync = prefs.getBoolean("sync_status", true);
boolean syncNew = prefs.getBoolean("status_new", true);
boolean syncLocation = prefs.getBoolean("sync_location", true);
boolean syncSelf = prefs.getBoolean("sync_self", false);
boolean imageDefault = prefs.getBoolean("image_primary", true);
boolean oldStatus = sync && (!syncNew || (Build.VERSION.SDK_INT < 15));
boolean faceDetect = true;
boolean root = prefs.getBoolean("root_enabled", false);
int rootSize = 512;
if(FacebookUtil.authorize(context, account)){
HashMap<String, SyncEntry> localContacts = getLocalContacts(account);
HashMap<String, Long> names = loadPhoneContacts(context);
HashMap<String, Long> uids = loadHTCData(context);
//Log.i("CONTACTS", names.toString());
boolean phoneOnly = prefs.getBoolean("phone_only", true);
/*if (phoneOnly){
names = loadPhoneContacts(context);
}*/
boolean wifiOnly = prefs.getBoolean("wifi_only", false);
boolean syncEmail = prefs.getBoolean("sync_facebook_email", false);
boolean syncBirthday = prefs.getBoolean("sync_contact_birthday", true);
boolean force = prefs.getBoolean("force_dl", false);
boolean google = prefs.getBoolean("update_google_photos", false);
boolean ignoreMiddleaNames = prefs.getBoolean("ignore_middle_names",false);
boolean addMeToFriends = prefs.getBoolean("add_me_to_friends", false);
Log.i("google", String.valueOf(google));
int fuzziness = Integer.parseInt(prefs.getString("fuzziness", "2"));
Set<String> addFriends = prefs.getStringSet("add_friends", new HashSet<String>());
Log.i(TAG, "phone_only: " + Boolean.toString(phoneOnly));
Log.i(TAG, "wifi_only: " + Boolean.toString(wifiOnly));
Log.i(TAG, "is wifi: " + Boolean.toString(DeviceUtil.isWifi(context)));
Log.i(TAG, "phone contacts: " + names.toString());
Log.i(TAG, "using old status api: " +String.valueOf(oldStatus));
Log.i(TAG, "ignoring middle names : " + String.valueOf(ignoreMiddleaNames));
Log.i(TAG, "add me to friends : "+ String.valueOf(addMeToFriends));
boolean chargingOnly = prefs.getBoolean("charging_only", false);
int maxsize = BitmapUtil.getMaxSize(context);
File cacheDir = context.getCacheDir();
Log.i("CACHE DIR", cacheDir.getAbsolutePath());
Log.i("MAX IMAGE SIZE", String.valueOf(maxsize));
if (!((wifiOnly && !DeviceUtil.isWifi(context)) || (chargingOnly && !DeviceUtil.isCharging(context)))){
try {
if (syncSelf){
addSelfContact(account, maxsize, cropPhotos, faceDetect, force, root, rootSize, cacheDir, google);
}
//ArrayList<FacebookFQLFriend> friends = FacebookUtil.getFriendInfo(oldStatus);
List<FacebookGraphFriend> friends = FacebookUtil.getFriends(maxsize, addMeToFriends);
for (FacebookGraphFriend friend : friends) {
String uid = friend.getUserName();
String friendName = friend.getName(ignoreMiddleaNames);
if (friendName != null && uid != null){
String match = matches(names.keySet(), friendName , fuzziness);
if (!(phoneOnly && (match == null) && !uids.containsKey(uid)) || addFriends.contains(friendName)){
//add contact
if (localContacts.get(uid) == null) {
//String name = friend.getString("name");
//Log.i(TAG, name + " already on phone: " + Boolean.toString(names.contains(name)));
addContact(account, friendName, uid);
SyncEntry entry = new SyncEntry();
Uri rawContactUr = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
.appendQueryParameter(RawContacts.Data.DATA1, uid)
.build();
Cursor c =mContentResolver.query(rawContactUr, new String[] {
BaseColumns._ID}, null,
null, null);
c.moveToLast();
long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
c.close();
// Log.i("ID", Long.toString(id));
entry.raw_id = id;
localContacts.put(uid, entry);
if (uids.containsKey(uid)){
ContactUtil.merge(context, uids.get(uid), id);
} else if (names.containsKey(match)){
ContactUtil.merge(context, names.get(match), id);
}
//localContacts = loadContacts(accounts, context);
}
// set contact photo
SyncEntry contact = localContacts.get(uid);
updateContactPhoto(contact.raw_id, friend.getPicTimestamp(), maxsize, cropPhotos, friend.getPicURL(), faceDetect, force, root, rootSize, cacheDir, google, imageDefault);
if (syncEmail && !FacebookUtil.RESPECT_FACEBOOK_POLICY)
ContactUtil.addEmail(context, contact.raw_id, friend.getEmail());
if (syncLocation && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
ContactUtil.updateContactLocation(contact.raw_id, friend.getLocation());
}
if (oldStatus && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
ArrayList<Status> statuses = friend.getStatuses();
if (statuses.size() >= 1){
updateContactStatus(contact.raw_id,
statuses.get(0).getMessage(), statuses.get(0).getTimestamp());
}
}
if (syncBirthday && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
String birthday = friend.getBirthday();
if (birthday != null){
ContactUtil.addBirthday(contact.raw_id, birthday);
}
}
}
}
} }catch (Exception e) {
// TODO: handle exception
Log.e("ERROR", e.toString());
e.printStackTrace();
}
if (root){
try {
RootUtil.refreshContacts();
} catch (ShellException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (force){
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("force_dl", false);
editor.commit();
}
} else {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("missed_contact_sync", true);
editor.commit();
}
}
}
}