/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts
39 by edam
- pulled contacts cache out in to seperate class
1
/*
2
 * ContactsCache.java
3
 *
95 by Tim Marston
added suopport for birthdays
4
 * Copyright (C) 2011 to 2013 Tim Marston <tim@ed.am>
39 by edam
- pulled contacts cache out in to seperate class
5
 *
6
 * This file is part of the Import Contacts program (hereafter referred
93 by Tim Marston
minor style tweaks
7
 * to as "this program").  For more information, see
50 by edam
updated all URLs, email addresses and package names to ed.am
8
 * http://ed.am/dev/android/import-contacts
39 by edam
- pulled contacts cache out in to seperate class
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
50 by edam
updated all URLs, email addresses and package names to ed.am
24
package am.ed.importcontacts;
39 by edam
- pulled contacts cache out in to seperate class
25
26
import java.util.HashMap;
27
import java.util.HashSet;
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
28
import java.util.Locale;
39 by edam
- pulled contacts cache out in to seperate class
29
30
public class ContactsCache
31
{
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
32
	/**
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
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.
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
36
	 */
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
37
	public static class CacheIdentifier
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
38
	{
66 by edam
removed redundant CacheIdentifier constructor and NONE type
39
		public enum Type { NAME, ORGANISATION, PRIMARY_NUMBER, PRIMARY_EMAIL }
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
40
41
		private Type _type;
42
		private String _detail;
43
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
44
		/**
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.
93 by Tim Marston
minor style tweaks
48
		 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
49
		 * @param type the detail type
50
		 * @param detail the detail
51
		 * @return the cache identifier, or null
52
		 */
53
		public static CacheIdentifier factory( Type type, String detail )
54
		{
55
			switch( type )
56
			{
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;
61
			default: return null;
62
			}
63
			if( detail == null ) return null;
64
			return new CacheIdentifier( type, detail );
65
		}
66
67
		/**
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.
93 by Tim Marston
minor style tweaks
71
		 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
72
		 * @param contact the contact data
73
		 * @return the cache identifier, or null
74
		 */
75
		public static CacheIdentifier factory( Importer.ContactData contact )
76
		{
67 by edam
slightly improved the efficiency of the cache identifier factory function
77
			CacheIdentifier identifier = null;
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
78
79
			if( contact.hasName() )
67 by edam
slightly improved the efficiency of the cache identifier factory function
80
				identifier = factory( CacheIdentifier.Type.NAME,
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
81
					contact.getName() );
67 by edam
slightly improved the efficiency of the cache identifier factory function
82
			if( identifier != null ) return identifier;
83
84
			if( contact.hasPrimaryOrganisation() )
85
				identifier = factory( CacheIdentifier.Type.ORGANISATION,
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
86
					contact.getPrimaryOrganisation() );
67 by edam
slightly improved the efficiency of the cache identifier factory function
87
			if( identifier != null ) return identifier;
88
89
			if( contact.hasPrimaryNumber() )
90
				identifier = factory( CacheIdentifier.Type.PRIMARY_NUMBER,
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
91
					contact.getPrimaryNumber() );
67 by edam
slightly improved the efficiency of the cache identifier factory function
92
			if( identifier != null ) return identifier;
93
94
			if( contact.hasPrimaryEmail() )
95
				identifier = factory( CacheIdentifier.Type.PRIMARY_EMAIL,
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
96
					contact.getPrimaryEmail() );
67 by edam
slightly improved the efficiency of the cache identifier factory function
97
			if( identifier != null ) return identifier;
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
98
67 by edam
slightly improved the efficiency of the cache identifier factory function
99
			return null;
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
100
		}
101
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
102
		protected CacheIdentifier( Type type, String detail )
103
		{
104
			_type = type;
105
			_detail = detail;
106
		}
107
108
		public Type getType()
109
		{
110
			return _type;
111
		}
112
113
		public String getDetail()
114
		{
115
			return _detail;
116
		}
117
	}
118
119
	// mappings of contact names, organisations and primary numbers to ids
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
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 >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
128
129
	// mapping of contact ids to sets of associated data
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
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 > >();
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
138
	private HashMap< Long, HashSet< String > > _contactNotes
139
		= new HashMap< Long, HashSet< String > >();
95 by Tim Marston
added suopport for birthdays
140
	private HashMap< Long, String > _contactBirthdays
141
		= new HashMap< Long, String >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
142
143
	public boolean canLookup( CacheIdentifier identifier )
144
	{
145
		return lookup( identifier ) != null;
146
	}
