/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
 *
57 by edam
cleanup; fixed some typos; updated TODO
4
 * Copyright (C) 2011 to 2012 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 > >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
140
141
	public boolean canLookup( CacheIdentifier identifier )
142
	{
143
		return lookup( identifier ) != null;
144
	}
145
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
146
	/**
147
	 * Retrieve the contact id of a contact identified by the specified cache
148
	 * identifier, if it exists.
93 by Tim Marston
minor style tweaks
149
	 *
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
150
	 * @param identifier the cache identifier
151
	 * @return a contact id, or null
152
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
153
	public Long lookup( CacheIdentifier identifier )
154
	{
155
		switch( identifier.getType() )
156
		{
157
		case NAME:
158
			return _contactsByName.get( identifier.getDetail() );
159
		case ORGANISATION:
160
			return _contactsByOrg.get( identifier.getDetail() );
161
		case PRIMARY_NUMBER:
162
			return _contactsByNumber.get( identifier.getDetail() );
163
		case PRIMARY_EMAIL:
164
			return _contactsByEmail.get( identifier.getDetail() );
165
		}
166
		return null;
167
	}
168
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
169
	/**
170
	 * Remove any cache entry that is identified by the cache identifier.
93 by Tim Marston
minor style tweaks
171
	 *
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
172
	 * @param identifier the cache identifier
173
	 * @return the contact id of the contact that was removed, or null
174
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
175
	public Long removeLookup( CacheIdentifier identifier )
176
	{
177
		switch( identifier.getType() )
178
		{
179
		case NAME:
180
			return _contactsByName.remove( identifier.getDetail() );
181
		case ORGANISATION:
182
			return _contactsByOrg.remove( identifier.getDetail() );
183
		case PRIMARY_NUMBER:
184
			return _contactsByNumber.remove( identifier.getDetail() );
185
		case PRIMARY_EMAIL:
186
			return _contactsByEmail.remove( identifier.getDetail() );
187
		}
188
		return null;
189
	}
190
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
191
	/**
192
	 * Add a lookup from a contact identifier to a contact id to the cache.
93 by Tim Marston
minor style tweaks
193
	 *
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
194
	 * @param identifier the cache identifier
195
	 * @param id teh contact id
196
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
197
	public void addLookup( CacheIdentifier identifier, Long id )
198
	{
199
		switch( identifier.getType() )
200
		{
201
		case NAME:
202
			_contactsByName.put( identifier.getDetail(), id );
203
			break;
204
		case ORGANISATION:
205
			_contactsByOrg.put( identifier.getDetail(), id );
206
			break;
207
		case PRIMARY_NUMBER:
208
			_contactsByNumber.put( identifier.getDetail(), id );
209
			break;
210
		case PRIMARY_EMAIL:
211
			_contactsByEmail.put( identifier.getDetail(), id );
212
			break;
213
		}
214
	}
215
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
216
	/**
217
	 * Remove any data that is associated with an contact id.
93 by Tim Marston
minor style tweaks
218
	 *
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
219
	 * @param id
220
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
221
	public void removeAssociatedData( Long id )
222
	{
223
		_contactNumbers.remove( id );
224
		_contactEmails.remove( id );
225
		_contactAddresses.remove( id );
226
		_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
227
		_contactNotes.remove( id );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
228
	}
229
230
	public boolean hasAssociatedNumber( Long id, String number )
231
	{
232
		number = normalisePhoneNumber( number );
233
		if( number == null ) return false;
234
235
		HashSet< String > set = _contactNumbers.get( id );
236
		return set != null && set.contains( number );
237
	}
238
239
	public void addAssociatedNumber( Long id, String number )
240
	{
241
		number = normalisePhoneNumber( number );
242
		if( number == null ) return;
243
244
		HashSet< String > set = _contactNumbers.get( id );
245
		if( set == null ) {
246
			set = new HashSet< String >();
247
			_contactNumbers.put( id, set );
248
		}
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
249
		set.add( number );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
250
	}
251
252
	public boolean hasAssociatedEmail( Long id, String email )
253
	{
254
		email = normaliseEmailAddress( email );
255
		if( email == null ) return false;
256
257
		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
258
		return set != null && set.contains( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
259
	}
260
261
	public void addAssociatedEmail( Long id, String email )
262
	{
263
		email = normaliseEmailAddress( email );
264
		if( email == null ) return;
265
266
		HashSet< String > set = _contactEmails.get( id );
267
		if( set == null ) {
268
			set = new HashSet< String >();
269
			_contactEmails.put( id, set );
270
		}
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
271
		set.add( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
272
	}
273
274
	public boolean hasAssociatedAddress( Long id, String address )
275
	{
276
		address = normaliseAddress( address );
277
		if( address == null ) return false;
278
279
		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
280
		return set != null && set.contains( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
281
	}
282
283
	public void addAssociatedAddress( Long id, String address )
284
	{
285
		address = normaliseAddress( address );
286
		if( address == null ) return;
287
288
		HashSet< String > set = _contactAddresses.get( id );
289
		if( set == null ) {
290
			set = new HashSet< String >();
291
			_contactAddresses.put( id, set );
292
		}
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
293
		set.add( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
294
	}
295
296
	public boolean hasAssociatedOrganisation( Long id, String organisation )
297
	{
298
		organisation = normaliseOrganisation( organisation );
299
		if( organisation == null ) return false;
300
301
		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
302
		return set != null && set.contains( organisation );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
303
	}
304
305
	public void addAssociatedOrganisation( Long id, String organisation )
306
	{
307
		organisation = normaliseOrganisation( organisation );
308
		if( organisation == null ) return;
309
310
		HashSet< String > set = _contactOrganisations.get( id );
311
		if( set == null ) {
312
			set = new HashSet< String >();
313
			_contactOrganisations.put( id, set );
314
		}
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
315
		set.add( organisation );
316
	}
317
318
	public boolean hasAssociatedNote( Long id, String note )
319
	{
320
		note = normaliseNote( note );
321
		if( note == null ) return false;
322
323
		HashSet< String > set = _contactNotes.get( id );
324
		return set != null && set.contains( note );
325
	}
326
327
	public void addAssociatedNote( Long id, String note )
328
	{
329
		note = normaliseNote( note );
330
		if( note == null ) return;
331
332
		HashSet< String > set = _contactNotes.get( id );
333
		if( set == null ) {
334
			set = new HashSet< String >();
335
			_contactNotes.put( id, set );
336
		}
337
		set.add( note );
39 by edam
- pulled contacts cache out in to seperate class
338
	}
339
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
340
	static public String normaliseName( String name )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
341
	{
342
		if( name == null ) return null;
343
		name = name.trim();
344
		return name.length() > 0? name : null;
345
	}
346
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
347
	static public String normalisePhoneNumber( String number )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
348
	{
349
		if( number == null ) return null;
350
		number = number.trim().replaceAll( "[-\\(\\) ]", "" );
351
		return number.length() > 0? number : null;
352
	}
353
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
354
	static public String normaliseEmailAddress( String email )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
355
	{
356
		if( email == null ) 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
357
		email = email.trim().toLowerCase( Locale.US );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
358
		return email.length() > 0? email : null;
359
	}
360
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
361
	static public String normaliseOrganisation( String organisation )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
362
	{
363
		if( organisation == null ) return null;
364
		organisation = organisation.trim();
365
		return organisation.length() > 0? organisation : null;
366
	}
367
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
368
	static public String normaliseAddress( String address )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
369
	{
370
		if( address == null ) return null;
371
		address = address.trim();
372
		return address.length() > 0? address : null;
39 by edam
- pulled contacts cache out in to seperate class
373
	}
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
374
375
	static public String normaliseNote( String note )
376
	{
377
		if( note == null ) return null;
378
		note = note.trim();
379
		return note.length() > 0? note : null;
380
	}
39 by edam
- pulled contacts cache out in to seperate class
381
}