36
36
public class ContactsCache
38
private HashMap< String, Long > _contacts;
39
* Information that can be used to identify a contact within the cache
41
static public class CacheIdentifier
44
NONE, NAME, ORGANISATION, PRIMARY_NUMBER, PRIMARY_EMAIL }
47
private String _detail;
49
protected CacheIdentifier()
54
protected CacheIdentifier( Type type, String detail )
65
public String getDetail()
71
// mappings of contact names, organisations and primary numbers to ids
72
private HashMap< String, Long > _contactsByName;
73
private HashMap< String, Long > _contactsByOrg;
74
private HashMap< String, Long > _contactsByNumber;
75
private HashMap< String, Long > _contactsByEmail;
77
// mapping of contact ids to sets of associated data
40
78
private HashMap< Long, HashSet< String > > _contactNumbers;
41
79
private HashMap< Long, HashSet< String > > _contactEmails;
42
80
private HashMap< Long, HashSet< String > > _contactAddresses;
44
public boolean exists( String name )
46
return _contacts.containsKey( name );
49
public Long getId( String name )
51
return _contacts.get( name );
54
public void remove( String name )
56
_contacts.remove( name );
59
public void put( Long id, String name )
61
_contacts.put( name, id );
64
public boolean hasNumber( Long id, String number )
66
HashSet< String > cache = _contactNumbers.get( id );
67
return cache != null && cache.contains( number );
70
public void addNumber( Long id, String number )
72
HashSet< String > cache = _contactNumbers.get( id );
74
cache = new HashSet< String >();
75
_contactNumbers.put( id, cache );
80
public boolean hasEmail( Long id, String email )
82
HashSet< String > cache = _contactEmails.get( id );
83
return cache != null && cache.contains( email );
86
public void addEmail( Long id, String email )
88
HashSet< String > cache = _contactEmails.get( id );
90
cache = new HashSet< String >();
91
_contactEmails.put( id, cache );
96
public boolean hasAddress( Long id, String address )
98
HashSet< String > cache = _contactAddresses.get( id );
99
return cache != null && cache.contains( address );
102
public void addAddress( Long id, String address )
104
HashSet< String > cache = _contactAddresses.get( id );
105
if( cache == null ) {
106
cache = new HashSet< String >();
107
_contactAddresses.put( id, cache );
109
cache.add( address );
81
private HashMap< Long, HashSet< String > > _contactOrganisations;
83
public static CacheIdentifier createIdentifier(
84
Importer.ContactData contact )
86
if( contact.hasName() ) {
87
String name = normaliseName( contact.getName() );
89
return new CacheIdentifier(
90
CacheIdentifier.Type.NAME, name );
93
if( contact.hasPrimaryOrganisation() ) {
94
String organisation = normaliseOrganisation(
95
contact.getPrimaryOrganisation() );
96
if( organisation != null )
97
return new CacheIdentifier(
98
CacheIdentifier.Type.ORGANISATION, organisation );
101
if( contact.hasPrimaryNumber() ) {
102
String number = normalisePhoneNumber( contact.getPrimaryNumber() );
104
return new CacheIdentifier(
105
CacheIdentifier.Type.PRIMARY_NUMBER, number );
108
if( contact.hasPrimaryEmail() ) {
109
String email = normaliseEmailAddress( contact.getPrimaryEmail() );
111
return new CacheIdentifier(
112
CacheIdentifier.Type.PRIMARY_EMAIL, email );
118
public boolean canLookup( CacheIdentifier identifier )
120
return lookup( identifier ) != null;
123
public Long lookup( CacheIdentifier identifier )
125
switch( identifier.getType() )
128
return _contactsByName.get( identifier.getDetail() );
130
return _contactsByOrg.get( identifier.getDetail() );
132
return _contactsByNumber.get( identifier.getDetail() );
134
return _contactsByEmail.get( identifier.getDetail() );
139
public Long removeLookup( CacheIdentifier identifier )
141
switch( identifier.getType() )
144
return _contactsByName.remove( identifier.getDetail() );
146
return _contactsByOrg.remove( identifier.getDetail() );
148
return _contactsByNumber.remove( identifier.getDetail() );
150
return _contactsByEmail.remove( identifier.getDetail() );
155
public void addLookup( CacheIdentifier identifier, Long id )
157
switch( identifier.getType() )
160
_contactsByName.put( identifier.getDetail(), id );
163
_contactsByOrg.put( identifier.getDetail(), id );
166
_contactsByNumber.put( identifier.getDetail(), id );
169
_contactsByEmail.put( identifier.getDetail(), id );
174
public void removeAssociatedData( Long id )
176
_contactNumbers.remove( id );
177
_contactEmails.remove( id );
178
_contactAddresses.remove( id );
179
_contactOrganisations.remove( id );
182
public boolean hasAssociatedNumber( Long id, String number )
184
number = normalisePhoneNumber( number );
185
if( number == null ) return false;
187
HashSet< String > set = _contactNumbers.get( id );
188
return set != null && set.contains( number );
191
public void addAssociatedNumber( Long id, String number )
193
number = normalisePhoneNumber( number );
194
if( number == null ) return;
196
HashSet< String > set = _contactNumbers.get( id );
198
set = new HashSet< String >();
199
_contactNumbers.put( id, set );
201
set.add( normalisePhoneNumber( number ) );
204
public boolean hasAssociatedEmail( Long id, String email )
206
email = normaliseEmailAddress( email );
207
if( email == null ) return false;
209
HashSet< String > set = _contactEmails.get( id );
210
return set != null && set.contains( normaliseEmailAddress( email ) );
213
public void addAssociatedEmail( Long id, String email )
215
email = normaliseEmailAddress( email );
216
if( email == null ) return;
218
HashSet< String > set = _contactEmails.get( id );
220
set = new HashSet< String >();
221
_contactEmails.put( id, set );
223
set.add( normaliseEmailAddress( email ) );
226
public boolean hasAssociatedAddress( Long id, String address )
228
address = normaliseAddress( address );
229
if( address == null ) return false;
231
HashSet< String > set = _contactAddresses.get( id );
232
return set != null && set.contains( normaliseAddress( address ) );
235
public void addAssociatedAddress( Long id, String address )
237
address = normaliseAddress( address );
238
if( address == null ) return;
240
HashSet< String > set = _contactAddresses.get( id );
242
set = new HashSet< String >();
243
_contactAddresses.put( id, set );
245
set.add( normaliseAddress( address ) );
248
public boolean hasAssociatedOrganisation( Long id, String organisation )
250
organisation = normaliseOrganisation( organisation );
251
if( organisation == null ) return false;
253
HashSet< String > set = _contactOrganisations.get( id );
254
return set != null && set.contains(
255
normaliseOrganisation( organisation ) );
258
public void addAssociatedOrganisation( Long id, String organisation )
260
organisation = normaliseOrganisation( organisation );
261
if( organisation == null ) return;
263
HashSet< String > set = _contactOrganisations.get( id );
265
set = new HashSet< String >();
266
_contactOrganisations.put( id, set );
268
set.add( normaliseOrganisation( organisation ) );
112
271
public void buildCache( Activity activity )
113
272
throws AbortImportException
118
// init contacts caches
119
_contacts = new HashMap< String, Long >();
277
_contactsByName = new HashMap< String, Long >();
278
_contactsByOrg = new HashMap< String, Long >();
279
_contactsByNumber = new HashMap< String, Long >();
280
_contactsByEmail = new HashMap< String, Long >();
282
// init associated data cache
120
283
_contactNumbers = new HashMap< Long, HashSet< String > >();
121
284
_contactEmails = new HashMap< Long, HashSet< String > >();
122
285
_contactAddresses = new HashMap< Long, HashSet< String > >();
124
// query and store map of contact names to ids
125
cols = new String[] { Contacts.People._ID, Contacts.People.NAME };
286
_contactOrganisations = new HashMap< Long, HashSet< String > >();
288
// set of contact ids that we have not yet added
289
HashSet< Long > unadded = new HashSet< Long >();
126
292
cur = activity.managedQuery( Contacts.People.CONTENT_URI,
127
cols, null, null, null);
128
if( cur.moveToFirst() ) {
129
int idCol = cur.getColumnIndex( Contacts.People._ID );
130
int nameCol = cur.getColumnIndex( Contacts.People.NAME );
132
_contacts.put( cur.getString( nameCol ), cur.getLong( idCol ) );
133
} while( cur.moveToNext() );
136
// query and store map of contact ids to sets of phone numbers
137
cols = new String[] { Contacts.Phones.PERSON_ID,
138
Contacts.Phones.NUMBER };
295
Contacts.People.NAME,
296
}, null, null, null );
297
while( cur.moveToNext() ) {
298
Long id = cur.getLong(
299
cur.getColumnIndex( Contacts.People._ID ) );
300
String name = normaliseName( cur.getString(
301
cur.getColumnIndex( Contacts.People.NAME ) ) );
304
// if we can, add a lookup for the contact id by name
305
if( name.length() > 0 ) {
306
addLookup( new CacheIdentifier(
307
CacheIdentifier.Type.NAME, name ), id );
312
// record that a lookup for this contact's id still needs to be
313
// added by some other means
317
// get contact organisations, primary ones first
318
cur = activity.managedQuery( Contacts.Organizations.CONTENT_URI,
320
Contacts.Phones.PERSON_ID,
321
Contacts.Organizations.COMPANY,
322
}, null, null, Contacts.Organizations.ISPRIMARY + " DESC" );
323
while( cur.moveToNext() ) {
324
Long id = cur.getLong( cur.getColumnIndex(
325
Contacts.Organizations.PERSON_ID ) );
326
String organisation = normaliseOrganisation( cur.getString(
327
cur.getColumnIndex( Contacts.Organizations.COMPANY ) ) );
328
if( organisation != null )
330
// if this is an organisation name for a contact for whom we
331
// have not added a lookup, add a lookup for the contact id
333
if( unadded.contains( id ) ) {
334
addLookup( new CacheIdentifier(
335
CacheIdentifier.Type.ORGANISATION, organisation ), id );
336
unadded.remove( id );
339
// add associated data
340
addAssociatedOrganisation( id, organisation );
344
// get all phone numbers, primary ones first
139
345
cur = activity.managedQuery( Contacts.Phones.CONTENT_URI,
140
cols, null, null, null);
141
if( cur.moveToFirst() ) {
142
int personIdCol = cur.getColumnIndex( Contacts.Phones.PERSON_ID );
143
int numberCol = cur.getColumnIndex( Contacts.Phones.NUMBER );
145
Long id = cur.getLong( personIdCol );
146
String number = Importer.sanitisePhoneNumber(
147
cur.getString( numberCol ) );
148
if( number != null ) {
149
HashSet< String > numbers = _contactNumbers.get( id );
150
if( numbers == null ) {
151
numbers = new HashSet< String >();
152
_contactNumbers.put( id, numbers );
154
numbers.add( number );
156
} while( cur.moveToNext() );
159
// query and store map of contact ids to sets of email addresses
160
cols = new String[] { Contacts.ContactMethods.PERSON_ID,
161
Contacts.ContactMethods.DATA };
162
cur = activity.managedQuery( Contacts.ContactMethods.CONTENT_URI,
163
cols, Contacts.ContactMethods.KIND + " = ?",
164
new String[] { "" + Contacts.KIND_EMAIL }, null );
165
if( cur.moveToFirst() ) {
166
int personIdCol = cur.getColumnIndex(
167
Contacts.ContactMethods.PERSON_ID );
168
int addressCol = cur.getColumnIndex(
169
Contacts.ContactMethods.DATA );
171
Long id = cur.getLong( personIdCol );
172
String address = Importer.sanitiseEmailAddress(
173
cur.getString( addressCol ) );
174
if( address != null ) {
175
HashSet< String > addresses = _contactEmails.get( id );
176
if( addresses == null ) {
177
addresses = new HashSet< String >();
178
_contactEmails.put( id, addresses );
180
addresses.add( address );
182
} while( cur.moveToNext() );
185
// query and store map of contact ids to sets of postal addresses
186
cols = new String[] { Contacts.ContactMethods.PERSON_ID,
187
Contacts.ContactMethods.DATA };
188
cur = activity.managedQuery( Contacts.ContactMethods.CONTENT_URI,
189
cols, Contacts.ContactMethods.KIND + " = ?",
190
new String[] { "" + Contacts.KIND_POSTAL }, null );
191
if( cur.moveToFirst() ) {
192
int personIdCol = cur.getColumnIndex(
193
Contacts.ContactMethods.PERSON_ID );
194
int addressCol = cur.getColumnIndex(
195
Contacts.ContactMethods.DATA );
197
Long id = cur.getLong( personIdCol );
198
String address = cur.getString( addressCol );
199
if( address != null ) {
200
HashSet< String > addresses = _contactAddresses.get( id );
201
if( addresses == null ) {
202
addresses = new HashSet< String >();
203
_contactAddresses.put( id, addresses );
205
addresses.add( address );
207
} while( cur.moveToNext() );
347
Contacts.Phones.PERSON_ID,
348
Contacts.Phones.NUMBER,
349
}, null, null, Contacts.Phones.ISPRIMARY + " DESC" );
350
while( cur.moveToNext() ) {
351
Long id = cur.getLong(
352
cur.getColumnIndex( Contacts.Phones.PERSON_ID ) );
353
String number = normalisePhoneNumber( cur.getString(
354
cur.getColumnIndex( Contacts.Phones.NUMBER ) ) );
357
// if this is a number for a contact for whom we have not
358
// added a lookup, add a lookup for the contact id by phone
360
if( unadded.contains( id ) ) {
361
addLookup( new CacheIdentifier(
362
CacheIdentifier.Type.PRIMARY_NUMBER, number ), id );
363
unadded.remove( id );
366
// add associated data
367
addAssociatedNumber( id, number );
371
// now get all email addresses, primary ones first, and postal addresses
372
cur = activity.managedQuery( Contacts.ContactMethods.CONTENT_URI,
374
Contacts.ContactMethods.PERSON_ID,
375
Contacts.ContactMethods.DATA,
376
Contacts.ContactMethods.KIND,
377
}, Contacts.ContactMethods.KIND + " IN( ?, ? )", new String[] {
378
"" + Contacts.KIND_EMAIL,
379
"" + Contacts.KIND_POSTAL,
380
}, Contacts.ContactMethods.ISPRIMARY + " DESC" );
381
while( cur.moveToNext() ) {
382
Long id = cur.getLong(
383
cur.getColumnIndex( Contacts.ContactMethods.PERSON_ID ) );
384
int kind = cur.getInt(
385
cur.getColumnIndex( Contacts.ContactMethods.KIND ) );
386
if( kind == Contacts.KIND_EMAIL )
388
String email = normaliseEmailAddress( cur.getString(
389
cur.getColumnIndex( Contacts.ContactMethods.DATA ) ) );
392
// if this is an email address for a contact for whom we
393
// have not added a lookup, add a lookup for the contact
394
// id by email address
395
if( unadded.contains( id ) ) {
396
addLookup( new CacheIdentifier(
397
CacheIdentifier.Type.PRIMARY_EMAIL, email ), id );
398
unadded.remove( id );
401
// add associated data
402
addAssociatedEmail( id, email );
405
else if( kind == Contacts.KIND_POSTAL )
407
String address = normaliseAddress( cur.getString(
408
cur.getColumnIndex( Contacts.ContactMethods.DATA ) ) );
409
if( address != null )
411
// add associated data
412
addAssociatedAddress( id, address );
418
static private String normaliseName( String name )
420
if( name == null ) return null;
422
return name.length() > 0? name : null;
425
static private String normalisePhoneNumber( String number )
427
if( number == null ) return null;
428
number = number.trim().replaceAll( "[-\\(\\) ]", "" );
429
return number.length() > 0? number : null;
432
static private String normaliseEmailAddress( String email )
434
if( email == null ) return null;
435
email = email.trim().toLowerCase();
436
return email.length() > 0? email : null;
439
static private String normaliseOrganisation( String organisation )
441
if( organisation == null ) return null;
442
organisation = organisation.trim();
443
return organisation.length() > 0? organisation : null;
446
static private String normaliseAddress( String address )
448
if( address == null ) return null;
449
address = address.trim();
450
return address.length() > 0? address : null;