2014-02-04 19:36:55 +01:00
/ *
* This is the source code of Telegram for Android v . 1 . 3 . x .
* It is licensed under GNU GPL v . 2 or later .
* You should have received a copy of the license in this archive ( see LICENSE ) .
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov , 2013 - 2018 .
2014-02-04 19:36:55 +01:00
* /
2015-09-24 22:52:02 +02:00
package org.telegram.messenger ;
2014-02-04 19:36:55 +01:00
import android.accounts.Account ;
import android.accounts.AccountManager ;
import android.content.ContentProviderOperation ;
import android.content.ContentProviderResult ;
import android.content.ContentResolver ;
2015-05-03 13:48:36 +02:00
import android.content.ContentValues ;
2014-11-10 12:05:22 +01:00
import android.content.SharedPreferences ;
2015-10-29 18:10:07 +01:00
import android.content.pm.PackageManager ;
2018-07-30 04:07:02 +02:00
import android.database.ContentObserver ;
2014-02-04 19:36:55 +01:00
import android.database.Cursor ;
2018-07-30 04:07:02 +02:00
import android.database.DatabaseUtils ;
2014-02-04 19:36:55 +01:00
import android.net.Uri ;
2015-10-29 18:10:07 +01:00
import android.os.Build ;
2014-02-04 19:36:55 +01:00
import android.provider.BaseColumns ;
import android.provider.ContactsContract ;
2015-07-22 20:56:37 +02:00
import android.text.TextUtils ;
2018-07-30 04:07:02 +02:00
import android.util.SparseArray ;
2014-02-04 19:36:55 +01:00
import org.telegram.PhoneFormat.PhoneFormat ;
2018-07-30 04:07:02 +02:00
import org.telegram.messenger.support.SparseLongArray ;
2015-09-24 22:52:02 +02:00
import org.telegram.tgnet.ConnectionsManager ;
import org.telegram.tgnet.TLRPC ;
2021-02-23 12:53:38 +01:00
import org.telegram.ui.Components.Bulletin ;
2014-02-04 19:36:55 +01:00
import java.util.ArrayList ;
2020-07-26 10:03:38 +02:00
import java.util.Arrays ;
2014-02-04 19:36:55 +01:00
import java.util.Collections ;
import java.util.HashMap ;
import java.util.concurrent.ConcurrentHashMap ;
2020-05-28 09:29:33 +02:00
import tw.nekomimi.nekogram.NekoConfig ;
2019-07-18 15:01:39 +02:00
public class ContactsController extends BaseController {
2014-11-17 23:04:31 +01:00
2018-07-30 04:07:02 +02:00
private Account systemAccount ;
2017-12-08 18:35:59 +01:00
private boolean loadingContacts ;
2018-07-30 04:07:02 +02:00
private final Object loadContactsSync = new Object ( ) ;
2017-12-08 18:35:59 +01:00
private boolean ignoreChanges ;
private boolean contactsSyncInProgress ;
2014-10-05 23:23:57 +02:00
private final Object observerLock = new Object ( ) ;
2017-12-08 18:35:59 +01:00
public boolean contactsLoaded ;
private boolean contactsBookLoaded ;
private boolean migratingContacts ;
2014-08-06 23:27:24 +02:00
private String lastContactsVersions = " " ;
2015-01-02 23:15:07 +01:00
private ArrayList < Integer > delayedContactsUpdate = new ArrayList < > ( ) ;
2017-12-08 18:35:59 +01:00
private String inviteLink ;
private boolean updatingInviteLink ;
2015-02-26 02:32:51 +01:00
private HashMap < String , String > sectionsToReplace = new HashMap < > ( ) ;
2014-02-04 19:36:55 +01:00
2020-07-26 10:03:38 +02:00
private int loadingGlobalSettings ;
2017-03-31 01:58:05 +02:00
private int loadingDeleteInfo ;
2014-11-17 03:44:57 +01:00
private int deleteAccountTTL ;
2019-06-04 12:14:50 +02:00
private int [ ] loadingPrivacyInfo = new int [ PRIVACY_RULES_TYPE_COUNT ] ;
private ArrayList < TLRPC . PrivacyRule > lastseenPrivacyRules ;
2017-12-08 18:35:59 +01:00
private ArrayList < TLRPC . PrivacyRule > groupPrivacyRules ;
private ArrayList < TLRPC . PrivacyRule > callPrivacyRules ;
2019-01-23 18:03:33 +01:00
private ArrayList < TLRPC . PrivacyRule > p2pPrivacyRules ;
2019-05-14 14:08:05 +02:00
private ArrayList < TLRPC . PrivacyRule > profilePhotoPrivacyRules ;
private ArrayList < TLRPC . PrivacyRule > forwardsPrivacyRules ;
2019-06-04 12:14:50 +02:00
private ArrayList < TLRPC . PrivacyRule > phonePrivacyRules ;
2019-09-10 12:56:11 +02:00
private ArrayList < TLRPC . PrivacyRule > addedByPhonePrivacyRules ;
2020-07-26 10:03:38 +02:00
private TLRPC . TL_globalPrivacySettings globalPrivacySettings ;
2019-06-04 12:14:50 +02:00
public final static int PRIVACY_RULES_TYPE_LASTSEEN = 0 ;
public final static int PRIVACY_RULES_TYPE_INVITE = 1 ;
public final static int PRIVACY_RULES_TYPE_CALLS = 2 ;
public final static int PRIVACY_RULES_TYPE_P2P = 3 ;
public final static int PRIVACY_RULES_TYPE_PHOTO = 4 ;
public final static int PRIVACY_RULES_TYPE_FORWARDS = 5 ;
public final static int PRIVACY_RULES_TYPE_PHONE = 6 ;
2019-09-10 12:56:11 +02:00
public final static int PRIVACY_RULES_TYPE_ADDED_BY_PHONE = 7 ;
2019-06-04 12:14:50 +02:00
2019-09-10 12:56:11 +02:00
public final static int PRIVACY_RULES_TYPE_COUNT = 8 ;
2014-11-17 03:44:57 +01:00
2018-07-30 04:07:02 +02:00
private class MyContentObserver extends ContentObserver {
2019-01-23 18:03:33 +01:00
private Runnable checkRunnable = ( ) - > {
for ( int a = 0 ; a < UserConfig . MAX_ACCOUNT_COUNT ; a + + ) {
if ( UserConfig . getInstance ( a ) . isClientActivated ( ) ) {
ConnectionsManager . getInstance ( a ) . resumeNetworkMaybe ( ) ;
ContactsController . getInstance ( a ) . checkContacts ( ) ;
2018-07-30 04:07:02 +02:00
}
}
} ;
public MyContentObserver ( ) {
super ( null ) ;
}
@Override
public void onChange ( boolean selfChange ) {
super . onChange ( selfChange ) ;
synchronized ( observerLock ) {
if ( ignoreChanges ) {
return ;
}
}
Utilities . globalQueue . cancelRunnable ( checkRunnable ) ;
Utilities . globalQueue . postRunnable ( checkRunnable , 500 ) ;
}
@Override
public boolean deliverSelfNotifications ( ) {
return false ;
}
}
2014-02-04 19:36:55 +01:00
public static class Contact {
2017-12-08 18:35:59 +01:00
public int contact_id ;
public String key ;
2018-07-30 04:07:02 +02:00
public String provider ;
public boolean isGoodProvider ;
public ArrayList < String > phones = new ArrayList < > ( 4 ) ;
public ArrayList < String > phoneTypes = new ArrayList < > ( 4 ) ;
public ArrayList < String > shortPhones = new ArrayList < > ( 4 ) ;
public ArrayList < Integer > phoneDeleted = new ArrayList < > ( 4 ) ;
2014-02-04 19:36:55 +01:00
public String first_name ;
public String last_name ;
2018-07-30 04:07:02 +02:00
public boolean namesFilled ;
2017-12-08 18:35:59 +01:00
public int imported ;
2018-07-30 04:07:02 +02:00
public TLRPC . User user ;
public String getLetter ( ) {
return getLetter ( first_name , last_name ) ;
}
public static String getLetter ( String first_name , String last_name ) {
String key ;
if ( ! TextUtils . isEmpty ( first_name ) ) {
return first_name . substring ( 0 , 1 ) ;
} else if ( ! TextUtils . isEmpty ( last_name ) ) {
return last_name . substring ( 0 , 1 ) ;
} else {
return " # " ;
}
}
2014-02-04 19:36:55 +01:00
}
2014-02-28 23:28:25 +01:00
private String [ ] projectionPhones = {
2017-12-08 18:35:59 +01:00
ContactsContract . CommonDataKinds . Phone . LOOKUP_KEY ,
2016-06-24 12:27:15 +02:00
ContactsContract . CommonDataKinds . Phone . NUMBER ,
ContactsContract . CommonDataKinds . Phone . TYPE ,
2018-07-30 04:07:02 +02:00
ContactsContract . CommonDataKinds . Phone . LABEL ,
ContactsContract . CommonDataKinds . Phone . DISPLAY_NAME ,
ContactsContract . RawContacts . ACCOUNT_TYPE ,
2014-02-04 19:36:55 +01:00
} ;
private String [ ] projectionNames = {
2017-12-08 18:35:59 +01:00
ContactsContract . CommonDataKinds . StructuredName . LOOKUP_KEY ,
2016-06-24 12:27:15 +02:00
ContactsContract . CommonDataKinds . StructuredName . GIVEN_NAME ,
ContactsContract . CommonDataKinds . StructuredName . FAMILY_NAME ,
2018-07-30 04:07:02 +02:00
ContactsContract . CommonDataKinds . StructuredName . MIDDLE_NAME ,
2014-02-04 19:36:55 +01:00
} ;
2017-12-08 18:35:59 +01:00
public HashMap < String , Contact > contactsBook = new HashMap < > ( ) ;
2015-01-02 23:15:07 +01:00
public HashMap < String , Contact > contactsBookSPhones = new HashMap < > ( ) ;
public ArrayList < Contact > phoneBookContacts = new ArrayList < > ( ) ;
2018-07-30 04:07:02 +02:00
public HashMap < String , ArrayList < Object > > phoneBookSectionsDict = new HashMap < > ( ) ;
public ArrayList < String > phoneBookSectionsArray = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
2015-01-02 23:15:07 +01:00
public ArrayList < TLRPC . TL_contact > contacts = new ArrayList < > ( ) ;
2017-12-08 18:35:59 +01:00
public ConcurrentHashMap < Integer , TLRPC . TL_contact > contactsDict = new ConcurrentHashMap < > ( 20 , 1 . 0f , 2 ) ;
2015-01-02 23:15:07 +01:00
public HashMap < String , ArrayList < TLRPC . TL_contact > > usersSectionsDict = new HashMap < > ( ) ;
public ArrayList < String > sortedUsersSectionsArray = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
2015-09-24 22:52:02 +02:00
public HashMap < String , ArrayList < TLRPC . TL_contact > > usersMutualSectionsDict = new HashMap < > ( ) ;
public ArrayList < String > sortedUsersMutualSectionsArray = new ArrayList < > ( ) ;
2015-01-02 23:15:07 +01:00
public HashMap < String , TLRPC . TL_contact > contactsByPhone = new HashMap < > ( ) ;
2017-12-08 18:35:59 +01:00
public HashMap < String , TLRPC . TL_contact > contactsByShortPhone = new HashMap < > ( ) ;
2014-02-28 23:28:25 +01:00
2016-06-24 12:27:15 +02:00
private int completedRequestsCount ;
2020-06-25 17:29:04 +02:00
2019-06-04 12:14:50 +02:00
private static volatile ContactsController [ ] Instance = new ContactsController [ UserConfig . MAX_ACCOUNT_COUNT ] ;
2018-07-30 04:07:02 +02:00
public static ContactsController getInstance ( int num ) {
ContactsController localInstance = Instance [ num ] ;
2014-03-22 23:31:55 +01:00
if ( localInstance = = null ) {
synchronized ( ContactsController . class ) {
2018-07-30 04:07:02 +02:00
localInstance = Instance [ num ] ;
2014-03-22 23:31:55 +01:00
if ( localInstance = = null ) {
2018-07-30 04:07:02 +02:00
Instance [ num ] = localInstance = new ContactsController ( num ) ;
2014-03-22 23:31:55 +01:00
}
}
}
return localInstance ;
}
2018-07-30 04:07:02 +02:00
public ContactsController ( int instance ) {
2019-07-18 15:01:39 +02:00
super ( instance ) ;
2018-07-30 04:07:02 +02:00
SharedPreferences preferences = MessagesController . getMainSettings ( currentAccount ) ;
2014-11-17 23:04:31 +01:00
if ( preferences . getBoolean ( " needGetStatuses " , false ) ) {
reloadContactsStatuses ( ) ;
}
2015-02-26 02:32:51 +01:00
sectionsToReplace . put ( " À " , " A " ) ;
sectionsToReplace . put ( " Á " , " A " ) ;
sectionsToReplace . put ( " Ä " , " A " ) ;
sectionsToReplace . put ( " Ù " , " U " ) ;
sectionsToReplace . put ( " Ú " , " U " ) ;
sectionsToReplace . put ( " Ü " , " U " ) ;
sectionsToReplace . put ( " Ì " , " I " ) ;
sectionsToReplace . put ( " Í " , " I " ) ;
sectionsToReplace . put ( " Ï " , " I " ) ;
sectionsToReplace . put ( " È " , " E " ) ;
sectionsToReplace . put ( " É " , " E " ) ;
sectionsToReplace . put ( " Ê " , " E " ) ;
sectionsToReplace . put ( " Ë " , " E " ) ;
sectionsToReplace . put ( " Ò " , " O " ) ;
sectionsToReplace . put ( " Ó " , " O " ) ;
sectionsToReplace . put ( " Ö " , " O " ) ;
sectionsToReplace . put ( " Ç " , " C " ) ;
sectionsToReplace . put ( " Ñ " , " N " ) ;
sectionsToReplace . put ( " Ÿ " , " Y " ) ;
sectionsToReplace . put ( " Ý " , " Y " ) ;
sectionsToReplace . put ( " Ţ " , " Y " ) ;
2018-07-30 04:07:02 +02:00
if ( instance = = 0 ) {
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
try {
if ( hasContactsPermission ( ) ) {
ApplicationLoader . applicationContext . getContentResolver ( ) . registerContentObserver ( ContactsContract . Contacts . CONTENT_URI , true , new MyContentObserver ( ) ) ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
} catch ( Throwable ignore ) {
2018-07-30 04:07:02 +02:00
}
} ) ;
}
2014-11-17 23:04:31 +01:00
}
2014-02-04 19:36:55 +01:00
public void cleanup ( ) {
contactsBook . clear ( ) ;
contactsBookSPhones . clear ( ) ;
2014-11-10 12:05:22 +01:00
phoneBookContacts . clear ( ) ;
2014-02-04 19:36:55 +01:00
contacts . clear ( ) ;
contactsDict . clear ( ) ;
usersSectionsDict . clear ( ) ;
2015-09-24 22:52:02 +02:00
usersMutualSectionsDict . clear ( ) ;
2014-02-04 19:36:55 +01:00
sortedUsersSectionsArray . clear ( ) ;
2015-09-24 22:52:02 +02:00
sortedUsersMutualSectionsArray . clear ( ) ;
2014-02-04 19:36:55 +01:00
delayedContactsUpdate . clear ( ) ;
2014-02-28 23:28:25 +01:00
contactsByPhone . clear ( ) ;
2017-12-08 18:35:59 +01:00
contactsByShortPhone . clear ( ) ;
2018-07-30 04:07:02 +02:00
phoneBookSectionsDict . clear ( ) ;
phoneBookSectionsArray . clear ( ) ;
2014-02-04 19:36:55 +01:00
loadingContacts = false ;
contactsSyncInProgress = false ;
contactsLoaded = false ;
contactsBookLoaded = false ;
2014-08-06 23:27:24 +02:00
lastContactsVersions = " " ;
2020-07-26 10:03:38 +02:00
loadingGlobalSettings = 0 ;
2014-11-17 03:44:57 +01:00
loadingDeleteInfo = 0 ;
deleteAccountTTL = 0 ;
2020-07-26 10:03:38 +02:00
Arrays . fill ( loadingPrivacyInfo , 0 ) ;
2019-06-04 12:14:50 +02:00
lastseenPrivacyRules = null ;
2019-01-23 18:03:33 +01:00
groupPrivacyRules = null ;
callPrivacyRules = null ;
p2pPrivacyRules = null ;
2019-05-14 14:08:05 +02:00
profilePhotoPrivacyRules = null ;
forwardsPrivacyRules = null ;
2019-06-04 12:14:50 +02:00
phonePrivacyRules = null ;
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
migratingContacts = false ;
completedRequestsCount = 0 ;
} ) ;
2014-02-04 19:36:55 +01:00
}
2014-11-10 12:05:22 +01:00
public void checkInviteText ( ) {
2018-07-30 04:07:02 +02:00
SharedPreferences preferences = MessagesController . getMainSettings ( currentAccount ) ;
2017-12-08 18:35:59 +01:00
inviteLink = preferences . getString ( " invitelink " , null ) ;
int time = preferences . getInt ( " invitelinktime " , 0 ) ;
if ( ! updatingInviteLink & & ( inviteLink = = null | | Math . abs ( System . currentTimeMillis ( ) / 1000 - time ) > = 86400 ) ) {
updatingInviteLink = true ;
2014-11-10 12:05:22 +01:00
TLRPC . TL_help_getInviteText req = new TLRPC . TL_help_getInviteText ( ) ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
if ( response ! = null ) {
final TLRPC . TL_help_inviteText res = ( TLRPC . TL_help_inviteText ) response ;
if ( res . message . length ( ) ! = 0 ) {
AndroidUtilities . runOnUIThread ( ( ) - > {
updatingInviteLink = false ;
SharedPreferences preferences1 = MessagesController . getMainSettings ( currentAccount ) ;
SharedPreferences . Editor editor = preferences1 . edit ( ) ;
editor . putString ( " invitelink " , inviteLink = res . message ) ;
editor . putInt ( " invitelinktime " , ( int ) ( System . currentTimeMillis ( ) / 1000 ) ) ;
editor . commit ( ) ;
} ) ;
2014-11-10 12:05:22 +01:00
}
}
2015-09-24 22:52:02 +02:00
} , ConnectionsManager . RequestFlagFailOnServerErrors ) ;
2014-11-10 12:05:22 +01:00
}
}
2017-12-08 18:35:59 +01:00
public String getInviteText ( int contacts ) {
String link = inviteLink = = null ? " https://telegram.org/dl " : inviteLink ;
if ( contacts < = 1 ) {
return LocaleController . formatString ( " InviteText2 " , R . string . InviteText2 , link ) ;
} else {
try {
return String . format ( LocaleController . getPluralString ( " InviteTextNum " , contacts ) , contacts , link ) ;
} catch ( Exception e ) {
return LocaleController . formatString ( " InviteText2 " , R . string . InviteText2 , link ) ;
}
}
2014-11-10 12:05:22 +01:00
}
2014-02-04 19:36:55 +01:00
public void checkAppAccount ( ) {
AccountManager am = AccountManager . get ( ApplicationLoader . applicationContext ) ;
2015-05-03 13:48:36 +02:00
try {
2020-06-25 17:29:04 +02:00
Account [ ] accounts = am . getAccountsByType ( BuildConfig . APPLICATION_ID ) ;
2018-07-30 04:07:02 +02:00
systemAccount = null ;
for ( int a = 0 ; a < accounts . length ; a + + ) {
Account acc = accounts [ a ] ;
boolean found = false ;
for ( int b = 0 ; b < UserConfig . MAX_ACCOUNT_COUNT ; b + + ) {
TLRPC . User user = UserConfig . getInstance ( b ) . getCurrentUser ( ) ;
if ( user ! = null ) {
2020-06-25 17:29:04 +02:00
if ( acc . name . equals ( formatName ( user . first_name , user . last_name ) ) ) {
2018-07-30 04:07:02 +02:00
if ( b = = currentAccount ) {
systemAccount = acc ;
}
found = true ;
break ;
}
}
2015-05-03 13:48:36 +02:00
}
2020-06-25 17:29:04 +02:00
if ( ! found | | NekoConfig . disableSystemAccount ) {
2018-07-30 04:07:02 +02:00
try {
am . removeAccount ( accounts [ a ] , null , null ) ;
} catch ( Exception ignore ) {
}
2014-02-04 19:36:55 +01:00
}
2018-07-30 04:07:02 +02:00
2014-02-04 19:36:55 +01:00
}
2020-06-25 17:29:04 +02:00
} catch ( Throwable e ) {
FileLog . e ( e ) ;
2014-02-04 19:36:55 +01:00
}
2019-07-18 15:01:39 +02:00
if ( getUserConfig ( ) . isClientActivated ( ) ) {
2018-07-30 04:07:02 +02:00
readContacts ( ) ;
2020-06-25 17:29:04 +02:00
if ( systemAccount = = null & & ! NekoConfig . disableSystemAccount ) {
2014-04-04 19:58:33 +02:00
try {
2020-06-14 06:02:04 +02:00
TLRPC . User user = getUserConfig ( ) . getCurrentUser ( ) ;
2020-06-25 17:29:04 +02:00
systemAccount = new Account ( formatName ( user . first_name , user . last_name ) , BuildConfig . APPLICATION_ID ) ;
2018-07-30 04:07:02 +02:00
am . addAccountExplicitly ( systemAccount , " " , null ) ;
2020-06-25 17:29:04 +02:00
} catch ( Exception e ) {
FileLog . e ( e ) ;
2014-04-04 19:58:33 +02:00
}
2014-02-04 19:36:55 +01:00
}
}
}
2018-07-30 04:07:02 +02:00
public void deleteUnknownAppAccounts ( ) {
2014-07-03 00:39:05 +02:00
try {
2018-07-30 04:07:02 +02:00
systemAccount = null ;
2014-07-03 00:39:05 +02:00
AccountManager am = AccountManager . get ( ApplicationLoader . applicationContext ) ;
2020-06-25 17:29:04 +02:00
Account [ ] accounts = am . getAccountsByType ( BuildConfig . APPLICATION_ID ) ;
2015-11-26 22:04:02 +01:00
for ( int a = 0 ; a < accounts . length ; a + + ) {
2018-07-30 04:07:02 +02:00
Account acc = accounts [ a ] ;
2020-06-25 17:29:04 +02:00
if ( NekoConfig . disableSystemAccount ) {
2018-07-30 04:07:02 +02:00
try {
am . removeAccount ( accounts [ a ] , null , null ) ;
} catch ( Exception ignore ) {
}
2020-06-25 17:29:04 +02:00
} else {
boolean found = false ;
for ( int b = 0 ; b < UserConfig . MAX_ACCOUNT_COUNT ; b + + ) {
TLRPC . User user = UserConfig . getInstance ( b ) . getCurrentUser ( ) ;
if ( user ! = null ) {
if ( acc . name . equals ( formatName ( user . first_name , user . last_name ) ) ) {
found = true ;
break ;
}
}
}
if ( ! found ) {
try {
am . removeAccount ( accounts [ a ] , null , null ) ;
} catch ( Exception ignore ) {
}
}
2018-07-30 04:07:02 +02:00
}
2014-07-03 00:39:05 +02:00
}
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
}
2014-05-25 00:47:05 +02:00
public void checkContacts ( ) {
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
if ( checkContactsInternal ( ) ) {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " detected contacts change " ) ;
2014-05-25 00:47:05 +02:00
}
2019-01-23 18:03:33 +01:00
performSyncPhoneBook ( getContactsCopy ( contactsBook ) , true , false , true , false , true , false ) ;
2014-05-25 00:47:05 +02:00
}
} ) ;
}
2016-06-24 12:27:15 +02:00
public void forceImportContacts ( ) {
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " force import contacts " ) ;
2017-12-08 18:35:59 +01:00
}
2019-01-23 18:03:33 +01:00
performSyncPhoneBook ( new HashMap < > ( ) , true , true , true , true , false , false ) ;
2017-12-08 18:35:59 +01:00
} ) ;
}
public void syncPhoneBookByAlert ( final HashMap < String , Contact > contacts , final boolean first , final boolean schedule , final boolean cancel ) {
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " sync contacts by alert " ) ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
performSyncPhoneBook ( contacts , true , first , schedule , false , false , cancel ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
public void deleteAllContacts ( final Runnable runnable ) {
resetImportedContacts ( ) ;
TLRPC . TL_contacts_deleteContacts req = new TLRPC . TL_contacts_deleteContacts ( ) ;
for ( int a = 0 , size = contacts . size ( ) ; a < size ; a + + ) {
TLRPC . TL_contact contact = contacts . get ( a ) ;
2019-07-18 15:01:39 +02:00
req . id . add ( getMessagesController ( ) . getInputUser ( contact . user_id ) ) ;
2018-07-30 04:07:02 +02:00
}
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
if ( error = = null ) {
2019-01-23 18:03:33 +01:00
contactsBookSPhones . clear ( ) ;
contactsBook . clear ( ) ;
completedRequestsCount = 0 ;
migratingContacts = false ;
contactsSyncInProgress = false ;
contactsLoaded = false ;
loadingContacts = false ;
contactsBookLoaded = false ;
lastContactsVersions = " " ;
AndroidUtilities . runOnUIThread ( ( ) - > {
AccountManager am = AccountManager . get ( ApplicationLoader . applicationContext ) ;
try {
2020-06-25 17:29:04 +02:00
Account [ ] accounts = am . getAccountsByType ( BuildConfig . APPLICATION_ID ) ;
2019-01-23 18:03:33 +01:00
systemAccount = null ;
for ( int a = 0 ; a < accounts . length ; a + + ) {
Account acc = accounts [ a ] ;
for ( int b = 0 ; b < UserConfig . MAX_ACCOUNT_COUNT ; b + + ) {
TLRPC . User user = UserConfig . getInstance ( b ) . getCurrentUser ( ) ;
if ( user ! = null ) {
if ( acc . name . equals ( " " + user . id ) ) {
am . removeAccount ( acc , null , null ) ;
break ;
2018-07-30 04:07:02 +02:00
}
}
}
}
2019-01-23 18:03:33 +01:00
} catch ( Throwable ignore ) {
}
try {
2020-06-25 17:29:04 +02:00
systemAccount = new Account ( " " + UserConfig . getInstance ( currentAccount ) . getClientUserId ( ) , BuildConfig . APPLICATION_ID ) ;
2019-01-23 18:03:33 +01:00
am . addAccountExplicitly ( systemAccount , " " , null ) ;
} catch ( Exception ignore ) {
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( new HashMap < > ( ) , false , true ) ;
getMessagesStorage ( ) . putContacts ( new ArrayList < > ( ) , true ) ;
2019-01-23 18:03:33 +01:00
phoneBookContacts . clear ( ) ;
contacts . clear ( ) ;
contactsDict . clear ( ) ;
usersSectionsDict . clear ( ) ;
usersMutualSectionsDict . clear ( ) ;
sortedUsersSectionsArray . clear ( ) ;
phoneBookSectionsDict . clear ( ) ;
phoneBookSectionsArray . clear ( ) ;
delayedContactsUpdate . clear ( ) ;
sortedUsersMutualSectionsArray . clear ( ) ;
contactsByPhone . clear ( ) ;
contactsByShortPhone . clear ( ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2019-01-23 18:03:33 +01:00
loadContacts ( false , 0 ) ;
runnable . run ( ) ;
} ) ;
2019-07-18 15:01:39 +02:00
} else {
AndroidUtilities . runOnUIThread ( runnable ) ;
2017-12-08 18:35:59 +01:00
}
} ) ;
}
public void resetImportedContacts ( ) {
TLRPC . TL_contacts_resetSaved req = new TLRPC . TL_contacts_resetSaved ( ) ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2017-12-08 18:35:59 +01:00
2016-06-24 12:27:15 +02:00
} ) ;
}
2014-05-25 00:47:05 +02:00
private boolean checkContactsInternal ( ) {
boolean reload = false ;
try {
2015-11-26 22:04:02 +01:00
if ( ! hasContactsPermission ( ) ) {
2015-10-29 18:10:07 +01:00
return false ;
}
2014-05-25 00:47:05 +02:00
ContentResolver cr = ApplicationLoader . applicationContext . getContentResolver ( ) ;
2019-06-04 12:14:50 +02:00
try ( Cursor pCur = cr . query ( ContactsContract . RawContacts . CONTENT_URI , new String [ ] { ContactsContract . RawContacts . VERSION } , null , null , null ) ) {
2015-09-24 22:52:02 +02:00
if ( pCur ! = null ) {
StringBuilder currentVersion = new StringBuilder ( ) ;
while ( pCur . moveToNext ( ) ) {
2018-07-30 04:07:02 +02:00
currentVersion . append ( pCur . getString ( pCur . getColumnIndex ( ContactsContract . RawContacts . VERSION ) ) ) ;
2015-09-24 22:52:02 +02:00
}
String newContactsVersion = currentVersion . toString ( ) ;
if ( lastContactsVersions . length ( ) ! = 0 & & ! lastContactsVersions . equals ( newContactsVersion ) ) {
reload = true ;
}
lastContactsVersions = newContactsVersion ;
2014-05-25 00:47:05 +02:00
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-05-25 00:47:05 +02:00
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-05-25 00:47:05 +02:00
}
return reload ;
}
2014-02-04 19:36:55 +01:00
public void readContacts ( ) {
2014-06-13 12:42:21 +02:00
synchronized ( loadContactsSync ) {
if ( loadingContacts ) {
return ;
}
loadingContacts = true ;
2014-02-28 23:28:25 +01:00
}
2014-06-13 12:42:21 +02:00
2019-01-23 18:03:33 +01:00
Utilities . stageQueue . postRunnable ( ( ) - > {
if ( ! contacts . isEmpty ( ) | | contactsLoaded ) {
synchronized ( loadContactsSync ) {
loadingContacts = false ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
return ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
loadContacts ( true , 0 ) ;
2014-02-04 19:36:55 +01:00
} ) ;
}
2018-07-30 04:07:02 +02:00
private boolean isNotValidNameString ( String src ) {
if ( TextUtils . isEmpty ( src ) ) {
return true ;
}
int count = 0 ;
for ( int a = 0 , len = src . length ( ) ; a < len ; a + + ) {
char c = src . charAt ( a ) ;
if ( c > = '0' & & c < = '9' ) {
count + + ;
}
}
return count > 3 ;
}
2017-12-08 18:35:59 +01:00
private HashMap < String , Contact > readContactsFromPhoneBook ( ) {
2019-07-18 15:01:39 +02:00
if ( ! getUserConfig ( ) . syncContacts ) {
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " contacts sync disabled " ) ;
}
return new HashMap < > ( ) ;
}
if ( ! hasContactsPermission ( ) ) {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " app has no contacts permissions " ) ;
}
return new HashMap < > ( ) ;
}
2017-12-08 18:35:59 +01:00
Cursor pCur = null ;
2018-07-30 04:07:02 +02:00
HashMap < String , Contact > contactsMap = null ;
2014-02-11 15:32:09 +01:00
try {
2018-07-30 04:07:02 +02:00
StringBuilder escaper = new StringBuilder ( ) ;
2014-02-11 15:32:09 +01:00
ContentResolver cr = ApplicationLoader . applicationContext . getContentResolver ( ) ;
2014-02-28 23:28:25 +01:00
2015-01-02 23:15:07 +01:00
HashMap < String , Contact > shortContacts = new HashMap < > ( ) ;
2017-12-08 18:35:59 +01:00
ArrayList < String > idsArr = new ArrayList < > ( ) ;
pCur = cr . query ( ContactsContract . CommonDataKinds . Phone . CONTENT_URI , projectionPhones , null , null , null ) ;
int lastContactId = 1 ;
2014-02-11 15:32:09 +01:00
if ( pCur ! = null ) {
2018-07-30 04:07:02 +02:00
int count = pCur . getCount ( ) ;
if ( count > 0 ) {
if ( contactsMap = = null ) {
contactsMap = new HashMap < > ( count ) ;
}
2014-02-11 15:32:09 +01:00
while ( pCur . moveToNext ( ) ) {
String number = pCur . getString ( 1 ) ;
2018-07-30 04:07:02 +02:00
String accountType = pCur . getString ( 5 ) ;
if ( accountType = = null ) {
accountType = " " ;
}
boolean isGoodAccountType = accountType . indexOf ( " .sim " ) ! = 0 ;
2017-03-31 01:58:05 +02:00
if ( TextUtils . isEmpty ( number ) ) {
2014-02-11 15:32:09 +01:00
continue ;
}
2014-02-28 23:28:25 +01:00
number = PhoneFormat . stripExceptNumbers ( number , true ) ;
2017-12-08 18:35:59 +01:00
if ( TextUtils . isEmpty ( number ) ) {
2014-02-11 15:32:09 +01:00
continue ;
}
2014-02-28 23:28:25 +01:00
String shortNumber = number ;
if ( number . startsWith ( " + " ) ) {
shortNumber = number . substring ( 1 ) ;
}
2018-07-30 04:07:02 +02:00
String lookup_key = pCur . getString ( 0 ) ;
escaper . setLength ( 0 ) ;
DatabaseUtils . appendEscapedSQLString ( escaper , lookup_key ) ;
String key = escaper . toString ( ) ;
Contact existingContact = shortContacts . get ( shortNumber ) ;
if ( existingContact ! = null ) {
if ( ! existingContact . isGoodProvider & & ! accountType . equals ( existingContact . provider ) ) {
escaper . setLength ( 0 ) ;
DatabaseUtils . appendEscapedSQLString ( escaper , existingContact . key ) ;
idsArr . remove ( escaper . toString ( ) ) ;
idsArr . add ( key ) ;
existingContact . key = lookup_key ;
existingContact . isGoodProvider = isGoodAccountType ;
existingContact . provider = accountType ;
}
2014-02-28 23:28:25 +01:00
continue ;
}
2017-12-08 18:35:59 +01:00
if ( ! idsArr . contains ( key ) ) {
idsArr . add ( key ) ;
2014-02-11 15:32:09 +01:00
}
int type = pCur . getInt ( 2 ) ;
2017-12-08 18:35:59 +01:00
Contact contact = contactsMap . get ( lookup_key ) ;
2014-02-11 15:32:09 +01:00
if ( contact = = null ) {
contact = new Contact ( ) ;
2018-07-30 04:07:02 +02:00
String displayName = pCur . getString ( 4 ) ;
if ( displayName = = null ) {
displayName = " " ;
} else {
displayName = displayName . trim ( ) ;
}
if ( isNotValidNameString ( displayName ) ) {
contact . first_name = displayName ;
contact . last_name = " " ;
} else {
int spaceIndex = displayName . lastIndexOf ( ' ' ) ;
if ( spaceIndex ! = - 1 ) {
contact . first_name = displayName . substring ( 0 , spaceIndex ) . trim ( ) ;
2019-06-04 12:14:50 +02:00
contact . last_name = displayName . substring ( spaceIndex + 1 ) . trim ( ) ;
2018-07-30 04:07:02 +02:00
} else {
contact . first_name = displayName ;
contact . last_name = " " ;
}
}
contact . provider = accountType ;
contact . isGoodProvider = isGoodAccountType ;
2017-12-08 18:35:59 +01:00
contact . key = lookup_key ;
contact . contact_id = lastContactId + + ;
contactsMap . put ( lookup_key , contact ) ;
2014-02-11 15:32:09 +01:00
}
2014-02-04 19:36:55 +01:00
2014-02-28 23:28:25 +01:00
contact . shortPhones . add ( shortNumber ) ;
contact . phones . add ( number ) ;
contact . phoneDeleted . add ( 0 ) ;
2014-02-04 19:36:55 +01:00
2014-02-11 15:32:09 +01:00
if ( type = = ContactsContract . CommonDataKinds . Phone . TYPE_CUSTOM ) {
2017-03-31 01:58:05 +02:00
String custom = pCur . getString ( 3 ) ;
contact . phoneTypes . add ( custom ! = null ? custom : LocaleController . getString ( " PhoneMobile " , R . string . PhoneMobile ) ) ;
2014-02-11 15:32:09 +01:00
} else if ( type = = ContactsContract . CommonDataKinds . Phone . TYPE_HOME ) {
2014-03-22 23:31:55 +01:00
contact . phoneTypes . add ( LocaleController . getString ( " PhoneHome " , R . string . PhoneHome ) ) ;
2014-02-11 15:32:09 +01:00
} else if ( type = = ContactsContract . CommonDataKinds . Phone . TYPE_MOBILE ) {
2014-03-22 23:31:55 +01:00
contact . phoneTypes . add ( LocaleController . getString ( " PhoneMobile " , R . string . PhoneMobile ) ) ;
2014-02-11 15:32:09 +01:00
} else if ( type = = ContactsContract . CommonDataKinds . Phone . TYPE_WORK ) {
2014-03-22 23:31:55 +01:00
contact . phoneTypes . add ( LocaleController . getString ( " PhoneWork " , R . string . PhoneWork ) ) ;
2014-02-11 15:32:09 +01:00
} else if ( type = = ContactsContract . CommonDataKinds . Phone . TYPE_MAIN ) {
2014-03-22 23:31:55 +01:00
contact . phoneTypes . add ( LocaleController . getString ( " PhoneMain " , R . string . PhoneMain ) ) ;
2014-02-11 15:32:09 +01:00
} else {
2014-03-22 23:31:55 +01:00
contact . phoneTypes . add ( LocaleController . getString ( " PhoneOther " , R . string . PhoneOther ) ) ;
2014-02-11 15:32:09 +01:00
}
2014-02-28 23:28:25 +01:00
shortContacts . put ( shortNumber , contact ) ;
2014-02-04 19:36:55 +01:00
}
}
2017-12-08 18:35:59 +01:00
try {
pCur . close ( ) ;
} catch ( Exception ignore ) {
}
pCur = null ;
2014-02-04 19:36:55 +01:00
}
2015-07-22 20:56:37 +02:00
String ids = TextUtils . join ( " , " , idsArr ) ;
2014-02-04 19:36:55 +01:00
2017-12-08 18:35:59 +01:00
pCur = cr . query ( ContactsContract . Data . CONTENT_URI , projectionNames , ContactsContract . CommonDataKinds . StructuredName . LOOKUP_KEY + " IN ( " + ids + " ) AND " + ContactsContract . Data . MIMETYPE + " = ' " + ContactsContract . CommonDataKinds . StructuredName . CONTENT_ITEM_TYPE + " ' " , null , null ) ;
2017-03-31 01:58:05 +02:00
if ( pCur ! = null ) {
2014-02-11 15:32:09 +01:00
while ( pCur . moveToNext ( ) ) {
2017-12-08 18:35:59 +01:00
String lookup_key = pCur . getString ( 0 ) ;
2014-02-11 15:32:09 +01:00
String fname = pCur . getString ( 1 ) ;
String sname = pCur . getString ( 2 ) ;
2018-07-30 04:07:02 +02:00
String mname = pCur . getString ( 3 ) ;
2017-12-08 18:35:59 +01:00
Contact contact = contactsMap . get ( lookup_key ) ;
2018-07-30 04:07:02 +02:00
if ( contact ! = null & & ! contact . namesFilled ) {
if ( contact . isGoodProvider ) {
if ( fname ! = null ) {
contact . first_name = fname ;
2014-02-11 15:32:09 +01:00
} else {
2018-07-30 04:07:02 +02:00
contact . first_name = " " ;
}
if ( sname ! = null ) {
contact . last_name = sname ;
} else {
contact . last_name = " " ;
}
if ( ! TextUtils . isEmpty ( mname ) ) {
if ( ! TextUtils . isEmpty ( contact . first_name ) ) {
contact . first_name + = " " + mname ;
} else {
contact . first_name = mname ;
}
}
} else {
if ( ! isNotValidNameString ( fname ) & & ( contact . first_name . contains ( fname ) | | fname . contains ( contact . first_name ) ) | |
! isNotValidNameString ( sname ) & & ( contact . last_name . contains ( sname ) | | fname . contains ( contact . last_name ) ) ) {
if ( fname ! = null ) {
contact . first_name = fname ;
} else {
contact . first_name = " " ;
}
if ( ! TextUtils . isEmpty ( mname ) ) {
if ( ! TextUtils . isEmpty ( contact . first_name ) ) {
contact . first_name + = " " + mname ;
} else {
contact . first_name = mname ;
}
}
if ( sname ! = null ) {
contact . last_name = sname ;
} else {
contact . last_name = " " ;
}
2014-02-11 15:32:09 +01:00
}
}
2018-07-30 04:07:02 +02:00
contact . namesFilled = true ;
2014-02-04 19:36:55 +01:00
}
}
2017-12-08 18:35:59 +01:00
try {
pCur . close ( ) ;
} catch ( Exception ignore ) {
}
pCur = null ;
2014-02-04 19:36:55 +01:00
}
2018-07-30 04:07:02 +02:00
} catch ( Throwable e ) {
2017-12-08 18:35:59 +01:00
FileLog . e ( e ) ;
2018-07-30 04:07:02 +02:00
if ( contactsMap ! = null ) {
contactsMap . clear ( ) ;
}
2017-12-08 18:35:59 +01:00
} finally {
try {
2014-02-28 23:28:25 +01:00
if ( pCur ! = null ) {
pCur . close ( ) ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2017-12-08 18:35:59 +01:00
}
2014-02-04 19:36:55 +01:00
}
2018-07-30 04:07:02 +02:00
/ * if ( BuildVars . LOGS_ENABLED & & contactsMap ! = null ) {
for ( HashMap . Entry < String , Contact > entry : contactsMap . entrySet ( ) ) {
2015-07-22 20:56:37 +02:00
Contact contact = entry . getValue ( ) ;
2017-03-31 01:58:05 +02:00
FileLog . e ( " contact = " + contact . first_name + " " + contact . last_name ) ;
2015-07-22 20:56:37 +02:00
if ( contact . first_name . length ( ) = = 0 & & contact . last_name . length ( ) = = 0 & & contact . phones . size ( ) > 0 ) {
2018-07-30 04:07:02 +02:00
FileLog . e ( " warning, empty name for contact = " + contact . key ) ;
2015-07-22 20:56:37 +02:00
}
2017-03-31 01:58:05 +02:00
FileLog . e ( " phones: " ) ;
2015-07-22 20:56:37 +02:00
for ( String s : contact . phones ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( " phone = " + s ) ;
2015-07-22 20:56:37 +02:00
}
2017-03-31 01:58:05 +02:00
FileLog . e ( " short phones: " ) ;
2015-07-22 20:56:37 +02:00
for ( String s : contact . shortPhones ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( " short phone = " + s ) ;
2015-07-22 20:56:37 +02:00
}
}
2015-09-24 22:52:02 +02:00
} * /
2019-01-23 18:03:33 +01:00
return contactsMap ! = null ? contactsMap : new HashMap < > ( ) ;
2014-02-04 19:36:55 +01:00
}
2017-12-08 18:35:59 +01:00
public HashMap < String , Contact > getContactsCopy ( HashMap < String , Contact > original ) {
HashMap < String , Contact > ret = new HashMap < > ( ) ;
for ( HashMap . Entry < String , Contact > entry : original . entrySet ( ) ) {
2014-02-04 19:36:55 +01:00
Contact copyContact = new Contact ( ) ;
Contact originalContact = entry . getValue ( ) ;
copyContact . phoneDeleted . addAll ( originalContact . phoneDeleted ) ;
copyContact . phones . addAll ( originalContact . phones ) ;
copyContact . phoneTypes . addAll ( originalContact . phoneTypes ) ;
copyContact . shortPhones . addAll ( originalContact . shortPhones ) ;
copyContact . first_name = originalContact . first_name ;
copyContact . last_name = originalContact . last_name ;
2017-12-08 18:35:59 +01:00
copyContact . contact_id = originalContact . contact_id ;
copyContact . key = originalContact . key ;
ret . put ( copyContact . key , copyContact ) ;
2014-02-04 19:36:55 +01:00
}
return ret ;
}
2018-07-30 04:07:02 +02:00
protected void migratePhoneBookToV7 ( final SparseArray < Contact > contactHashMap ) {
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
if ( migratingContacts ) {
return ;
}
migratingContacts = true ;
HashMap < String , Contact > migratedMap = new HashMap < > ( ) ;
HashMap < String , Contact > contactsMap = readContactsFromPhoneBook ( ) ;
final HashMap < String , String > contactsBookShort = new HashMap < > ( ) ;
for ( HashMap . Entry < String , Contact > entry : contactsMap . entrySet ( ) ) {
Contact value = entry . getValue ( ) ;
for ( int a = 0 ; a < value . shortPhones . size ( ) ; a + + ) {
contactsBookShort . put ( value . shortPhones . get ( a ) , value . key ) ;
}
}
for ( int b = 0 ; b < contactHashMap . size ( ) ; b + + ) {
Contact value = contactHashMap . valueAt ( b ) ;
for ( int a = 0 ; a < value . shortPhones . size ( ) ; a + + ) {
String sphone = value . shortPhones . get ( a ) ;
String key = contactsBookShort . get ( sphone ) ;
if ( key ! = null ) {
value . key = key ;
migratedMap . put ( key , value ) ;
break ;
2017-12-08 18:35:59 +01:00
}
}
}
2019-01-23 18:03:33 +01:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " migrated contacts " + migratedMap . size ( ) + " of " + contactHashMap . size ( ) ) ;
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( migratedMap , true , false ) ;
2017-12-08 18:35:59 +01:00
} ) ;
}
protected void performSyncPhoneBook ( final HashMap < String , Contact > contactHashMap , final boolean request , final boolean first , final boolean schedule , final boolean force , final boolean checkCount , final boolean canceled ) {
2014-02-28 23:28:25 +01:00
if ( ! first & & ! contactsBookLoaded ) {
return ;
}
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
int newPhonebookContacts = 0 ;
int serverContactsInPhonebook = 0 ;
boolean disableDeletion = true ; //disable contacts deletion, because phone numbers can't be compared due to different numbers format
/ * if ( schedule ) {
try {
AccountManager am = AccountManager . get ( ApplicationLoader . applicationContext ) ;
Account [ ] accounts = am . getAccountsByType ( " org.telegram.account " ) ;
boolean recreateAccount = false ;
2019-07-18 15:01:39 +02:00
if ( getUserConfig ( ) . isClientActivated ( ) ) {
2019-01-23 18:03:33 +01:00
if ( accounts . length ! = 1 ) {
FileLog . e ( " detected account deletion! " ) ;
2019-07-18 15:01:39 +02:00
currentAccount = new Account ( getUserConfig ( ) . getCurrentUser ( ) . phone , " org.telegram.account " ) ;
2019-01-23 18:03:33 +01:00
am . addAccountExplicitly ( currentAccount , " " , null ) ;
AndroidUtilities . runOnUIThread ( new Runnable ( ) {
@Override
public void run ( ) {
performWriteContactsToPhoneBook ( ) ;
}
} ) ;
2014-02-28 23:28:25 +01:00
}
}
2019-01-23 18:03:33 +01:00
} catch ( Exception e ) {
FileLog . e ( e ) ;
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
} * /
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
HashMap < String , Contact > contactShortHashMap = new HashMap < > ( ) ;
for ( HashMap . Entry < String , Contact > entry : contactHashMap . entrySet ( ) ) {
Contact c = entry . getValue ( ) ;
for ( int a = 0 ; a < c . shortPhones . size ( ) ; a + + ) {
contactShortHashMap . put ( c . shortPhones . get ( a ) , c ) ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
}
2018-07-30 04:07:02 +02:00
2019-01-23 18:03:33 +01:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " start read contacts from phone " ) ;
}
if ( ! schedule ) {
checkContactsInternal ( ) ;
}
final HashMap < String , Contact > contactsMap = readContactsFromPhoneBook ( ) ;
final HashMap < String , ArrayList < Object > > phoneBookSectionsDictFinal = new HashMap < > ( ) ;
final HashMap < String , Contact > phoneBookByShortPhonesFinal = new HashMap < > ( ) ;
final ArrayList < String > phoneBookSectionsArrayFinal = new ArrayList < > ( ) ;
2018-07-30 04:07:02 +02:00
2019-01-23 18:03:33 +01:00
for ( HashMap . Entry < String , Contact > entry : contactsMap . entrySet ( ) ) {
Contact contact = entry . getValue ( ) ;
for ( int a = 0 , size = contact . shortPhones . size ( ) ; a < size ; a + + ) {
String phone = contact . shortPhones . get ( a ) ;
phoneBookByShortPhonesFinal . put ( phone . substring ( Math . max ( 0 , phone . length ( ) - 7 ) ) , contact ) ;
}
String key = contact . getLetter ( ) ;
ArrayList < Object > arrayList = phoneBookSectionsDictFinal . get ( key ) ;
if ( arrayList = = null ) {
arrayList = new ArrayList < > ( ) ;
phoneBookSectionsDictFinal . put ( key , arrayList ) ;
phoneBookSectionsArrayFinal . add ( key ) ;
}
arrayList . add ( contact ) ;
}
final HashMap < String , Contact > contactsBookShort = new HashMap < > ( ) ;
int alreadyImportedContacts = contactHashMap . size ( ) ;
ArrayList < TLRPC . TL_inputPhoneContact > toImport = new ArrayList < > ( ) ;
if ( ! contactHashMap . isEmpty ( ) ) {
for ( HashMap . Entry < String , Contact > pair : contactsMap . entrySet ( ) ) {
String id = pair . getKey ( ) ;
Contact value = pair . getValue ( ) ;
Contact existing = contactHashMap . get ( id ) ;
if ( existing = = null ) {
for ( int a = 0 ; a < value . shortPhones . size ( ) ; a + + ) {
Contact c = contactShortHashMap . get ( value . shortPhones . get ( a ) ) ;
if ( c ! = null ) {
existing = c ;
id = existing . key ;
break ;
}
}
}
if ( existing ! = null ) {
value . imported = existing . imported ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
boolean nameChanged = existing ! = null & & ( ! TextUtils . isEmpty ( value . first_name ) & & ! existing . first_name . equals ( value . first_name ) | | ! TextUtils . isEmpty ( value . last_name ) & & ! existing . last_name . equals ( value . last_name ) ) ;
if ( existing = = null | | nameChanged ) {
for ( int a = 0 ; a < value . phones . size ( ) ; a + + ) {
String sphone = value . shortPhones . get ( a ) ;
String sphone9 = sphone . substring ( Math . max ( 0 , sphone . length ( ) - 7 ) ) ;
contactsBookShort . put ( sphone , value ) ;
if ( existing ! = null ) {
int index = existing . shortPhones . indexOf ( sphone ) ;
if ( index ! = - 1 ) {
Integer deleted = existing . phoneDeleted . get ( index ) ;
value . phoneDeleted . set ( a , deleted ) ;
if ( deleted = = 1 ) {
continue ;
}
}
}
if ( request ) {
if ( ! nameChanged ) {
if ( contactsByPhone . containsKey ( sphone ) ) {
serverContactsInPhonebook + + ;
continue ;
}
newPhonebookContacts + + ;
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
TLRPC . TL_inputPhoneContact imp = new TLRPC . TL_inputPhoneContact ( ) ;
imp . client_id = value . contact_id ;
imp . client_id | = ( ( long ) a ) < < 32 ;
imp . first_name = value . first_name ;
imp . last_name = value . last_name ;
imp . phone = value . phones . get ( a ) ;
toImport . add ( imp ) ;
2014-02-28 23:28:25 +01:00
}
}
2017-12-08 18:35:59 +01:00
if ( existing ! = null ) {
2019-01-23 18:03:33 +01:00
contactHashMap . remove ( id ) ;
2017-12-08 18:35:59 +01:00
}
2019-01-23 18:03:33 +01:00
} else {
for ( int a = 0 ; a < value . phones . size ( ) ; a + + ) {
String sphone = value . shortPhones . get ( a ) ;
String sphone9 = sphone . substring ( Math . max ( 0 , sphone . length ( ) - 7 ) ) ;
contactsBookShort . put ( sphone , value ) ;
int index = existing . shortPhones . indexOf ( sphone ) ;
boolean emptyNameReimport = false ;
if ( request ) {
TLRPC . TL_contact contact = contactsByPhone . get ( sphone ) ;
if ( contact ! = null ) {
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( contact . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user ! = null ) {
serverContactsInPhonebook + + ;
if ( TextUtils . isEmpty ( user . first_name ) & & TextUtils . isEmpty ( user . last_name ) & & ( ! TextUtils . isEmpty ( value . first_name ) | | ! TextUtils . isEmpty ( value . last_name ) ) ) {
index = - 1 ;
emptyNameReimport = true ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
} else if ( contactsByShortPhone . containsKey ( sphone9 ) ) {
serverContactsInPhonebook + + ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
if ( index = = - 1 ) {
2014-02-04 19:36:55 +01:00
if ( request ) {
2019-01-23 18:03:33 +01:00
if ( ! emptyNameReimport ) {
TLRPC . TL_contact contact = contactsByPhone . get ( sphone ) ;
if ( contact ! = null ) {
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( contact . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user ! = null ) {
serverContactsInPhonebook + + ;
String firstName = user . first_name ! = null ? user . first_name : " " ;
String lastName = user . last_name ! = null ? user . last_name : " " ;
if ( firstName . equals ( value . first_name ) & & lastName . equals ( value . last_name ) | | TextUtils . isEmpty ( value . first_name ) & & TextUtils . isEmpty ( value . last_name ) ) {
continue ;
}
} else {
newPhonebookContacts + + ;
}
} else if ( contactsByShortPhone . containsKey ( sphone9 ) ) {
2017-12-08 18:35:59 +01:00
serverContactsInPhonebook + + ;
}
2014-02-28 23:28:25 +01:00
}
2014-02-04 19:36:55 +01:00
TLRPC . TL_inputPhoneContact imp = new TLRPC . TL_inputPhoneContact ( ) ;
2017-12-08 18:35:59 +01:00
imp . client_id = value . contact_id ;
2016-06-24 12:27:15 +02:00
imp . client_id | = ( ( long ) a ) < < 32 ;
2014-02-04 19:36:55 +01:00
imp . first_name = value . first_name ;
imp . last_name = value . last_name ;
imp . phone = value . phones . get ( a ) ;
toImport . add ( imp ) ;
}
2019-01-23 18:03:33 +01:00
} else {
value . phoneDeleted . set ( a , existing . phoneDeleted . get ( index ) ) ;
existing . phones . remove ( index ) ;
existing . shortPhones . remove ( index ) ;
existing . phoneDeleted . remove ( index ) ;
existing . phoneTypes . remove ( index ) ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
if ( existing . phones . isEmpty ( ) ) {
contactHashMap . remove ( id ) ;
2018-07-30 04:07:02 +02:00
}
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
if ( ! first & & contactHashMap . isEmpty ( ) & & toImport . isEmpty ( ) & & alreadyImportedContacts = = contactsMap . size ( ) ) {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " contacts not changed! " ) ;
}
return ;
}
if ( request & & ! contactHashMap . isEmpty ( ) & & ! contactsMap . isEmpty ( ) ) {
if ( toImport . isEmpty ( ) ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( contactsMap , false , false ) ;
2019-01-23 18:03:33 +01:00
}
if ( ! disableDeletion & & ! contactHashMap . isEmpty ( ) ) {
AndroidUtilities . runOnUIThread ( ( ) - > {
/ * if ( BuildVars . DEBUG_VERSION ) {
FileLog . e ( " need delete contacts " ) ;
for ( HashMap . Entry < Integer , Contact > c : contactHashMap . entrySet ( ) ) {
Contact contact = c . getValue ( ) ;
FileLog . e ( " delete contact " + contact . first_name + " " + contact . last_name ) ;
for ( String phone : contact . phones ) {
FileLog . e ( phone ) ;
}
}
} * /
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
final ArrayList < TLRPC . User > toDelete = new ArrayList < > ( ) ;
if ( contactHashMap ! = null & & ! contactHashMap . isEmpty ( ) ) {
try {
final HashMap < String , TLRPC . User > contactsPhonesShort = new HashMap < > ( ) ;
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < contacts . size ( ) ; a + + ) {
TLRPC . TL_contact value = contacts . get ( a ) ;
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( value . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user = = null | | TextUtils . isEmpty ( user . phone ) ) {
continue ;
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
contactsPhonesShort . put ( user . phone , user ) ;
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
int removed = 0 ;
for ( HashMap . Entry < String , Contact > entry : contactHashMap . entrySet ( ) ) {
Contact contact = entry . getValue ( ) ;
boolean was = false ;
for ( int a = 0 ; a < contact . shortPhones . size ( ) ; a + + ) {
String phone = contact . shortPhones . get ( a ) ;
TLRPC . User user = contactsPhonesShort . get ( phone ) ;
if ( user ! = null ) {
was = true ;
toDelete . add ( user ) ;
contact . shortPhones . remove ( a ) ;
a - - ;
}
}
if ( ! was | | contact . shortPhones . size ( ) = = 0 ) {
removed + + ;
}
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
} catch ( Exception e ) {
FileLog . e ( e ) ;
2014-02-28 23:28:25 +01:00
}
2019-01-23 18:03:33 +01:00
}
if ( ! toDelete . isEmpty ( ) ) {
2021-02-23 12:53:38 +01:00
deleteContact ( toDelete , false ) ;
2019-01-23 18:03:33 +01:00
}
} ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
} else if ( request ) {
for ( HashMap . Entry < String , Contact > pair : contactsMap . entrySet ( ) ) {
Contact value = pair . getValue ( ) ;
String key = pair . getKey ( ) ;
for ( int a = 0 ; a < value . phones . size ( ) ; a + + ) {
if ( ! force ) {
String sphone = value . shortPhones . get ( a ) ;
String sphone9 = sphone . substring ( Math . max ( 0 , sphone . length ( ) - 7 ) ) ;
TLRPC . TL_contact contact = contactsByPhone . get ( sphone ) ;
if ( contact ! = null ) {
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( contact . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user ! = null ) {
2017-12-08 18:35:59 +01:00
serverContactsInPhonebook + + ;
2019-01-23 18:03:33 +01:00
String firstName = user . first_name ! = null ? user . first_name : " " ;
String lastName = user . last_name ! = null ? user . last_name : " " ;
if ( firstName . equals ( value . first_name ) & & lastName . equals ( value . last_name ) | | TextUtils . isEmpty ( value . first_name ) & & TextUtils . isEmpty ( value . last_name ) ) {
continue ;
}
2015-07-22 20:56:37 +02:00
}
2019-01-23 18:03:33 +01:00
} else if ( contactsByShortPhone . containsKey ( sphone9 ) ) {
serverContactsInPhonebook + + ;
2014-02-28 23:28:25 +01:00
}
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
TLRPC . TL_inputPhoneContact imp = new TLRPC . TL_inputPhoneContact ( ) ;
imp . client_id = value . contact_id ;
imp . client_id | = ( ( long ) a ) < < 32 ;
imp . first_name = value . first_name ;
imp . last_name = value . last_name ;
imp . phone = value . phones . get ( a ) ;
toImport . add ( imp ) ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " done processing contacts " ) ;
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
if ( request ) {
if ( ! toImport . isEmpty ( ) ) {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . e ( " start import contacts " ) ;
/ * for ( TLRPC . TL_inputPhoneContact contact : toImport ) {
FileLog . e ( " add contact " + contact . first_name + " " + contact . last_name + " " + contact . phone ) ;
} * /
}
2016-06-24 12:27:15 +02:00
2019-01-23 18:03:33 +01:00
final int checkType ;
if ( checkCount & & newPhonebookContacts ! = 0 ) {
if ( newPhonebookContacts > = 30 ) {
checkType = 1 ;
} else if ( first & & alreadyImportedContacts = = 0 & & contactsByPhone . size ( ) - serverContactsInPhonebook > contactsByPhone . size ( ) / 3 * 2 ) {
checkType = 2 ;
2017-12-08 18:35:59 +01:00
} else {
checkType = 0 ;
}
2019-01-23 18:03:33 +01:00
} else {
checkType = 0 ;
}
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " new phone book contacts " + newPhonebookContacts + " serverContactsInPhonebook " + serverContactsInPhonebook + " totalContacts " + contactsByPhone . size ( ) ) ;
}
if ( checkType ! = 0 ) {
2019-07-18 15:01:39 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > getNotificationCenter ( ) . postNotificationName ( NotificationCenter . hasNewContactsToImport , checkType , contactHashMap , first , schedule ) ) ;
2019-01-23 18:03:33 +01:00
return ;
} else if ( canceled ) {
Utilities . stageQueue . postRunnable ( ( ) - > {
contactsBookSPhones = contactsBookShort ;
contactsBook = contactsMap ;
contactsSyncInProgress = false ;
contactsBookLoaded = true ;
if ( first ) {
contactsLoaded = true ;
}
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( contactsMap , false , false ) ;
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
mergePhonebookAndTelegramContacts ( phoneBookSectionsDictFinal , phoneBookSectionsArrayFinal , phoneBookByShortPhonesFinal ) ;
updateUnregisteredContacts ( ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsImported ) ;
2017-12-08 18:35:59 +01:00
} ) ;
2019-01-23 18:03:33 +01:00
} ) ;
return ;
}
final boolean [ ] hasErrors = new boolean [ ] { false } ;
final HashMap < String , Contact > contactsMapToSave = new HashMap < > ( contactsMap ) ;
final SparseArray < String > contactIdToKey = new SparseArray < > ( ) ;
for ( HashMap . Entry < String , Contact > entry : contactsMapToSave . entrySet ( ) ) {
Contact value = entry . getValue ( ) ;
contactIdToKey . put ( value . contact_id , value . key ) ;
}
completedRequestsCount = 0 ;
final int count = ( int ) Math . ceil ( toImport . size ( ) / 500 . 0 ) ;
for ( int a = 0 ; a < count ; a + + ) {
final TLRPC . TL_contacts_importContacts req = new TLRPC . TL_contacts_importContacts ( ) ;
int start = a * 500 ;
int end = Math . min ( start + 500 , toImport . size ( ) ) ;
req . contacts = new ArrayList < > ( toImport . subList ( start , end ) ) ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
completedRequestsCount + + ;
if ( error = = null ) {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " contacts imported " ) ;
}
final TLRPC . TL_contacts_importedContacts res = ( TLRPC . TL_contacts_importedContacts ) response ;
if ( ! res . retry_contacts . isEmpty ( ) ) {
for ( int a1 = 0 ; a1 < res . retry_contacts . size ( ) ; a1 + + ) {
long id = res . retry_contacts . get ( a1 ) ;
contactsMapToSave . remove ( contactIdToKey . get ( ( int ) id ) ) ;
2017-12-08 18:35:59 +01:00
}
2019-01-23 18:03:33 +01:00
hasErrors [ 0 ] = true ;
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " result has retry contacts " ) ;
2017-12-08 18:35:59 +01:00
}
}
2019-01-23 18:03:33 +01:00
for ( int a1 = 0 ; a1 < res . popular_invites . size ( ) ; a1 + + ) {
TLRPC . TL_popularContact popularContact = res . popular_invites . get ( a1 ) ;
Contact contact = contactsMap . get ( contactIdToKey . get ( ( int ) popularContact . client_id ) ) ;
if ( contact ! = null ) {
contact . imported = popularContact . importers ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
/ * if ( BuildVars . LOGS_ENABLED ) {
for ( TLRPC . User user : res . users ) {
FileLog . e ( " received user " + user . first_name + " " + user . last_name + " " + user . phone ) ;
2014-03-05 17:42:10 +01:00
}
2019-01-23 18:03:33 +01:00
} * /
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putUsersAndChats ( res . users , null , true , true ) ;
2019-01-23 18:03:33 +01:00
ArrayList < TLRPC . TL_contact > cArr = new ArrayList < > ( ) ;
for ( int a1 = 0 ; a1 < res . imported . size ( ) ; a1 + + ) {
TLRPC . TL_contact contact = new TLRPC . TL_contact ( ) ;
contact . user_id = res . imported . get ( a1 ) . user_id ;
cArr . add ( contact ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
processLoadedContacts ( cArr , res . users , 2 ) ;
} else {
for ( int a1 = 0 ; a1 < req . contacts . size ( ) ; a1 + + ) {
TLRPC . TL_inputPhoneContact contact = req . contacts . get ( a1 ) ;
contactsMapToSave . remove ( contactIdToKey . get ( ( int ) contact . client_id ) ) ;
}
hasErrors [ 0 ] = true ;
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " import contacts error " + error . text ) ;
2014-03-05 17:42:10 +01:00
}
2019-01-23 18:03:33 +01:00
}
if ( completedRequestsCount = = count ) {
if ( ! contactsMapToSave . isEmpty ( ) ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( contactsMapToSave , false , false ) ;
2014-03-05 17:42:10 +01:00
}
2019-01-23 18:03:33 +01:00
Utilities . stageQueue . postRunnable ( ( ) - > {
contactsBookSPhones = contactsBookShort ;
contactsBook = contactsMap ;
contactsSyncInProgress = false ;
contactsBookLoaded = true ;
if ( first ) {
contactsLoaded = true ;
}
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
}
AndroidUtilities . runOnUIThread ( ( ) - > {
2018-07-30 04:07:02 +02:00
mergePhonebookAndTelegramContacts ( phoneBookSectionsDictFinal , phoneBookSectionsArrayFinal , phoneBookByShortPhonesFinal ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsImported ) ;
2019-01-23 18:03:33 +01:00
} ) ;
if ( hasErrors [ 0 ] ) {
2019-07-18 15:01:39 +02:00
Utilities . globalQueue . postRunnable ( ( ) - > getMessagesStorage ( ) . getCachedPhoneBook ( true ) , 60000 * 5 ) ;
2016-06-24 12:27:15 +02:00
}
} ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
} , ConnectionsManager . RequestFlagFailOnServerErrors | ConnectionsManager . RequestFlagCanCompress ) ;
2014-02-04 19:36:55 +01:00
}
} else {
2019-01-23 18:03:33 +01:00
Utilities . stageQueue . postRunnable ( ( ) - > {
contactsBookSPhones = contactsBookShort ;
contactsBook = contactsMap ;
contactsSyncInProgress = false ;
contactsBookLoaded = true ;
if ( first ) {
contactsLoaded = true ;
}
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
2014-03-04 20:29:32 +01:00
}
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
mergePhonebookAndTelegramContacts ( phoneBookSectionsDictFinal , phoneBookSectionsArrayFinal , phoneBookByShortPhonesFinal ) ;
updateUnregisteredContacts ( ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsImported ) ;
2019-01-23 18:03:33 +01:00
} ) ;
2014-03-04 20:29:32 +01:00
} ) ;
2019-01-23 18:03:33 +01:00
}
} else {
Utilities . stageQueue . postRunnable ( ( ) - > {
contactsBookSPhones = contactsBookShort ;
contactsBook = contactsMap ;
contactsSyncInProgress = false ;
contactsBookLoaded = true ;
if ( first ) {
contactsLoaded = true ;
}
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsLoaded & & contactsBookLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
2014-02-11 15:32:09 +01:00
}
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > mergePhonebookAndTelegramContacts ( phoneBookSectionsDictFinal , phoneBookSectionsArrayFinal , phoneBookByShortPhonesFinal ) ) ;
} ) ;
if ( ! contactsMap . isEmpty ( ) ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putCachedPhoneBook ( contactsMap , false , false ) ;
2014-02-04 19:36:55 +01:00
}
}
} ) ;
}
2014-06-13 12:42:21 +02:00
public boolean isLoadingContacts ( ) {
synchronized ( loadContactsSync ) {
return loadingContacts ;
}
}
2017-12-08 18:35:59 +01:00
private int getContactsHash ( ArrayList < TLRPC . TL_contact > contacts ) {
long acc = 0 ;
contacts = new ArrayList < > ( contacts ) ;
2019-01-23 18:03:33 +01:00
Collections . sort ( contacts , ( tl_contact , tl_contact2 ) - > {
if ( tl_contact . user_id > tl_contact2 . user_id ) {
return 1 ;
} else if ( tl_contact . user_id < tl_contact2 . user_id ) {
return - 1 ;
2017-12-08 18:35:59 +01:00
}
2019-01-23 18:03:33 +01:00
return 0 ;
2017-12-08 18:35:59 +01:00
} ) ;
int count = contacts . size ( ) ;
for ( int a = - 1 ; a < count ; a + + ) {
if ( a = = - 1 ) {
2019-07-18 15:01:39 +02:00
acc = ( ( acc * 20261 ) + 0x80000000L + getUserConfig ( ) . contactsSavedCount ) % 0x80000000L ;
2017-12-08 18:35:59 +01:00
} else {
TLRPC . TL_contact set = contacts . get ( a ) ;
acc = ( ( acc * 20261 ) + 0x80000000L + set . user_id ) % 0x80000000L ;
}
}
return ( int ) acc ;
}
public void loadContacts ( boolean fromCache , final int hash ) {
2014-06-13 12:42:21 +02:00
synchronized ( loadContactsSync ) {
loadingContacts = true ;
}
2014-02-04 19:36:55 +01:00
if ( fromCache ) {
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " load contacts from cache " ) ;
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . getContacts ( ) ;
2014-02-04 19:36:55 +01:00
} else {
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " load contacts from server " ) ;
}
2017-12-08 18:35:59 +01:00
2014-02-04 19:36:55 +01:00
TLRPC . TL_contacts_getContacts req = new TLRPC . TL_contacts_getContacts ( ) ;
2017-12-08 18:35:59 +01:00
req . hash = hash ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
if ( error = = null ) {
TLRPC . contacts_Contacts res = ( TLRPC . contacts_Contacts ) response ;
if ( hash ! = 0 & & res instanceof TLRPC . TL_contacts_contactsNotModified ) {
contactsLoaded = true ;
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsBookLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
}
2019-07-18 15:01:39 +02:00
getUserConfig ( ) . lastContactsSyncTime = ( int ) ( System . currentTimeMillis ( ) / 1000 ) ;
getUserConfig ( ) . saveConfig ( false ) ;
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
synchronized ( loadContactsSync ) {
loadingContacts = false ;
2018-07-30 04:07:02 +02:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2019-01-23 18:03:33 +01:00
} ) ;
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " load contacts don't change " ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
return ;
} else {
2019-07-18 15:01:39 +02:00
getUserConfig ( ) . contactsSavedCount = res . saved_count ;
getUserConfig ( ) . saveConfig ( false ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
processLoadedContacts ( res . contacts , res . users , 0 ) ;
2014-02-04 19:36:55 +01:00
}
2015-09-24 22:52:02 +02:00
} ) ;
2014-02-04 19:36:55 +01:00
}
}
public void processLoadedContacts ( final ArrayList < TLRPC . TL_contact > contactsArr , final ArrayList < TLRPC . User > usersArr , final int from ) {
2014-02-28 23:28:25 +01:00
//from: 0 - from server, 1 - from db, 2 - from imported contacts
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . putUsers ( usersArr , from = = 1 ) ;
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
final SparseArray < TLRPC . User > usersDict = new SparseArray < > ( ) ;
2014-03-10 10:27:49 +01:00
2019-01-23 18:03:33 +01:00
final boolean isEmpty = contactsArr . isEmpty ( ) ;
2014-11-19 11:32:27 +01:00
2019-01-23 18:03:33 +01:00
if ( ! contacts . isEmpty ( ) ) {
for ( int a = 0 ; a < contactsArr . size ( ) ; a + + ) {
TLRPC . TL_contact contact = contactsArr . get ( a ) ;
if ( contactsDict . get ( contact . user_id ) ! = null ) {
contactsArr . remove ( a ) ;
a - - ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
contactsArr . addAll ( contacts ) ;
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < contactsArr . size ( ) ; a + + ) {
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( contactsArr . get ( a ) . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user ! = null ) {
usersDict . put ( user . id , user ) ;
//if (BuildVars.DEBUG_VERSION) {
// FileLog.e("loaded user contact " + user.first_name + " " + user.last_name + " " + user.phone);
//}
}
}
Utilities . stageQueue . postRunnable ( ( ) - > {
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " done loading contacts " ) ;
}
2019-07-18 15:01:39 +02:00
if ( from = = 1 & & ( contactsArr . isEmpty ( ) | | Math . abs ( System . currentTimeMillis ( ) / 1000 - getUserConfig ( ) . lastContactsSyncTime ) > = 24 * 60 * 60 ) ) {
2019-01-23 18:03:33 +01:00
loadContacts ( false , getContactsHash ( contactsArr ) ) ;
if ( contactsArr . isEmpty ( ) ) {
return ;
2014-03-10 10:27:49 +01:00
}
}
2019-01-23 18:03:33 +01:00
if ( from = = 0 ) {
2019-07-18 15:01:39 +02:00
getUserConfig ( ) . lastContactsSyncTime = ( int ) ( System . currentTimeMillis ( ) / 1000 ) ;
getUserConfig ( ) . saveConfig ( false ) ;
2019-01-23 18:03:33 +01:00
}
2014-03-10 10:27:49 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < contactsArr . size ( ) ; a + + ) {
TLRPC . TL_contact contact = contactsArr . get ( a ) ;
2019-07-18 15:01:39 +02:00
if ( usersDict . get ( contact . user_id ) = = null & & contact . user_id ! = getUserConfig ( ) . getClientUserId ( ) ) {
2019-01-23 18:03:33 +01:00
loadContacts ( false , 0 ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
2019-01-23 18:03:33 +01:00
FileLog . d ( " contacts are broken, load from server " ) ;
2015-08-13 11:23:31 +02:00
}
2019-01-23 18:03:33 +01:00
return ;
}
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
if ( from ! = 1 ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putUsersAndChats ( usersArr , null , true , true ) ;
getMessagesStorage ( ) . putContacts ( contactsArr , from ! = 2 ) ;
2019-01-23 18:03:33 +01:00
}
2014-03-10 10:27:49 +01:00
2019-01-23 18:03:33 +01:00
Collections . sort ( contactsArr , ( tl_contact , tl_contact2 ) - > {
TLRPC . User user1 = usersDict . get ( tl_contact . user_id ) ;
TLRPC . User user2 = usersDict . get ( tl_contact2 . user_id ) ;
String name1 = UserObject . getFirstName ( user1 ) ;
String name2 = UserObject . getFirstName ( user2 ) ;
return name1 . compareTo ( name2 ) ;
} ) ;
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
final ConcurrentHashMap < Integer , TLRPC . TL_contact > contactsDictionary = new ConcurrentHashMap < > ( 20 , 1 . 0f , 2 ) ;
final HashMap < String , ArrayList < TLRPC . TL_contact > > sectionsDict = new HashMap < > ( ) ;
final HashMap < String , ArrayList < TLRPC . TL_contact > > sectionsDictMutual = new HashMap < > ( ) ;
final ArrayList < String > sortedSectionsArray = new ArrayList < > ( ) ;
final ArrayList < String > sortedSectionsArrayMutual = new ArrayList < > ( ) ;
HashMap < String , TLRPC . TL_contact > contactsByPhonesDict = null ;
HashMap < String , TLRPC . TL_contact > contactsByPhonesShortDict = null ;
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
if ( ! contactsBookLoaded ) {
contactsByPhonesDict = new HashMap < > ( ) ;
contactsByPhonesShortDict = new HashMap < > ( ) ;
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
final HashMap < String , TLRPC . TL_contact > contactsByPhonesDictFinal = contactsByPhonesDict ;
final HashMap < String , TLRPC . TL_contact > contactsByPhonesShortDictFinal = contactsByPhonesShortDict ;
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < contactsArr . size ( ) ; a + + ) {
TLRPC . TL_contact value = contactsArr . get ( a ) ;
TLRPC . User user = usersDict . get ( value . user_id ) ;
if ( user = = null ) {
continue ;
}
contactsDictionary . put ( value . user_id , value ) ;
if ( contactsByPhonesDict ! = null & & ! TextUtils . isEmpty ( user . phone ) ) {
contactsByPhonesDict . put ( user . phone , value ) ;
contactsByPhonesShortDict . put ( user . phone . substring ( Math . max ( 0 , user . phone . length ( ) - 7 ) ) , value ) ;
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
String key = UserObject . getFirstName ( user ) ;
if ( key . length ( ) > 1 ) {
key = key . substring ( 0 , 1 ) ;
}
if ( key . length ( ) = = 0 ) {
key = " # " ;
} else {
key = key . toUpperCase ( ) ;
}
String replace = sectionsToReplace . get ( key ) ;
if ( replace ! = null ) {
key = replace ;
}
ArrayList < TLRPC . TL_contact > arr = sectionsDict . get ( key ) ;
if ( arr = = null ) {
arr = new ArrayList < > ( ) ;
sectionsDict . put ( key , arr ) ;
sortedSectionsArray . add ( key ) ;
}
arr . add ( value ) ;
if ( user . mutual_contact ) {
arr = sectionsDictMutual . get ( key ) ;
if ( arr = = null ) {
arr = new ArrayList < > ( ) ;
sectionsDictMutual . put ( key , arr ) ;
sortedSectionsArrayMutual . add ( key ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
arr . add ( value ) ;
}
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
Collections . sort ( sortedSectionsArray , ( s , s2 ) - > {
char cv1 = s . charAt ( 0 ) ;
char cv2 = s2 . charAt ( 0 ) ;
if ( cv1 = = '#' ) {
return 1 ;
} else if ( cv2 = = '#' ) {
return - 1 ;
}
return s . compareTo ( s2 ) ;
} ) ;
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
Collections . sort ( sortedSectionsArrayMutual , ( s , s2 ) - > {
char cv1 = s . charAt ( 0 ) ;
char cv2 = s2 . charAt ( 0 ) ;
if ( cv1 = = '#' ) {
return 1 ;
} else if ( cv2 = = '#' ) {
return - 1 ;
}
return s . compareTo ( s2 ) ;
} ) ;
2015-09-24 22:52:02 +02:00
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
contacts = contactsArr ;
contactsDict = contactsDictionary ;
usersSectionsDict = sectionsDict ;
usersMutualSectionsDict = sectionsDictMutual ;
sortedUsersSectionsArray = sortedSectionsArray ;
sortedUsersMutualSectionsArray = sortedSectionsArrayMutual ;
if ( from ! = 2 ) {
synchronized ( loadContactsSync ) {
loadingContacts = false ;
}
}
performWriteContactsToPhoneBook ( ) ;
updateUnregisteredContacts ( ) ;
2014-02-04 19:36:55 +01:00
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2014-11-19 11:32:27 +01:00
2019-01-23 18:03:33 +01:00
if ( from ! = 1 & & ! isEmpty ) {
saveContactsLoadTime ( ) ;
} else {
reloadContactsStatusesMaybe ( ) ;
}
} ) ;
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
if ( ! delayedContactsUpdate . isEmpty ( ) & & contactsLoaded & & contactsBookLoaded ) {
applyContactsUpdates ( delayedContactsUpdate , null , null , null ) ;
delayedContactsUpdate . clear ( ) ;
}
2014-02-28 23:28:25 +01:00
2019-01-23 18:03:33 +01:00
if ( contactsByPhonesDictFinal ! = null ) {
AndroidUtilities . runOnUIThread ( ( ) - > {
Utilities . globalQueue . postRunnable ( ( ) - > {
contactsByPhone = contactsByPhonesDictFinal ;
contactsByShortPhone = contactsByPhonesShortDictFinal ;
} ) ;
if ( contactsSyncInProgress ) {
return ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
contactsSyncInProgress = true ;
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . getCachedPhoneBook ( false ) ;
2019-01-23 18:03:33 +01:00
} ) ;
} else {
contactsLoaded = true ;
}
} ) ;
2014-02-04 19:36:55 +01:00
} ) ;
}
2019-05-14 14:08:05 +02:00
public boolean isContact ( int uid ) {
return contactsDict . get ( uid ) ! = null ;
}
2019-12-31 14:08:08 +01:00
public void reloadContactsStatusesMaybe ( ) {
2014-11-19 11:32:27 +01:00
try {
2018-07-30 04:07:02 +02:00
SharedPreferences preferences = MessagesController . getMainSettings ( currentAccount ) ;
2014-11-19 11:32:27 +01:00
long lastReloadStatusTime = preferences . getLong ( " lastReloadStatusTime " , 0 ) ;
2019-12-31 14:08:08 +01:00
if ( lastReloadStatusTime < System . currentTimeMillis ( ) - 1000 * 60 * 60 * 3 ) {
2014-11-19 11:32:27 +01:00
reloadContactsStatuses ( ) ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-11-19 11:32:27 +01:00
}
}
private void saveContactsLoadTime ( ) {
try {
2018-07-30 04:07:02 +02:00
SharedPreferences preferences = MessagesController . getMainSettings ( currentAccount ) ;
2020-06-25 17:29:04 +02:00
preferences . edit ( ) . putLong ( " lastReloadStatusTime " , System . currentTimeMillis ( ) ) . apply ( ) ;
2014-11-19 11:32:27 +01:00
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-11-19 11:32:27 +01:00
}
}
2018-07-30 04:07:02 +02:00
private void mergePhonebookAndTelegramContacts ( final HashMap < String , ArrayList < Object > > phoneBookSectionsDictFinal , final ArrayList < String > phoneBookSectionsArrayFinal , final HashMap < String , Contact > phoneBookByShortPhonesFinal ) {
final ArrayList < TLRPC . TL_contact > contactsCopy = new ArrayList < > ( contacts ) ;
2019-01-23 18:03:33 +01:00
Utilities . globalQueue . postRunnable ( ( ) - > {
for ( int a = 0 , size = contactsCopy . size ( ) ; a < size ; a + + ) {
TLRPC . TL_contact value = contactsCopy . get ( a ) ;
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( value . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user = = null | | TextUtils . isEmpty ( user . phone ) ) {
continue ;
}
String phone = user . phone . substring ( Math . max ( 0 , user . phone . length ( ) - 7 ) ) ;
Contact contact = phoneBookByShortPhonesFinal . get ( phone ) ;
if ( contact ! = null ) {
if ( contact . user = = null ) {
contact . user = user ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
} else {
String key = Contact . getLetter ( user . first_name , user . last_name ) ;
ArrayList < Object > arrayList = phoneBookSectionsDictFinal . get ( key ) ;
if ( arrayList = = null ) {
arrayList = new ArrayList < > ( ) ;
phoneBookSectionsDictFinal . put ( key , arrayList ) ;
phoneBookSectionsArrayFinal . add ( key ) ;
}
arrayList . add ( user ) ;
}
}
for ( ArrayList < Object > arrayList : phoneBookSectionsDictFinal . values ( ) ) {
Collections . sort ( arrayList , ( o1 , o2 ) - > {
String name1 ;
String name2 ;
if ( o1 instanceof TLRPC . User ) {
TLRPC . User user = ( TLRPC . User ) o1 ;
name1 = ContactsController . formatName ( user . first_name , user . last_name ) ;
} else if ( o1 instanceof Contact ) {
Contact contact = ( Contact ) o1 ;
if ( contact . user ! = null ) {
name1 = ContactsController . formatName ( contact . user . first_name , contact . user . last_name ) ;
} else {
name1 = ContactsController . formatName ( contact . first_name , contact . last_name ) ;
2018-07-30 04:07:02 +02:00
}
} else {
2019-01-23 18:03:33 +01:00
name1 = " " ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
if ( o2 instanceof TLRPC . User ) {
TLRPC . User user = ( TLRPC . User ) o2 ;
name2 = ContactsController . formatName ( user . first_name , user . last_name ) ;
} else if ( o2 instanceof Contact ) {
Contact contact = ( Contact ) o2 ;
if ( contact . user ! = null ) {
name2 = ContactsController . formatName ( contact . user . first_name , contact . user . last_name ) ;
} else {
name2 = ContactsController . formatName ( contact . first_name , contact . last_name ) ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
} else {
name2 = " " ;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
return name1 . compareTo ( name2 ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
2019-01-23 18:03:33 +01:00
Collections . sort ( phoneBookSectionsArrayFinal , ( s , s2 ) - > {
char cv1 = s . charAt ( 0 ) ;
char cv2 = s2 . charAt ( 0 ) ;
if ( cv1 = = '#' ) {
return 1 ;
} else if ( cv2 = = '#' ) {
return - 1 ;
}
return s . compareTo ( s2 ) ;
} ) ;
AndroidUtilities . runOnUIThread ( ( ) - > {
phoneBookSectionsArray = phoneBookSectionsArrayFinal ;
phoneBookSectionsDict = phoneBookSectionsDictFinal ;
} ) ;
2018-07-30 04:07:02 +02:00
} ) ;
}
private void updateUnregisteredContacts ( ) {
2015-02-26 02:32:51 +01:00
final HashMap < String , TLRPC . TL_contact > contactsPhonesShort = new HashMap < > ( ) ;
2014-02-04 19:36:55 +01:00
2018-07-30 04:07:02 +02:00
for ( int a = 0 , size = contacts . size ( ) ; a < size ; a + + ) {
TLRPC . TL_contact value = contacts . get ( a ) ;
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( value . user_id ) ;
2017-03-31 01:58:05 +02:00
if ( user = = null | | TextUtils . isEmpty ( user . phone ) ) {
2014-02-04 19:36:55 +01:00
continue ;
}
2014-02-28 23:28:25 +01:00
contactsPhonesShort . put ( user . phone , value ) ;
2014-02-04 19:36:55 +01:00
}
2015-02-26 02:32:51 +01:00
final ArrayList < Contact > sortedPhoneBookContacts = new ArrayList < > ( ) ;
2017-12-08 18:35:59 +01:00
for ( HashMap . Entry < String , Contact > pair : contactsBook . entrySet ( ) ) {
2014-02-04 19:36:55 +01:00
Contact value = pair . getValue ( ) ;
boolean skip = false ;
for ( int a = 0 ; a < value . phones . size ( ) ; a + + ) {
String sphone = value . shortPhones . get ( a ) ;
if ( contactsPhonesShort . containsKey ( sphone ) | | value . phoneDeleted . get ( a ) = = 1 ) {
skip = true ;
break ;
}
}
if ( skip ) {
continue ;
}
2014-11-10 12:05:22 +01:00
sortedPhoneBookContacts . add ( value ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
Collections . sort ( sortedPhoneBookContacts , ( contact , contact2 ) - > {
String toComapre1 = contact . first_name ;
if ( toComapre1 . length ( ) = = 0 ) {
toComapre1 = contact . last_name ;
}
String toComapre2 = contact2 . first_name ;
if ( toComapre2 . length ( ) = = 0 ) {
toComapre2 = contact2 . last_name ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
return toComapre1 . compareTo ( toComapre2 ) ;
2014-02-04 19:36:55 +01:00
} ) ;
2014-11-10 12:05:22 +01:00
phoneBookContacts = sortedPhoneBookContacts ;
2014-02-04 19:36:55 +01:00
}
private void buildContactsSectionsArrays ( boolean sort ) {
if ( sort ) {
2019-01-23 18:03:33 +01:00
Collections . sort ( contacts , ( tl_contact , tl_contact2 ) - > {
2019-07-18 15:01:39 +02:00
TLRPC . User user1 = getMessagesController ( ) . getUser ( tl_contact . user_id ) ;
TLRPC . User user2 = getMessagesController ( ) . getUser ( tl_contact2 . user_id ) ;
2019-01-23 18:03:33 +01:00
String name1 = UserObject . getFirstName ( user1 ) ;
String name2 = UserObject . getFirstName ( user2 ) ;
return name1 . compareTo ( name2 ) ;
2014-02-04 19:36:55 +01:00
} ) ;
}
2015-02-26 02:32:51 +01:00
final HashMap < String , ArrayList < TLRPC . TL_contact > > sectionsDict = new HashMap < > ( ) ;
final ArrayList < String > sortedSectionsArray = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
2017-12-08 18:35:59 +01:00
for ( int a = 0 ; a < contacts . size ( ) ; a + + ) {
TLRPC . TL_contact value = contacts . get ( a ) ;
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( value . user_id ) ;
2014-02-04 19:36:55 +01:00
if ( user = = null ) {
continue ;
}
2015-06-29 19:12:11 +02:00
String key = UserObject . getFirstName ( user ) ;
2015-02-26 02:32:51 +01:00
if ( key . length ( ) > 1 ) {
key = key . substring ( 0 , 1 ) ;
}
2014-02-04 19:36:55 +01:00
if ( key . length ( ) = = 0 ) {
key = " # " ;
} else {
key = key . toUpperCase ( ) ;
}
2015-02-26 02:32:51 +01:00
String replace = sectionsToReplace . get ( key ) ;
if ( replace ! = null ) {
key = replace ;
2014-02-04 19:36:55 +01:00
}
ArrayList < TLRPC . TL_contact > arr = sectionsDict . get ( key ) ;
if ( arr = = null ) {
2015-02-26 02:32:51 +01:00
arr = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
sectionsDict . put ( key , arr ) ;
sortedSectionsArray . add ( key ) ;
}
arr . add ( value ) ;
}
2019-01-23 18:03:33 +01:00
Collections . sort ( sortedSectionsArray , ( s , s2 ) - > {
char cv1 = s . charAt ( 0 ) ;
char cv2 = s2 . charAt ( 0 ) ;
if ( cv1 = = '#' ) {
return 1 ;
} else if ( cv2 = = '#' ) {
return - 1 ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
return s . compareTo ( s2 ) ;
2014-02-04 19:36:55 +01:00
} ) ;
usersSectionsDict = sectionsDict ;
sortedUsersSectionsArray = sortedSectionsArray ;
}
2015-11-26 22:04:02 +01:00
private boolean hasContactsPermission ( ) {
if ( Build . VERSION . SDK_INT > = 23 ) {
return ApplicationLoader . applicationContext . checkSelfPermission ( android . Manifest . permission . READ_CONTACTS ) = = PackageManager . PERMISSION_GRANTED ;
}
Cursor cursor = null ;
try {
ContentResolver cr = ApplicationLoader . applicationContext . getContentResolver ( ) ;
cursor = cr . query ( ContactsContract . CommonDataKinds . Phone . CONTENT_URI , projectionPhones , null , null , null ) ;
if ( cursor = = null | | cursor . getCount ( ) = = 0 ) {
return false ;
}
2016-10-11 13:57:01 +02:00
} catch ( Throwable e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-11-26 22:04:02 +01:00
} finally {
try {
if ( cursor ! = null ) {
cursor . close ( ) ;
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2015-11-26 22:04:02 +01:00
}
}
return true ;
}
2014-06-07 01:35:21 +02:00
private void performWriteContactsToPhoneBookInternal ( ArrayList < TLRPC . TL_contact > contactsArray ) {
2018-07-30 04:07:02 +02:00
Cursor cursor = null ;
2014-02-28 23:28:25 +01:00
try {
2015-11-26 22:04:02 +01:00
if ( ! hasContactsPermission ( ) ) {
2015-10-29 18:10:07 +01:00
return ;
}
2020-08-14 18:58:22 +02:00
final SharedPreferences settings = MessagesController . getMainSettings ( currentAccount ) ;
final boolean forceUpdate = ! settings . getBoolean ( " contacts_updated_v7 " , false ) ;
if ( forceUpdate ) {
settings . edit ( ) . putBoolean ( " contacts_updated_v7 " , true ) . commit ( ) ;
}
final ContentResolver contentResolver = ApplicationLoader . applicationContext . getContentResolver ( ) ;
2018-07-30 04:07:02 +02:00
Uri rawContactUri = ContactsContract . RawContacts . CONTENT_URI . buildUpon ( ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_NAME , systemAccount . name ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_TYPE , systemAccount . type ) . build ( ) ;
2020-08-14 18:58:22 +02:00
cursor = contentResolver . query ( rawContactUri , new String [ ] { BaseColumns . _ID , ContactsContract . RawContacts . SYNC2 } , null , null , null ) ;
2018-07-30 04:07:02 +02:00
SparseLongArray bookContacts = new SparseLongArray ( ) ;
if ( cursor ! = null ) {
while ( cursor . moveToNext ( ) ) {
bookContacts . put ( cursor . getInt ( 1 ) , cursor . getLong ( 0 ) ) ;
2014-02-28 23:28:25 +01:00
}
2018-07-30 04:07:02 +02:00
cursor . close ( ) ;
cursor = null ;
2014-02-28 23:28:25 +01:00
2015-11-26 22:04:02 +01:00
for ( int a = 0 ; a < contactsArray . size ( ) ; a + + ) {
TLRPC . TL_contact u = contactsArray . get ( a ) ;
2020-08-14 18:58:22 +02:00
if ( forceUpdate | | bookContacts . indexOfKey ( u . user_id ) < 0 ) {
addContactToPhoneBook ( getMessagesController ( ) . getUser ( u . user_id ) , forceUpdate ) ;
2014-02-28 23:28:25 +01:00
}
}
}
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2018-07-30 04:07:02 +02:00
} finally {
if ( cursor ! = null ) {
cursor . close ( ) ;
}
2014-02-28 23:28:25 +01:00
}
}
2014-02-04 19:36:55 +01:00
private void performWriteContactsToPhoneBook ( ) {
2018-07-30 04:07:02 +02:00
final ArrayList < TLRPC . TL_contact > contactsArray = new ArrayList < > ( contacts ) ;
2019-01-23 18:03:33 +01:00
Utilities . phoneBookQueue . postRunnable ( ( ) - > performWriteContactsToPhoneBookInternal ( contactsArray ) ) ;
2014-02-04 19:36:55 +01:00
}
private void applyContactsUpdates ( ArrayList < Integer > ids , ConcurrentHashMap < Integer , TLRPC . User > userDict , ArrayList < TLRPC . TL_contact > newC , ArrayList < Integer > contactsTD ) {
if ( newC = = null | | contactsTD = = null ) {
2015-02-26 02:32:51 +01:00
newC = new ArrayList < > ( ) ;
contactsTD = new ArrayList < > ( ) ;
2016-06-24 12:27:15 +02:00
for ( int a = 0 ; a < ids . size ( ) ; a + + ) {
Integer uid = ids . get ( a ) ;
2014-02-04 19:36:55 +01:00
if ( uid > 0 ) {
TLRPC . TL_contact contact = new TLRPC . TL_contact ( ) ;
contact . user_id = uid ;
newC . add ( contact ) ;
} else if ( uid < 0 ) {
contactsTD . add ( - uid ) ;
}
}
}
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " process update - contacts add = " + newC . size ( ) + " delete = " + contactsTD . size ( ) ) ;
}
2014-02-04 19:36:55 +01:00
2014-10-08 22:22:22 +02:00
StringBuilder toAdd = new StringBuilder ( ) ;
StringBuilder toDelete = new StringBuilder ( ) ;
2014-02-04 19:36:55 +01:00
boolean reloadContacts = false ;
2016-06-24 12:27:15 +02:00
for ( int a = 0 ; a < newC . size ( ) ; a + + ) {
TLRPC . TL_contact newContact = newC . get ( a ) ;
2014-02-04 19:36:55 +01:00
TLRPC . User user = null ;
if ( userDict ! = null ) {
user = userDict . get ( newContact . user_id ) ;
}
if ( user = = null ) {
2019-07-18 15:01:39 +02:00
user = getMessagesController ( ) . getUser ( newContact . user_id ) ;
2014-02-11 15:32:09 +01:00
} else {
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . putUser ( user , true ) ;
2014-02-04 19:36:55 +01:00
}
2017-03-31 01:58:05 +02:00
if ( user = = null | | TextUtils . isEmpty ( user . phone ) ) {
2014-02-04 19:36:55 +01:00
reloadContacts = true ;
continue ;
}
2014-02-28 23:28:25 +01:00
Contact contact = contactsBookSPhones . get ( user . phone ) ;
2014-02-04 19:36:55 +01:00
if ( contact ! = null ) {
2014-02-28 23:28:25 +01:00
int index = contact . shortPhones . indexOf ( user . phone ) ;
2014-02-04 19:36:55 +01:00
if ( index ! = - 1 ) {
contact . phoneDeleted . set ( index , 0 ) ;
}
}
if ( toAdd . length ( ) ! = 0 ) {
2014-10-08 22:22:22 +02:00
toAdd . append ( " , " ) ;
2014-02-04 19:36:55 +01:00
}
2014-10-08 22:22:22 +02:00
toAdd . append ( user . phone ) ;
2014-02-04 19:36:55 +01:00
}
2016-06-24 12:27:15 +02:00
for ( int a = 0 ; a < contactsTD . size ( ) ; a + + ) {
final Integer uid = contactsTD . get ( a ) ;
2019-01-23 18:03:33 +01:00
Utilities . phoneBookQueue . postRunnable ( ( ) - > deleteContactFromPhoneBook ( uid ) ) ;
2014-02-04 19:36:55 +01:00
TLRPC . User user = null ;
if ( userDict ! = null ) {
user = userDict . get ( uid ) ;
}
if ( user = = null ) {
2019-07-18 15:01:39 +02:00
user = getMessagesController ( ) . getUser ( uid ) ;
2014-02-11 15:32:09 +01:00
} else {
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . putUser ( user , true ) ;
2014-02-04 19:36:55 +01:00
}
if ( user = = null ) {
reloadContacts = true ;
continue ;
}
2017-03-31 01:58:05 +02:00
if ( ! TextUtils . isEmpty ( user . phone ) ) {
2014-02-28 23:28:25 +01:00
Contact contact = contactsBookSPhones . get ( user . phone ) ;
2014-02-04 19:36:55 +01:00
if ( contact ! = null ) {
2014-02-28 23:28:25 +01:00
int index = contact . shortPhones . indexOf ( user . phone ) ;
2014-02-04 19:36:55 +01:00
if ( index ! = - 1 ) {
contact . phoneDeleted . set ( index , 1 ) ;
}
}
if ( toDelete . length ( ) ! = 0 ) {
2014-10-08 22:22:22 +02:00
toDelete . append ( " , " ) ;
2014-02-04 19:36:55 +01:00
}
2014-10-08 22:22:22 +02:00
toDelete . append ( user . phone ) ;
2014-02-04 19:36:55 +01:00
}
}
if ( toAdd . length ( ) ! = 0 | | toDelete . length ( ) ! = 0 ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . applyPhoneBookUpdates ( toAdd . toString ( ) , toDelete . toString ( ) ) ;
2014-02-04 19:36:55 +01:00
}
if ( reloadContacts ) {
2019-01-23 18:03:33 +01:00
Utilities . stageQueue . postRunnable ( ( ) - > loadContacts ( false , 0 ) ) ;
2014-02-04 19:36:55 +01:00
} else {
final ArrayList < TLRPC . TL_contact > newContacts = newC ;
final ArrayList < Integer > contactsToDelete = contactsTD ;
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
for ( int a = 0 ; a < newContacts . size ( ) ; a + + ) {
TLRPC . TL_contact contact = newContacts . get ( a ) ;
if ( contactsDict . get ( contact . user_id ) = = null ) {
contacts . add ( contact ) ;
contactsDict . put ( contact . user_id , contact ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
for ( int a = 0 ; a < contactsToDelete . size ( ) ; a + + ) {
Integer uid = contactsToDelete . get ( a ) ;
TLRPC . TL_contact contact = contactsDict . get ( uid ) ;
if ( contact ! = null ) {
contacts . remove ( contact ) ;
contactsDict . remove ( uid ) ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
if ( ! newContacts . isEmpty ( ) ) {
updateUnregisteredContacts ( ) ;
performWriteContactsToPhoneBook ( ) ;
}
performSyncPhoneBook ( getContactsCopy ( contactsBook ) , false , false , false , false , true , false ) ;
buildContactsSectionsArrays ( ! newContacts . isEmpty ( ) ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2014-02-04 19:36:55 +01:00
} ) ;
}
}
public void processContactsUpdates ( ArrayList < Integer > ids , ConcurrentHashMap < Integer , TLRPC . User > userDict ) {
2015-02-26 02:32:51 +01:00
final ArrayList < TLRPC . TL_contact > newContacts = new ArrayList < > ( ) ;
final ArrayList < Integer > contactsToDelete = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
for ( Integer uid : ids ) {
if ( uid > 0 ) {
TLRPC . TL_contact contact = new TLRPC . TL_contact ( ) ;
contact . user_id = uid ;
newContacts . add ( contact ) ;
if ( ! delayedContactsUpdate . isEmpty ( ) ) {
int idx = delayedContactsUpdate . indexOf ( - uid ) ;
if ( idx ! = - 1 ) {
delayedContactsUpdate . remove ( idx ) ;
}
}
} else if ( uid < 0 ) {
contactsToDelete . add ( - uid ) ;
if ( ! delayedContactsUpdate . isEmpty ( ) ) {
int idx = delayedContactsUpdate . indexOf ( - uid ) ;
if ( idx ! = - 1 ) {
delayedContactsUpdate . remove ( idx ) ;
}
}
}
}
if ( ! contactsToDelete . isEmpty ( ) ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . deleteContacts ( contactsToDelete ) ;
2014-02-04 19:36:55 +01:00
}
if ( ! newContacts . isEmpty ( ) ) {
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putContacts ( newContacts , false ) ;
2014-02-04 19:36:55 +01:00
}
if ( ! contactsLoaded | | ! contactsBookLoaded ) {
delayedContactsUpdate . addAll ( ids ) ;
2018-07-30 04:07:02 +02:00
if ( BuildVars . LOGS_ENABLED ) {
FileLog . d ( " delay update - contacts add = " + newContacts . size ( ) + " delete = " + contactsToDelete . size ( ) ) ;
}
2014-02-04 19:36:55 +01:00
} else {
applyContactsUpdates ( ids , userDict , newContacts , contactsToDelete ) ;
}
}
2014-02-28 23:28:25 +01:00
public long addContactToPhoneBook ( TLRPC . User user , boolean check ) {
2019-07-18 15:01:39 +02:00
if ( systemAccount = = null | | user = = null ) {
2014-02-04 19:36:55 +01:00
return - 1 ;
}
2015-11-26 22:04:02 +01:00
if ( ! hasContactsPermission ( ) ) {
2015-10-29 18:10:07 +01:00
return - 1 ;
}
2014-02-04 19:36:55 +01:00
long res = - 1 ;
synchronized ( observerLock ) {
ignoreChanges = true ;
}
2014-02-28 23:28:25 +01:00
ContentResolver contentResolver = ApplicationLoader . applicationContext . getContentResolver ( ) ;
if ( check ) {
try {
2018-07-30 04:07:02 +02:00
Uri rawContactUri = ContactsContract . RawContacts . CONTENT_URI . buildUpon ( ) . appendQueryParameter ( ContactsContract . CALLER_IS_SYNCADAPTER , " true " ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_NAME , systemAccount . name ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_TYPE , systemAccount . type ) . build ( ) ;
2014-02-28 23:28:25 +01:00
int value = contentResolver . delete ( rawContactUri , ContactsContract . RawContacts . SYNC2 + " = " + user . id , null ) ;
2019-03-03 21:40:48 +01:00
} catch ( Exception ignore ) {
2014-02-28 23:28:25 +01:00
}
}
2015-02-26 02:32:51 +01:00
ArrayList < ContentProviderOperation > query = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
ContentProviderOperation . Builder builder = ContentProviderOperation . newInsert ( ContactsContract . RawContacts . CONTENT_URI ) ;
2018-07-30 04:07:02 +02:00
builder . withValue ( ContactsContract . RawContacts . ACCOUNT_NAME , systemAccount . name ) ;
builder . withValue ( ContactsContract . RawContacts . ACCOUNT_TYPE , systemAccount . type ) ;
2019-07-18 15:01:39 +02:00
builder . withValue ( ContactsContract . RawContacts . SYNC1 , TextUtils . isEmpty ( user . phone ) ? " " : user . phone ) ;
2014-02-04 19:36:55 +01:00
builder . withValue ( ContactsContract . RawContacts . SYNC2 , user . id ) ;
query . 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 . GIVEN_NAME , user . first_name ) ;
builder . withValue ( ContactsContract . CommonDataKinds . StructuredName . FAMILY_NAME , user . last_name ) ;
query . add ( builder . build ( ) ) ;
2014-02-28 23:28:25 +01:00
// builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
// builder.withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0);
// builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
// builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "+" + user.phone);
// builder.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
// query.add(builder.build());
2014-02-04 19:36:55 +01:00
2020-08-14 18:58:22 +02:00
final String phoneOrName = TextUtils . isEmpty ( user . phone ) ? ContactsController . formatName ( user . first_name , user . last_name ) : " + " + user . phone ;
2014-02-04 19:36:55 +01:00
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.telegram.messenger.android.profile " ) ;
2015-05-03 13:48:36 +02:00
builder . withValue ( ContactsContract . Data . DATA1 , user . id ) ;
2014-02-04 19:36:55 +01:00
builder . withValue ( ContactsContract . Data . DATA2 , " Telegram Profile " ) ;
2020-08-14 18:58:22 +02:00
builder . withValue ( ContactsContract . Data . DATA3 , LocaleController . formatString ( " ContactShortcutMessage " , R . string . ContactShortcutMessage , phoneOrName ) ) ;
builder . withValue ( ContactsContract . Data . DATA4 , user . id ) ;
query . 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.telegram.messenger.android.call " ) ;
builder . withValue ( ContactsContract . Data . DATA1 , user . id ) ;
builder . withValue ( ContactsContract . Data . DATA2 , " Telegram Voice Call " ) ;
builder . withValue ( ContactsContract . Data . DATA3 , LocaleController . formatString ( " ContactShortcutVoiceCall " , R . string . ContactShortcutVoiceCall , phoneOrName ) ) ;
2014-02-04 19:36:55 +01:00
builder . withValue ( ContactsContract . Data . DATA4 , user . id ) ;
query . add ( builder . build ( ) ) ;
2020-08-14 18:58:22 +02:00
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.telegram.messenger.android.call.video " ) ;
builder . withValue ( ContactsContract . Data . DATA1 , user . id ) ;
builder . withValue ( ContactsContract . Data . DATA2 , " Telegram Video Call " ) ;
builder . withValue ( ContactsContract . Data . DATA3 , LocaleController . formatString ( " ContactShortcutVideoCall " , R . string . ContactShortcutVideoCall , phoneOrName ) ) ;
builder . withValue ( ContactsContract . Data . DATA4 , user . id ) ;
query . add ( builder . build ( ) ) ;
2014-02-04 19:36:55 +01:00
try {
2014-02-28 23:28:25 +01:00
ContentProviderResult [ ] result = contentResolver . applyBatch ( ContactsContract . AUTHORITY , query ) ;
2015-11-26 22:04:02 +01:00
if ( result ! = null & & result . length > 0 & & result [ 0 ] . uri ! = null ) {
res = Long . parseLong ( result [ 0 ] . uri . getLastPathSegment ( ) ) ;
}
2019-03-03 21:40:48 +01:00
} catch ( Exception ignore ) {
2014-02-04 19:36:55 +01:00
}
synchronized ( observerLock ) {
ignoreChanges = false ;
}
return res ;
}
private void deleteContactFromPhoneBook ( int uid ) {
2015-11-26 22:04:02 +01:00
if ( ! hasContactsPermission ( ) ) {
2015-10-29 18:10:07 +01:00
return ;
}
2014-02-04 19:36:55 +01:00
synchronized ( observerLock ) {
ignoreChanges = true ;
}
try {
2015-10-29 18:10:07 +01:00
ContentResolver contentResolver = ApplicationLoader . applicationContext . getContentResolver ( ) ;
2018-07-30 04:07:02 +02:00
Uri rawContactUri = ContactsContract . RawContacts . CONTENT_URI . buildUpon ( ) . appendQueryParameter ( ContactsContract . CALLER_IS_SYNCADAPTER , " true " ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_NAME , systemAccount . name ) . appendQueryParameter ( ContactsContract . RawContacts . ACCOUNT_TYPE , systemAccount . type ) . build ( ) ;
2014-02-04 19:36:55 +01:00
int value = contentResolver . delete ( rawContactUri , ContactsContract . RawContacts . SYNC2 + " = " + uid , null ) ;
} catch ( Exception e ) {
2017-03-31 01:58:05 +02:00
FileLog . e ( e ) ;
2014-02-04 19:36:55 +01:00
}
synchronized ( observerLock ) {
ignoreChanges = false ;
}
}
2015-05-03 13:48:36 +02:00
protected void markAsContacted ( final String contactId ) {
if ( contactId = = null ) {
return ;
}
2019-01-23 18:03:33 +01:00
Utilities . phoneBookQueue . postRunnable ( ( ) - > {
Uri uri = Uri . parse ( contactId ) ;
ContentValues values = new ContentValues ( ) ;
values . put ( ContactsContract . Contacts . LAST_TIME_CONTACTED , System . currentTimeMillis ( ) ) ;
ContentResolver cr = ApplicationLoader . applicationContext . getContentResolver ( ) ;
cr . update ( uri , values , null , null ) ;
2015-05-03 13:48:36 +02:00
} ) ;
}
2019-07-18 15:01:39 +02:00
public void addContact ( TLRPC . User user , boolean exception ) {
if ( user = = null ) {
2014-02-04 19:36:55 +01:00
return ;
}
2019-07-18 15:01:39 +02:00
TLRPC . TL_contacts_addContact req = new TLRPC . TL_contacts_addContact ( ) ;
req . id = getMessagesController ( ) . getInputUser ( user ) ;
req . first_name = user . first_name ;
req . last_name = user . last_name ;
req . phone = user . phone ;
req . add_phone_privacy_exception = exception ;
if ( req . phone = = null ) {
req . phone = " " ;
} else if ( req . phone . length ( ) > 0 & & ! req . phone . startsWith ( " + " ) ) {
req . phone = " + " + req . phone ;
}
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
if ( error ! = null ) {
return ;
}
2019-07-18 15:01:39 +02:00
final TLRPC . Updates res = ( TLRPC . Updates ) response ;
getMessagesController ( ) . processUpdates ( res , false ) ;
2019-01-23 18:03:33 +01:00
/ * if ( BuildVars . DEBUG_VERSION ) {
for ( TLRPC . User user : res . users ) {
FileLog . e ( " received user " + user . first_name + " " + user . last_name + " " + user . phone ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
} * /
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < res . users . size ( ) ; a + + ) {
final TLRPC . User u = res . users . get ( a ) ;
2019-07-18 15:01:39 +02:00
if ( u . id ! = user . id ) {
continue ;
}
2019-01-23 18:03:33 +01:00
Utilities . phoneBookQueue . postRunnable ( ( ) - > addContactToPhoneBook ( u , true ) ) ;
TLRPC . TL_contact newContact = new TLRPC . TL_contact ( ) ;
newContact . user_id = u . id ;
ArrayList < TLRPC . TL_contact > arrayList = new ArrayList < > ( ) ;
arrayList . add ( newContact ) ;
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . putContacts ( arrayList , false ) ;
2019-01-23 18:03:33 +01:00
if ( ! TextUtils . isEmpty ( u . phone ) ) {
CharSequence name = formatName ( u . first_name , u . last_name ) ;
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . applyPhoneBookUpdates ( u . phone , " " ) ;
2019-01-23 18:03:33 +01:00
Contact contact = contactsBookSPhones . get ( u . phone ) ;
if ( contact ! = null ) {
int index = contact . shortPhones . indexOf ( u . phone ) ;
if ( index ! = - 1 ) {
contact . phoneDeleted . set ( index , 0 ) ;
2014-02-04 19:36:55 +01:00
}
}
}
2019-01-23 18:03:33 +01:00
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
2019-07-18 15:01:39 +02:00
for ( int a = 0 ; a < res . users . size ( ) ; a + + ) {
TLRPC . User u = res . users . get ( a ) ;
if ( ! u . contact | | contactsDict . get ( u . id ) ! = null ) {
continue ;
2014-02-04 19:36:55 +01:00
}
2019-07-18 15:01:39 +02:00
TLRPC . TL_contact newContact = new TLRPC . TL_contact ( ) ;
newContact . user_id = u . id ;
contacts . add ( newContact ) ;
contactsDict . put ( newContact . user_id , newContact ) ;
2019-01-23 18:03:33 +01:00
}
buildContactsSectionsArrays ( true ) ;
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2019-01-23 18:03:33 +01:00
} ) ;
2015-09-24 22:52:02 +02:00
} , ConnectionsManager . RequestFlagFailOnServerErrors | ConnectionsManager . RequestFlagCanCompress ) ;
2014-02-04 19:36:55 +01:00
}
2021-02-23 12:53:38 +01:00
public void deleteContact ( final ArrayList < TLRPC . User > users , boolean showBulletin ) {
2014-02-04 19:36:55 +01:00
if ( users = = null | | users . isEmpty ( ) ) {
return ;
}
TLRPC . TL_contacts_deleteContacts req = new TLRPC . TL_contacts_deleteContacts ( ) ;
2015-02-26 02:32:51 +01:00
final ArrayList < Integer > uids = new ArrayList < > ( ) ;
2014-02-04 19:36:55 +01:00
for ( TLRPC . User user : users ) {
2019-07-18 15:01:39 +02:00
TLRPC . InputUser inputUser = getMessagesController ( ) . getInputUser ( user ) ;
2014-02-04 19:36:55 +01:00
if ( inputUser = = null ) {
continue ;
}
2019-07-18 15:01:39 +02:00
user . contact = false ;
2014-02-04 19:36:55 +01:00
uids . add ( user . id ) ;
req . id . add ( inputUser ) ;
}
2021-02-23 12:53:38 +01:00
String userName = users . get ( 0 ) . first_name ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
if ( error ! = null ) {
return ;
}
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . processUpdates ( ( TLRPC . Updates ) response , false ) ;
getMessagesStorage ( ) . deleteContacts ( uids ) ;
2019-01-23 18:03:33 +01:00
Utilities . phoneBookQueue . postRunnable ( ( ) - > {
for ( TLRPC . User user : users ) {
deleteContactFromPhoneBook ( user . id ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
} ) ;
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < users . size ( ) ; a + + ) {
TLRPC . User user = users . get ( a ) ;
if ( TextUtils . isEmpty ( user . phone ) ) {
continue ;
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . applyPhoneBookUpdates ( user . phone , " " ) ;
2019-01-23 18:03:33 +01:00
Contact contact = contactsBookSPhones . get ( user . phone ) ;
if ( contact ! = null ) {
int index = contact . shortPhones . indexOf ( user . phone ) ;
if ( index ! = - 1 ) {
contact . phoneDeleted . set ( index , 1 ) ;
2014-02-04 19:36:55 +01:00
}
}
2019-01-23 18:03:33 +01:00
}
2014-02-04 19:36:55 +01:00
2019-01-23 18:03:33 +01:00
AndroidUtilities . runOnUIThread ( ( ) - > {
boolean remove = false ;
for ( TLRPC . User user : users ) {
TLRPC . TL_contact contact = contactsDict . get ( user . id ) ;
if ( contact ! = null ) {
remove = true ;
contacts . remove ( contact ) ;
contactsDict . remove ( user . id ) ;
2014-02-04 19:36:55 +01:00
}
2019-01-23 18:03:33 +01:00
}
if ( remove ) {
buildContactsSectionsArrays ( false ) ;
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . updateInterfaces , MessagesController . UPDATE_MASK_NAME ) ;
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . contactsDidLoad ) ;
2021-02-23 12:53:38 +01:00
if ( showBulletin ) {
NotificationCenter . getGlobalInstance ( ) . postNotificationName ( NotificationCenter . showBulletin , Bulletin . TYPE_ERROR , LocaleController . formatString ( " DeletedFromYourContacts " , R . string . DeletedFromYourContacts , userName ) ) ;
}
2019-01-23 18:03:33 +01:00
} ) ;
2015-09-24 22:52:02 +02:00
} ) ;
2014-02-04 19:36:55 +01:00
}
2014-09-24 04:17:27 +02:00
2019-12-31 14:08:08 +01:00
private void reloadContactsStatuses ( ) {
2014-11-19 11:32:27 +01:00
saveContactsLoadTime ( ) ;
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . clearFullUsers ( ) ;
2018-07-30 04:07:02 +02:00
SharedPreferences preferences = MessagesController . getMainSettings ( currentAccount ) ;
2014-11-17 23:04:31 +01:00
final SharedPreferences . Editor editor = preferences . edit ( ) ;
2020-06-25 17:29:04 +02:00
editor . putBoolean ( " needGetStatuses " , true ) . apply ( ) ;
2014-11-17 23:04:31 +01:00
TLRPC . TL_contacts_getStatuses req = new TLRPC . TL_contacts_getStatuses ( ) ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > {
2019-01-23 18:03:33 +01:00
if ( error = = null ) {
AndroidUtilities . runOnUIThread ( ( ) - > {
editor . remove ( " needGetStatuses " ) . commit ( ) ;
TLRPC . Vector vector = ( TLRPC . Vector ) response ;
if ( ! vector . objects . isEmpty ( ) ) {
ArrayList < TLRPC . User > dbUsersStatus = new ArrayList < > ( ) ;
for ( Object object : vector . objects ) {
TLRPC . User toDbUser = new TLRPC . TL_user ( ) ;
TLRPC . TL_contactStatus status = ( TLRPC . TL_contactStatus ) object ;
if ( status = = null ) {
continue ;
}
if ( status . status instanceof TLRPC . TL_userStatusRecently ) {
status . status . expires = - 100 ;
} else if ( status . status instanceof TLRPC . TL_userStatusLastWeek ) {
status . status . expires = - 101 ;
} else if ( status . status instanceof TLRPC . TL_userStatusLastMonth ) {
status . status . expires = - 102 ;
}
2014-11-19 02:23:46 +01:00
2019-07-18 15:01:39 +02:00
TLRPC . User user = getMessagesController ( ) . getUser ( status . user_id ) ;
2019-01-23 18:03:33 +01:00
if ( user ! = null ) {
user . status = status . status ;
2014-11-17 23:04:31 +01:00
}
2019-01-23 18:03:33 +01:00
toDbUser . status = status . status ;
dbUsersStatus . add ( toDbUser ) ;
2014-11-17 23:04:31 +01:00
}
2019-07-18 15:01:39 +02:00
getMessagesStorage ( ) . updateUsers ( dbUsersStatus , true , true , true ) ;
2019-01-23 18:03:33 +01:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . updateInterfaces , MessagesController . UPDATE_MASK_STATUS ) ;
2019-01-23 18:03:33 +01:00
} ) ;
2014-11-17 23:04:31 +01:00
}
} ) ;
}
2014-11-17 03:44:57 +01:00
public void loadPrivacySettings ( ) {
if ( loadingDeleteInfo = = 0 ) {
loadingDeleteInfo = 1 ;
TLRPC . TL_account_getAccountTTL req = new TLRPC . TL_account_getAccountTTL ( ) ;
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > AndroidUtilities . runOnUIThread ( ( ) - > {
2019-01-23 18:03:33 +01:00
if ( error = = null ) {
TLRPC . TL_accountDaysTTL ttl = ( TLRPC . TL_accountDaysTTL ) response ;
deleteAccountTTL = ttl . days ;
loadingDeleteInfo = 2 ;
} else {
loadingDeleteInfo = 0 ;
2017-03-31 01:58:05 +02:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . privacyRulesUpdated ) ;
2019-01-23 18:03:33 +01:00
} ) ) ;
2017-03-31 01:58:05 +02:00
}
2020-07-26 10:03:38 +02:00
if ( loadingGlobalSettings = = 0 ) {
loadingGlobalSettings = 1 ;
TLRPC . TL_account_getGlobalPrivacySettings req = new TLRPC . TL_account_getGlobalPrivacySettings ( ) ;
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > AndroidUtilities . runOnUIThread ( ( ) - > {
if ( error = = null ) {
globalPrivacySettings = ( TLRPC . TL_globalPrivacySettings ) response ;
loadingGlobalSettings = 2 ;
} else {
loadingGlobalSettings = 0 ;
}
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . privacyRulesUpdated ) ;
} ) ) ;
}
2019-01-23 18:03:33 +01:00
for ( int a = 0 ; a < loadingPrivacyInfo . length ; a + + ) {
if ( loadingPrivacyInfo [ a ] ! = 0 ) {
continue ;
}
loadingPrivacyInfo [ a ] = 1 ;
final int num = a ;
2016-03-06 02:49:31 +01:00
TLRPC . TL_account_getPrivacy req = new TLRPC . TL_account_getPrivacy ( ) ;
2019-01-23 18:03:33 +01:00
switch ( num ) {
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_LASTSEEN :
2019-01-23 18:03:33 +01:00
req . key = new TLRPC . TL_inputPrivacyKeyStatusTimestamp ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_INVITE :
2019-01-23 18:03:33 +01:00
req . key = new TLRPC . TL_inputPrivacyKeyChatInvite ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_CALLS :
2019-01-23 18:03:33 +01:00
req . key = new TLRPC . TL_inputPrivacyKeyPhoneCall ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_P2P :
2019-01-23 18:03:33 +01:00
req . key = new TLRPC . TL_inputPrivacyKeyPhoneP2P ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_PHOTO :
2019-05-14 14:08:05 +02:00
req . key = new TLRPC . TL_inputPrivacyKeyProfilePhoto ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_FORWARDS :
2019-05-14 14:08:05 +02:00
req . key = new TLRPC . TL_inputPrivacyKeyForwards ( ) ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_PHONE :
req . key = new TLRPC . TL_inputPrivacyKeyPhoneNumber ( ) ;
break ;
2019-09-10 12:56:11 +02:00
case PRIVACY_RULES_TYPE_ADDED_BY_PHONE :
default :
req . key = new TLRPC . TL_inputPrivacyKeyAddedByPhone ( ) ;
break ;
2019-01-23 18:03:33 +01:00
}
2019-07-18 15:01:39 +02:00
getConnectionsManager ( ) . sendRequest ( req , ( response , error ) - > AndroidUtilities . runOnUIThread ( ( ) - > {
2019-01-23 18:03:33 +01:00
if ( error = = null ) {
TLRPC . TL_account_privacyRules rules = ( TLRPC . TL_account_privacyRules ) response ;
2019-07-18 15:01:39 +02:00
getMessagesController ( ) . putUsers ( rules . users , false ) ;
getMessagesController ( ) . putChats ( rules . chats , false ) ;
2019-01-23 18:03:33 +01:00
switch ( num ) {
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_LASTSEEN :
lastseenPrivacyRules = rules . rules ;
2019-01-23 18:03:33 +01:00
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_INVITE :
2019-01-23 18:03:33 +01:00
groupPrivacyRules = rules . rules ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_CALLS :
2019-01-23 18:03:33 +01:00
callPrivacyRules = rules . rules ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_P2P :
2019-01-23 18:03:33 +01:00
p2pPrivacyRules = rules . rules ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_PHOTO :
2019-05-14 14:08:05 +02:00
profilePhotoPrivacyRules = rules . rules ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_FORWARDS :
2019-05-14 14:08:05 +02:00
forwardsPrivacyRules = rules . rules ;
break ;
2019-06-04 12:14:50 +02:00
case PRIVACY_RULES_TYPE_PHONE :
phonePrivacyRules = rules . rules ;
break ;
2019-09-10 12:56:11 +02:00
case PRIVACY_RULES_TYPE_ADDED_BY_PHONE :
default :
addedByPhonePrivacyRules = rules . rules ;
break ;
2019-01-23 18:03:33 +01:00
}
loadingPrivacyInfo [ num ] = 2 ;
} else {
loadingPrivacyInfo [ num ] = 0 ;
2016-03-06 02:49:31 +01:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . privacyRulesUpdated ) ;
2019-01-23 18:03:33 +01:00
} ) ) ;
2016-03-06 02:49:31 +01:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . privacyRulesUpdated ) ;
2014-11-17 03:44:57 +01:00
}
public void setDeleteAccountTTL ( int ttl ) {
deleteAccountTTL = ttl ;
}
public int getDeleteAccountTTL ( ) {
return deleteAccountTTL ;
}
public boolean getLoadingDeleteInfo ( ) {
return loadingDeleteInfo ! = 2 ;
}
2020-07-26 10:03:38 +02:00
public boolean getLoadingGlobalSettings ( ) {
return loadingGlobalSettings ! = 2 ;
}
2019-01-23 18:03:33 +01:00
public boolean getLoadingPrivicyInfo ( int type ) {
return loadingPrivacyInfo [ type ] ! = 2 ;
2014-11-17 03:44:57 +01:00
}
2020-07-26 10:03:38 +02:00
public TLRPC . TL_globalPrivacySettings getGlobalPrivacySettings ( ) {
return globalPrivacySettings ;
}
2017-03-31 01:58:05 +02:00
public ArrayList < TLRPC . PrivacyRule > getPrivacyRules ( int type ) {
2019-06-04 12:14:50 +02:00
switch ( type ) {
case PRIVACY_RULES_TYPE_LASTSEEN :
return lastseenPrivacyRules ;
case PRIVACY_RULES_TYPE_INVITE :
return groupPrivacyRules ;
case PRIVACY_RULES_TYPE_CALLS :
return callPrivacyRules ;
case PRIVACY_RULES_TYPE_P2P :
return p2pPrivacyRules ;
case PRIVACY_RULES_TYPE_PHOTO :
return profilePhotoPrivacyRules ;
case PRIVACY_RULES_TYPE_FORWARDS :
return forwardsPrivacyRules ;
case PRIVACY_RULES_TYPE_PHONE :
return phonePrivacyRules ;
2019-09-10 12:56:11 +02:00
case PRIVACY_RULES_TYPE_ADDED_BY_PHONE :
return addedByPhonePrivacyRules ;
2019-06-04 12:14:50 +02:00
}
return null ;
2016-03-06 02:49:31 +01:00
}
2017-03-31 01:58:05 +02:00
public void setPrivacyRules ( ArrayList < TLRPC . PrivacyRule > rules , int type ) {
2019-06-04 12:14:50 +02:00
switch ( type ) {
case PRIVACY_RULES_TYPE_LASTSEEN :
lastseenPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_INVITE :
groupPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_CALLS :
callPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_P2P :
p2pPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_PHOTO :
profilePhotoPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_FORWARDS :
forwardsPrivacyRules = rules ;
break ;
case PRIVACY_RULES_TYPE_PHONE :
phonePrivacyRules = rules ;
break ;
2019-09-10 12:56:11 +02:00
case PRIVACY_RULES_TYPE_ADDED_BY_PHONE :
addedByPhonePrivacyRules = rules ;
break ;
2016-03-06 02:49:31 +01:00
}
2019-07-18 15:01:39 +02:00
getNotificationCenter ( ) . postNotificationName ( NotificationCenter . privacyRulesUpdated ) ;
2014-11-17 23:04:31 +01:00
reloadContactsStatuses ( ) ;
2014-11-17 03:44:57 +01:00
}
2019-01-23 18:03:33 +01:00
public void createOrUpdateConnectionServiceContact ( int id , String firstName , String lastName ) {
2020-12-23 08:48:30 +01:00
if ( ! hasContactsPermission ( ) ) {
2019-01-23 18:03:33 +01:00
return ;
2020-12-23 08:48:30 +01:00
}
2019-01-23 18:03:33 +01:00
try {
ContentResolver resolver = ApplicationLoader . applicationContext . getContentResolver ( ) ;
ArrayList < ContentProviderOperation > ops = new ArrayList < > ( ) ;
final Uri groupsURI = ContactsContract . Groups . CONTENT_URI . buildUpon ( ) . appendQueryParameter ( ContactsContract . CALLER_IS_SYNCADAPTER , " true " ) . build ( ) ;
final Uri rawContactsURI = ContactsContract . RawContacts . CONTENT_URI . buildUpon ( ) . appendQueryParameter ( ContactsContract . CALLER_IS_SYNCADAPTER , " true " ) . build ( ) ;
// 1. Check if we already have the invisible group/label and create it if we don't
Cursor cursor = resolver . query ( groupsURI , new String [ ] { ContactsContract . Groups . _ID } ,
ContactsContract . Groups . TITLE + " =? AND " + ContactsContract . Groups . ACCOUNT_TYPE + " =? AND " + ContactsContract . Groups . ACCOUNT_NAME + " =? " ,
new String [ ] { " TelegramConnectionService " , systemAccount . type , systemAccount . name } , null ) ;
int groupID ;
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
groupID = cursor . getInt ( 0 ) ;
/ * ops . add ( ContentProviderOperation . newUpdate ( groupsURI )
. withSelection ( ContactsContract . Groups . _ID + " =? " , new String [ ] { groupID + " " } )
. withValue ( ContactsContract . Groups . DELETED , 0 )
. build ( ) ) ; * /
} else {
ContentValues values = new ContentValues ( ) ;
values . put ( ContactsContract . Groups . ACCOUNT_TYPE , systemAccount . type ) ;
values . put ( ContactsContract . Groups . ACCOUNT_NAME , systemAccount . name ) ;
values . put ( ContactsContract . Groups . GROUP_VISIBLE , 0 ) ;
values . put ( ContactsContract . Groups . GROUP_IS_READ_ONLY , 1 ) ;
values . put ( ContactsContract . Groups . TITLE , " TelegramConnectionService " ) ;
Uri res = resolver . insert ( groupsURI , values ) ;
groupID = Integer . parseInt ( res . getLastPathSegment ( ) ) ;
}
if ( cursor ! = null )
cursor . close ( ) ;
// 2. Find the existing ConnectionService contact and update it or create it
cursor = resolver . query ( ContactsContract . Data . CONTENT_URI , new String [ ] { ContactsContract . Data . RAW_CONTACT_ID } ,
ContactsContract . Data . MIMETYPE + " =? AND " + ContactsContract . CommonDataKinds . GroupMembership . GROUP_ROW_ID + " =? " ,
new String [ ] { ContactsContract . CommonDataKinds . GroupMembership . CONTENT_ITEM_TYPE , groupID + " " } , null ) ;
int backRef = ops . size ( ) ;
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
int contactID = cursor . getInt ( 0 ) ;
ops . add ( ContentProviderOperation . newUpdate ( rawContactsURI )
. withSelection ( ContactsContract . RawContacts . _ID + " =? " , new String [ ] { contactID + " " } )
. withValue ( ContactsContract . RawContacts . DELETED , 0 )
. build ( ) ) ;
ops . add ( ContentProviderOperation . newUpdate ( ContactsContract . Data . CONTENT_URI )
. withSelection ( ContactsContract . Data . RAW_CONTACT_ID + " =? AND " + ContactsContract . Data . MIMETYPE + " =? " ,
new String [ ] { contactID + " " , ContactsContract . CommonDataKinds . Phone . CONTENT_ITEM_TYPE } )
. withValue ( ContactsContract . CommonDataKinds . Phone . NUMBER , " +99084 " + id )
. build ( ) ) ;
ops . add ( ContentProviderOperation . newUpdate ( ContactsContract . Data . CONTENT_URI )
. withSelection ( ContactsContract . Data . RAW_CONTACT_ID + " =? AND " + ContactsContract . Data . MIMETYPE + " =? " ,
new String [ ] { contactID + " " , ContactsContract . CommonDataKinds . StructuredName . CONTENT_ITEM_TYPE } )
. withValue ( ContactsContract . CommonDataKinds . StructuredName . GIVEN_NAME , firstName )
. withValue ( ContactsContract . CommonDataKinds . StructuredName . FAMILY_NAME , lastName )
. build ( ) ) ;
} else {
ops . add ( ContentProviderOperation . newInsert ( rawContactsURI )
. withValue ( ContactsContract . RawContacts . ACCOUNT_TYPE , systemAccount . type )
. withValue ( ContactsContract . RawContacts . ACCOUNT_NAME , systemAccount . name )
. withValue ( ContactsContract . RawContacts . RAW_CONTACT_IS_READ_ONLY , 1 )
. withValue ( ContactsContract . RawContacts . AGGREGATION_MODE , ContactsContract . RawContacts . AGGREGATION_MODE_DISABLED )
. build ( ) ) ;
ops . add ( ContentProviderOperation . newInsert ( ContactsContract . Data . CONTENT_URI )
. withValueBackReference ( ContactsContract . Data . RAW_CONTACT_ID , backRef )
. withValue ( ContactsContract . Data . MIMETYPE , ContactsContract . CommonDataKinds . StructuredName . CONTENT_ITEM_TYPE )
. withValue ( ContactsContract . CommonDataKinds . StructuredName . GIVEN_NAME , firstName )
. withValue ( ContactsContract . CommonDataKinds . StructuredName . FAMILY_NAME , lastName )
. build ( ) ) ;
// The prefix +990 isn't assigned to anything, so our "phone number" is going to be +990-TG-UserID
ops . add ( ContentProviderOperation . newInsert ( ContactsContract . Data . CONTENT_URI )
. withValueBackReference ( ContactsContract . Data . RAW_CONTACT_ID , backRef )
. withValue ( ContactsContract . Data . MIMETYPE , ContactsContract . CommonDataKinds . Phone . CONTENT_ITEM_TYPE )
. withValue ( ContactsContract . CommonDataKinds . Phone . NUMBER , " +99084 " + id )
. build ( ) ) ;
ops . add ( ContentProviderOperation . newInsert ( ContactsContract . Data . CONTENT_URI )
. withValueBackReference ( ContactsContract . Data . RAW_CONTACT_ID , backRef )
. withValue ( ContactsContract . Data . MIMETYPE , ContactsContract . CommonDataKinds . GroupMembership . CONTENT_ITEM_TYPE )
. withValue ( ContactsContract . CommonDataKinds . GroupMembership . GROUP_ROW_ID , groupID )
. build ( ) ) ;
}
if ( cursor ! = null )
cursor . close ( ) ;
resolver . applyBatch ( ContactsContract . AUTHORITY , ops ) ;
} catch ( Exception x ) {
FileLog . e ( x ) ;
}
}
public void deleteConnectionServiceContact ( ) {
if ( ! hasContactsPermission ( ) )
return ;
try {
ContentResolver resolver = ApplicationLoader . applicationContext . getContentResolver ( ) ;
Cursor cursor = resolver . query ( ContactsContract . Groups . CONTENT_URI , new String [ ] { ContactsContract . Groups . _ID } ,
ContactsContract . Groups . TITLE + " =? AND " + ContactsContract . Groups . ACCOUNT_TYPE + " =? AND " + ContactsContract . Groups . ACCOUNT_NAME + " =? " ,
new String [ ] { " TelegramConnectionService " , systemAccount . type , systemAccount . name } , null ) ;
int groupID ;
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
groupID = cursor . getInt ( 0 ) ;
cursor . close ( ) ;
} else {
if ( cursor ! = null )
cursor . close ( ) ;
return ;
}
cursor = resolver . query ( ContactsContract . Data . CONTENT_URI , new String [ ] { ContactsContract . Data . RAW_CONTACT_ID } ,
ContactsContract . Data . MIMETYPE + " =? AND " + ContactsContract . CommonDataKinds . GroupMembership . GROUP_ROW_ID + " =? " ,
new String [ ] { ContactsContract . CommonDataKinds . GroupMembership . CONTENT_ITEM_TYPE , groupID + " " } , null ) ;
int contactID ;
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
contactID = cursor . getInt ( 0 ) ;
cursor . close ( ) ;
} else {
if ( cursor ! = null )
cursor . close ( ) ;
return ;
}
resolver . delete ( ContactsContract . RawContacts . CONTENT_URI , ContactsContract . RawContacts . _ID + " =? " , new String [ ] { contactID + " " } ) ;
//resolver.delete(ContactsContract.Groups.CONTENT_URI, ContactsContract.Groups._ID+"=?", new String[]{groupID+""});
} catch ( Exception x ) {
FileLog . e ( x ) ;
}
}
2014-09-24 04:17:27 +02:00
public static String formatName ( String firstName , String lastName ) {
2020-09-30 15:48:47 +02:00
return formatName ( firstName , lastName , 0 ) ;
}
public static String formatName ( String firstName , String lastName , int maxLength ) {
2015-05-03 13:48:36 +02:00
/ * if ( ( firstName = = null | | firstName . length ( ) = = 0 ) & & ( lastName = = null | | lastName . length ( ) = = 0 ) ) {
return LocaleController . getString ( " HiddenName " , R . string . HiddenName ) ;
} * /
if ( firstName ! = null ) {
firstName = firstName . trim ( ) ;
}
if ( lastName ! = null ) {
lastName = lastName . trim ( ) ;
}
StringBuilder result = new StringBuilder ( ( firstName ! = null ? firstName . length ( ) : 0 ) + ( lastName ! = null ? lastName . length ( ) : 0 ) + 1 ) ;
2020-05-28 09:29:33 +02:00
if ( NekoConfig . nameOrder = = 1 ) {
2015-05-03 13:48:36 +02:00
if ( firstName ! = null & & firstName . length ( ) > 0 ) {
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & firstName . length ( ) > maxLength + 2 ) {
return firstName . substring ( 0 , maxLength ) ;
}
2015-05-03 13:48:36 +02:00
result . append ( firstName ) ;
if ( lastName ! = null & & lastName . length ( ) > 0 ) {
result . append ( " " ) ;
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & result . length ( ) + lastName . length ( ) > maxLength ) {
result . append ( lastName . charAt ( 0 ) ) ;
} else {
result . append ( lastName ) ;
}
2015-05-03 13:48:36 +02:00
}
} else if ( lastName ! = null & & lastName . length ( ) > 0 ) {
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & lastName . length ( ) > maxLength + 2 ) {
return lastName . substring ( 0 , maxLength ) ;
}
2015-05-03 13:48:36 +02:00
result . append ( lastName ) ;
2014-09-24 04:17:27 +02:00
}
} else {
2015-05-03 13:48:36 +02:00
if ( lastName ! = null & & lastName . length ( ) > 0 ) {
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & lastName . length ( ) > maxLength + 2 ) {
return lastName . substring ( 0 , maxLength ) ;
}
2015-05-03 13:48:36 +02:00
result . append ( lastName ) ;
if ( firstName ! = null & & firstName . length ( ) > 0 ) {
result . append ( " " ) ;
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & result . length ( ) + firstName . length ( ) > maxLength ) {
result . append ( firstName . charAt ( 0 ) ) ;
} else {
result . append ( firstName ) ;
}
2015-05-03 13:48:36 +02:00
}
} else if ( firstName ! = null & & firstName . length ( ) > 0 ) {
2020-09-30 15:48:47 +02:00
if ( maxLength > 0 & & firstName . length ( ) > maxLength + 2 ) {
return firstName . substring ( 0 , maxLength ) ;
}
2015-05-03 13:48:36 +02:00
result . append ( firstName ) ;
2014-09-24 04:17:27 +02:00
}
}
2015-05-03 13:48:36 +02:00
return result . toString ( ) ;
2014-09-24 04:17:27 +02:00
}
2014-02-04 19:36:55 +01:00
}