21
21
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24
package org.waxworlds.edam.importcontacts;
24
package am.ed.importcontacts;
26
26
import java.util.HashMap;
27
27
import java.util.HashSet;
29
import org.waxworlds.edam.importcontacts.Importer.AbortImportException;
31
import android.app.Activity;
32
import android.database.Cursor;
33
import android.provider.Contacts;
28
import java.util.Locale;
36
30
public class ContactsCache
38
private HashMap< String, Long > _contacts;
40
private HashMap< Long, HashSet< String > > _contactNumbers;
41
private HashMap< Long, HashSet< String > > _contactEmails;
42
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 );
112
public void buildCache( Activity activity )
113
throws AbortImportException
118
// init contacts caches
119
_contacts = new HashMap< String, Long >();
120
_contactNumbers = new HashMap< Long, HashSet< String > >();
121
_contactEmails = new HashMap< Long, HashSet< String > >();
122
_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 };
126
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 };
139
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() );
33
* A thing that can be used to identify (or lookup) a contact within the
34
* contacts cache. It is not a reference to a cache entry and may not
35
* identify an existing contact in the cache.
37
public static class CacheIdentifier
39
public enum Type { NAME, ORGANISATION, PRIMARY_NUMBER, PRIMARY_EMAIL }
42
private String _detail;
45
* Obtain a cache identifier. This routine is designed to be as robust
46
* as possible (in terms of bad or null detail values), and to return
47
* null when a cache identifier can not be created.
49
* @param type the detail type
50
* @param detail the detail
51
* @return the cache identifier, or null
53
public static CacheIdentifier factory( Type type, String detail )
57
case NAME: detail = normaliseName( detail ); break;
58
case ORGANISATION: detail = normaliseOrganisation( detail ); break;
59
case PRIMARY_NUMBER: detail = normalisePhoneNumber( detail ); break;
60
case PRIMARY_EMAIL: detail = normaliseEmailAddress( detail ); break;
63
if( detail == null ) return null;
64
return new CacheIdentifier( type, detail );
68
* Obtain a cache identifier from contact data. This routine is
69
* designed to be as robust as possible and may return null when a cache
70
* identifier can not be created.
72
* @param contact the contact data
73
* @return the cache identifier, or null
75
public static CacheIdentifier factory( Importer.ContactData contact )
77
CacheIdentifier identifier = null;
79
if( contact.hasName() )
80
identifier = factory( CacheIdentifier.Type.NAME,
82
if( identifier != null ) return identifier;
84
if( contact.hasPrimaryOrganisation() )
85
identifier = factory( CacheIdentifier.Type.ORGANISATION,
86
contact.getPrimaryOrganisation() );
87
if( identifier != null ) return identifier;
89
if( contact.hasPrimaryNumber() )
90
identifier = factory( CacheIdentifier.Type.PRIMARY_NUMBER,
91
contact.getPrimaryNumber() );
92
if( identifier != null ) return identifier;
94
if( contact.hasPrimaryEmail() )
95
identifier = factory( CacheIdentifier.Type.PRIMARY_EMAIL,
96
contact.getPrimaryEmail() );
97
if( identifier != null ) return identifier;
102
protected CacheIdentifier( Type type, String detail )
108
public Type getType()
113
public String getDetail()
119
// mappings of contact names, organisations and primary numbers to ids
120
private HashMap< String, Long > _contactsByName
121
= new HashMap< String, Long >();
122
private HashMap< String, Long > _contactsByOrg
123
= new HashMap< String, Long >();
124
private HashMap< String, Long > _contactsByNumber
125
= new HashMap< String, Long >();
126
private HashMap< String, Long > _contactsByEmail
127
= new HashMap< String, Long >();
129
// mapping of contact ids to sets of associated data
130
private HashMap< Long, HashSet< String > > _contactNumbers
131
= new HashMap< Long, HashSet< String > >();
132
private HashMap< Long, HashSet< String > > _contactEmails
133
= new HashMap< Long, HashSet< String > >();
134
private HashMap< Long, HashSet< String > > _contactAddresses
135
= new HashMap< Long, HashSet< String > >();
136
private HashMap< Long, HashSet< String > > _contactOrganisations
137
= new HashMap< Long, HashSet< String > >();
138
private HashMap< Long, HashSet< String > > _contactNotes
139
= new HashMap< Long, HashSet< String > >();
140
private HashMap< Long, String > _contactBirthdays
141
= new HashMap< Long, String >();
143
public boolean canLookup( CacheIdentifier identifier )
145
return lookup( identifier ) != null;
149
* Retrieve the contact id of a contact identified by the specified cache
150
* identifier, if it exists.
152
* @param identifier the cache identifier
153
* @return a contact id, or null
155
public Long lookup( CacheIdentifier identifier )
157
switch( identifier.getType() )
160
return _contactsByName.get( identifier.getDetail() );
162
return _contactsByOrg.get( identifier.getDetail() );
164
return _contactsByNumber.get( identifier.getDetail() );
166
return _contactsByEmail.get( identifier.getDetail() );
172
* Remove any cache entry that is identified by the cache identifier.
174
* @param identifier the cache identifier
175
* @return the contact id of the contact that was removed, or null
177
public Long removeLookup( CacheIdentifier identifier )
179
switch( identifier.getType() )
182
return _contactsByName.remove( identifier.getDetail() );
184
return _contactsByOrg.remove( identifier.getDetail() );
186
return _contactsByNumber.remove( identifier.getDetail() );
188
return _contactsByEmail.remove( identifier.getDetail() );
194
* Add a lookup from a contact identifier to a contact id to the cache.
196
* @param identifier the cache identifier
197
* @param id teh contact id
199
public void addLookup( CacheIdentifier identifier, Long id )
201
switch( identifier.getType() )
204
_contactsByName.put( identifier.getDetail(), id );
207
_contactsByOrg.put( identifier.getDetail(), id );
210
_contactsByNumber.put( identifier.getDetail(), id );
213
_contactsByEmail.put( identifier.getDetail(), id );
219
* Remove any data that is associated with an contact id.
223
public void removeAssociatedData( Long id )
225
_contactNumbers.remove( id );
226
_contactEmails.remove( id );
227
_contactAddresses.remove( id );
228
_contactOrganisations.remove( id );
229
_contactNotes.remove( id );
232
public boolean hasAssociatedNumber( Long id, String number )
234
number = normalisePhoneNumber( number );
235
if( number == null ) return false;
237
HashSet< String > set = _contactNumbers.get( id );
238
return set != null && set.contains( number );
241
public void addAssociatedNumber( Long id, String number )
243
number = normalisePhoneNumber( number );
244
if( number == null ) return;
246
HashSet< String > set = _contactNumbers.get( id );
248
set = new HashSet< String >();
249
_contactNumbers.put( id, set );
254
public boolean hasAssociatedEmail( Long id, String email )
256
email = normaliseEmailAddress( email );
257
if( email == null ) return false;
259
HashSet< String > set = _contactEmails.get( id );
260
return set != null && set.contains( email );
263
public void addAssociatedEmail( Long id, String email )
265
email = normaliseEmailAddress( email );
266
if( email == null ) return;
268
HashSet< String > set = _contactEmails.get( id );
270
set = new HashSet< String >();
271
_contactEmails.put( id, set );
276
public boolean hasAssociatedAddress( Long id, String address )
278
address = normaliseAddress( address );
279
if( address == null ) return false;
281
HashSet< String > set = _contactAddresses.get( id );
282
return set != null && set.contains( address );
285
public void addAssociatedAddress( Long id, String address )
287
address = normaliseAddress( address );
288
if( address == null ) return;
290
HashSet< String > set = _contactAddresses.get( id );
292
set = new HashSet< String >();
293
_contactAddresses.put( id, set );
298
public boolean hasAssociatedOrganisation( Long id, String organisation )
300
organisation = normaliseOrganisation( organisation );
301
if( organisation == null ) return false;
303
HashSet< String > set = _contactOrganisations.get( id );
304
return set != null && set.contains( organisation );
307
public void addAssociatedOrganisation( Long id, String organisation )
309
organisation = normaliseOrganisation( organisation );
310
if( organisation == null ) return;
312
HashSet< String > set = _contactOrganisations.get( id );
314
set = new HashSet< String >();
315
_contactOrganisations.put( id, set );
317
set.add( organisation );
320
public boolean hasAssociatedNote( Long id, String note )
322
note = normaliseNote( note );
323
if( note == null ) return false;
325
HashSet< String > set = _contactNotes.get( id );
326
return set != null && set.contains( note );
329
public void addAssociatedNote( Long id, String note )
331
note = normaliseNote( note );
332
if( note == null ) return;
334
HashSet< String > set = _contactNotes.get( id );
336
set = new HashSet< String >();
337
_contactNotes.put( id, set );
342
public boolean hasAssociatedBirthday( Long id, String birthday )
344
birthday = normaliseBirthday( birthday );
345
if( birthday == null ) return false;
347
String found = _contactBirthdays.get( id );
348
return found != null && found.equalsIgnoreCase( birthday );
351
public void addAssociatedBirthday( Long id, String birthday )
353
birthday = normaliseBirthday( birthday );
354
if( birthday == null ) return;
356
_contactBirthdays.put( id, birthday );
359
static public String normaliseName( String name )
361
if( name == null ) return null;
363
return name.length() > 0? name : null;
366
static public String normalisePhoneNumber( String number )
368
if( number == null ) return null;
369
number = number.trim().replaceAll( "[-\\(\\) ]", "" );
370
return number.length() > 0? number : null;
373
static public String normaliseEmailAddress( String email )
375
if( email == null ) return null;
376
email = email.trim().toLowerCase( Locale.US );
377
return email.length() > 0? email : null;
380
static public String normaliseOrganisation( String organisation )
382
if( organisation == null ) return null;
383
organisation = organisation.trim();
384
return organisation.length() > 0? organisation : null;
387
static public String normaliseAddress( String address )
389
if( address == null ) return null;
390
address = address.trim();
391
return address.length() > 0? address : null;
394
static public String normaliseNote( String note )
396
if( note == null ) return null;
398
return note.length() > 0? note : null;
401
static public String normaliseBirthday( String birthday )
403
if( birthday == null ) return null;
404
birthday = birthday.trim();
405
return birthday.length() > 0? birthday : null;