147
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
148
	/**
149
	 * Retrieve the contact id of a contact identified by the specified cache
150
	 * identifier, if it exists.
93 by Tim Marston
minor style tweaks
151
	 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
152
	 * @param identifier the cache identifier
153
	 * @return a contact id, or null
154
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
155
	public Long lookup( CacheIdentifier identifier )
156
	{
157
		switch( identifier.getType() )
158
		{
159
		case NAME:
160
			return _contactsByName.get( identifier.getDetail() );
161
		case ORGANISATION:
162
			return _contactsByOrg.get( identifier.getDetail() );
163
		case PRIMARY_NUMBER:
164
			return _contactsByNumber.get( identifier.getDetail() );
165
		case PRIMARY_EMAIL:
166
			return _contactsByEmail.get( identifier.getDetail() );
167
		}
168
		return null;
169
	}
170
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
171
	/**
172
	 * Remove any cache entry that is identified by the cache identifier.
93 by Tim Marston
minor style tweaks
173
	 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
174
	 * @param identifier the cache identifier
175
	 * @return the contact id of the contact that was removed, or null
176
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
177
	public Long removeLookup( CacheIdentifier identifier )
178
	{
179
		switch( identifier.getType() )
180
		{
181
		case NAME:
182
			return _contactsByName.remove( identifier.getDetail() );
183
		case ORGANISATION:
184
			return _contactsByOrg.remove( identifier.getDetail() );
185
		case PRIMARY_NUMBER:
186
			return _contactsByNumber.remove( identifier.getDetail() );
187
		case PRIMARY_EMAIL:
188
			return _contactsByEmail.remove( identifier.getDetail() );
189
		}
190
		return null;
191
	}
192
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
193
	/**
194
	 * Add a lookup from a contact identifier to a contact id to the cache.
93 by Tim Marston
minor style tweaks
195
	 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
196
	 * @param identifier the cache identifier
197
	 * @param id teh contact id
198
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
199
	public void addLookup( CacheIdentifier identifier, Long id )
200
	{
201
		switch( identifier.getType() )
202
		{
203
		case NAME:
204
			_contactsByName.put( identifier.getDetail(), id );
205
			break;
206
		case ORGANISATION:
207
			_contactsByOrg.put( identifier.getDetail(), id );
208
			break;
209
		case PRIMARY_NUMBER:
210
			_contactsByNumber.put( identifier.getDetail(), id );
211
			break;
212
		case PRIMARY_EMAIL:
213
			_contactsByEmail.put( identifier.getDetail(), id );
214
			break;
215
		}
216
	}
217
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
218
	/**
219
	 * Remove any data that is associated with an contact id.
93 by Tim Marston
minor style tweaks
220
	 *
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
221
	 * @param id
222
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
223
	public void removeAssociatedData( Long id )
224
	{
225
		_contactNumbers.remove( id );
226
		_contactEmails.remove( id );
227
		_contactAddresses.remove( id );
228
		_contactOrganisations.remove( id );
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
229
		_contactNotes.remove( id );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
230
	}
231
232
	public boolean hasAssociatedNumber( Long id, String number )
233
	{
234
		number = normalisePhoneNumber( number );
235
		if( number == null ) return false;
236
237
		HashSet< String > set = _contactNumbers.get( id );
238
		return set != null && set.contains( number );
239
	}
240
241
	public void addAssociatedNumber( Long id, String number )
242
	{
243
		number = normalisePhoneNumber( number );
244
		if( number == null ) return;
245
246
		HashSet< String > set = _contactNumbers.get( id );
247
		if( set == null ) {
248
			set = new HashSet< String >();
249
			_contactNumbers.put( id, set );
250
		}
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
251
		set.add( number );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
252
	}
253
254
	public boolean hasAssociatedEmail( Long id, String email )
255
	{
256
		email = normaliseEmailAddress( email );
257
		if( email == null ) return false;
258
259
		HashSet< String > set = _contactEmails.get( id );
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
260
		return set != null && set.contains( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
261
	}
262
263
	public void addAssociatedEmail( Long id, String email )
264
	{
265
		email = normaliseEmailAddress( email );
266
		if( email == null ) return;
267
268
		HashSet< String > set = _contactEmails.get( id );
269
		if( set == null ) {
270
			set = new HashSet< String >();
271
			_contactEmails.put( id, set );
272
		}
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
273
		set.add( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
274
	}
275
276
	public boolean hasAssociatedAddress( Long id, String address )
277
	{
278
		address = normaliseAddress( address );
279
		if( address == null ) return false;
280
281
		HashSet< String > set = _contactAddresses.get( id );
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
282
		return set != null && set.contains( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
283
	}
284
285
	public void addAssociatedAddress( Long id, String address )
286
	{
287
		address = normaliseAddress( address );
288
		if( address == null ) return;
289
290
		HashSet< String > set = _contactAddresses.get( id );
291
		if( set == null ) {
292
			set = new HashSet< String >();
293
			_contactAddresses.put( id, set );
294
		}
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
295
		set.add( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
296
	}
297
298
	public boolean hasAssociatedOrganisation( Long id, String organisation )
299
	{
300
		organisation = normaliseOrganisation( organisation );
301
		if( organisation == null ) return false;
302
303
		HashSet< String > set = _contactOrganisations.get( id );
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
304
		return set != null && set.contains( organisation );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
305
	}
306
307
	public void addAssociatedOrganisation( Long id, String organisation )
308
	{
309
		organisation = normaliseOrganisation( organisation );
310
		if( organisation == null ) return;
311
312
		HashSet< String > set = _contactOrganisations.get( id );
313
		if( set == null ) {
314
			set = new HashSet< String >();
315
			_contactOrganisations.put( id, set );
316
		}
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
317
		set.add( organisation );
318
	}
319
320
	public boolean hasAssociatedNote( Long id, String note )
321
	{
322
		note = normaliseNote( note );
323
		if( note == null ) return false;
324
325
		HashSet< String > set = _contactNotes.get( id );
326
		return set != null && set.contains( note );
327
	}
328
329
	public void addAssociatedNote( Long id, String note )
330
	{
331
		note = normaliseNote( note );
332
		if( note == null ) return;
333
334
		HashSet< String > set = _contactNotes.get( id );
335
		if( set == null ) {
336
			set = new HashSet< String >();
337
			_contactNotes.put( id, set );
338
		}
339
		set.add( note );
39 by edam
- pulled contacts cache out in to seperate class
340
	}
341
95 by Tim Marston
added suopport for birthdays
342
	public boolean hasAssociatedBirthday( Long id, String birthday )
343
	{
344
		birthday = normaliseBirthday( birthday );
345
		if( birthday == null ) return false;
346
347
		String found = _contactBirthdays.get( id );
348
		return found != null && found.equalsIgnoreCase( birthday );
349
	}
350
351
	public void addAssociatedBirthday( Long id, String birthday )
352
	{
353
		birthday = normaliseBirthday( birthday );
354
		if( birthday == null ) return;
355
356
		_contactBirthdays.put( id, birthday );
357
	}
358
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
359
	static public String normaliseName( String name )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
360
	{
361
		if( name == null ) return null;
362
		name = name.trim();
363
		return name.length() > 0? name : null;
364
	}
365
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
366
	static public String normalisePhoneNumber( String number )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
367
	{
368
		if( number == null ) return null;
369
		number = number.trim().replaceAll( "[-\\(\\) ]", "" );
370
		return number.length() > 0? number : null;
371
	}
372
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
373
	static public String normaliseEmailAddress( String email )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
374
	{
375
		if( email == null ) return null;
111 by Tim Marston
removed some unused code, fixed locale warnings and made showContinueOrAbort()
376
		email = email.trim().toLowerCase( Locale.ENGLISH );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
377
		return email.length() > 0? email : null;
378
	}
379
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
380
	static public String normaliseOrganisation( String organisation )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
381
	{
382
		if( organisation == null ) return null;
383
		organisation = organisation.trim();
384
		return organisation.length() > 0? organisation : null;
385
	}
386
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
387
	static public String normaliseAddress( String address )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
388
	{
389
		if( address == null ) return null;
390
		address = address.trim();
391
		return address.length() > 0? address : null;
39 by edam
- pulled contacts cache out in to seperate class
392
	}
65 by edam
added support for notes; rewrote backends so that all normalising of data is now done within the contacts cache; made the vCard unescape routine slightly more acceptant of non-standard escaped characters
393
394
	static public String normaliseNote( String note )
395
	{
396
		if( note == null ) return null;
397
		note = note.trim();
398
		return note.length() > 0? note : null;
399
	}
95 by Tim Marston
added suopport for birthdays
400
401
	static public String normaliseBirthday( String birthday )
402
	{
403
		if( birthday == null ) return null;
404
		birthday = birthday.trim();
405
		return birthday.length() > 0? birthday : null;
406
	}
39 by edam
- pulled contacts cache out in to seperate class
407
}