/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
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
	{
39
		public enum Type {
40
			NONE, NAME, ORGANISATION, PRIMARY_NUMBER, PRIMARY_EMAIL }
41
42
		private Type _type;
43
		private String _detail;
44
45
		protected CacheIdentifier()
46
		{
47
			_type = Type.NONE;
48
		}
49
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
50
		/**
51
		 * Obtain a cache identifier.  This routine is designed to be as robust
52
		 * as possible (in terms of bad or null detail values), and to return
53
		 * null when a cache identifier can not be created.
54
		 * @param type the detail type
55
		 * @param detail the detail
56
		 * @return the cache identifier, or null
57
		 */
58
		public static CacheIdentifier factory( Type type, String detail )
59
		{
60
			switch( type )
61
			{
62
			case NAME: detail = normaliseName( detail ); break;
63
			case ORGANISATION: detail = normaliseOrganisation( detail ); break;
64
			case PRIMARY_NUMBER: detail = normalisePhoneNumber( detail ); break;
65
			case PRIMARY_EMAIL: detail = normaliseEmailAddress( detail ); break;
66
			default: return null;
67
			}
68
			if( detail == null ) return null;
69
			return new CacheIdentifier( type, detail );
70
		}
71
72
		/**
73
		 * Obtain a cache identifier from contact data.  This routine is
74
		 * designed to be as robust as possible and may return null when a cache
75
		 * identifier can not be created.
76
		 * @param contact the contact data
77
		 * @return the cache identifier, or null
78
		 */
79
		public static CacheIdentifier factory( Importer.ContactData contact )
80
		{
81
			CacheIdentifier ret = null;
82
83
			if( contact.hasName() )
84
				ret = factory( CacheIdentifier.Type.NAME,
85
					contact.getName() );
86
			if( ret == null && contact.hasPrimaryOrganisation() )
87
				ret = factory( CacheIdentifier.Type.ORGANISATION,
88
					contact.getPrimaryOrganisation() );
89
			if( ret == null && contact.hasPrimaryNumber() )
90
				ret = factory( CacheIdentifier.Type.PRIMARY_NUMBER,
91
					contact.getPrimaryNumber() );
92
			if( ret == null && contact.hasPrimaryEmail() )
93
				ret = factory( CacheIdentifier.Type.PRIMARY_EMAIL,
94
					contact.getPrimaryEmail() );
95
96
			return ret;
97
		}
98
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
99
		protected CacheIdentifier( Type type, String detail )
100
		{
101
			_type = type;
102
			_detail = detail;
103
		}
104
105
		public Type getType()
106
		{
107
			return _type;
108
		}
109
110
		public String getDetail()
111
		{
112
			return _detail;
113
		}
114
	}
115
116
	// 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
117
	private HashMap< String, Long > _contactsByName
118
		= new HashMap< String, Long >();
119
	private HashMap< String, Long > _contactsByOrg
120
		= new HashMap< String, Long >();
121
	private HashMap< String, Long > _contactsByNumber
122
		= new HashMap< String, Long >();
123
	private HashMap< String, Long > _contactsByEmail
124
		= new HashMap< String, Long >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
125
126
	// 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
127
	private HashMap< Long, HashSet< String > > _contactNumbers
128
		= new HashMap< Long, HashSet< String > >();
129
	private HashMap< Long, HashSet< String > > _contactEmails
130
		= new HashMap< Long, HashSet< String > >();
131
	private HashMap< Long, HashSet< String > > _contactAddresses
132
		= new HashMap< Long, HashSet< String > >();
133
	private HashMap< Long, HashSet< String > > _contactOrganisations
134
		= 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
135
	private HashMap< Long, HashSet< String > > _contactNotes
136
		= new HashMap< Long, HashSet< String > >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
137
138
	public boolean canLookup( CacheIdentifier identifier )
139
	{
140
		return lookup( identifier ) != null;
141
	}
142
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
143
	/**
144
	 * Retrieve the contact id of a contact identified by the specified cache
145
	 * identifier, if it exists.
146
	 * @param identifier the cache identifier
147
	 * @return a contact id, or null
148
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
149
	public Long lookup( CacheIdentifier identifier )
150
	{
151
		switch( identifier.getType() )
152
		{
153
		case NAME:
154
			return _contactsByName.get( identifier.getDetail() );
155
		case ORGANISATION:
156
			return _contactsByOrg.get( identifier.getDetail() );
157
		case PRIMARY_NUMBER:
158
			return _contactsByNumber.get( identifier.getDetail() );
159
		case PRIMARY_EMAIL:
160
			return _contactsByEmail.get( identifier.getDetail() );
161
		}
162
		return null;
163
	}
164
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
165
	/**
166
	 * Remove any cache entry that is identified by the cache identifier.
167
	 * @param identifier the cache identifier
168
	 * @return the contact id of the contact that was removed, or null
169
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
170
	public Long removeLookup( CacheIdentifier identifier )
171
	{
172
		switch( identifier.getType() )
173
		{
174
		case NAME:
175
			return _contactsByName.remove( identifier.getDetail() );
176
		case ORGANISATION:
177
			return _contactsByOrg.remove( identifier.getDetail() );
178
		case PRIMARY_NUMBER:
179
			return _contactsByNumber.remove( identifier.getDetail() );
180
		case PRIMARY_EMAIL:
181
			return _contactsByEmail.remove( identifier.getDetail() );
182
		}
183
		return null;
184
	}
185
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
186
	/**
187
	 * Add a lookup from a contact identifier to a contact id to the cache.
188
	 * @param identifier the cache identifier
189
	 * @param id teh contact id
190
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
191
	public void addLookup( CacheIdentifier identifier, Long id )
192
	{
193
		switch( identifier.getType() )
194
		{
195
		case NAME:
196
			_contactsByName.put( identifier.getDetail(), id );
197
			break;
198
		case ORGANISATION:
199
			_contactsByOrg.put( identifier.getDetail(), id );
200
			break;
201
		case PRIMARY_NUMBER:
202
			_contactsByNumber.put( identifier.getDetail(), id );
203
			break;
204
		case PRIMARY_EMAIL:
205
			_contactsByEmail.put( identifier.getDetail(), id );
206
			break;
207
		}
208
	}
209
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
210
	/**
211
	 * Remove any data that is associated with an contact id.
212
	 * @param id
213
	 */
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
214
	public void removeAssociatedData( Long id )
215
	{
216
		_contactNumbers.remove( id );
217
		_contactEmails.remove( id );
218
		_contactAddresses.remove( id );
219
		_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
220
		_contactNotes.remove( id );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
221
	}
222
223
	public boolean hasAssociatedNumber( Long id, String number )
224
	{
225
		number = normalisePhoneNumber( number );
226
		if( number == null ) return false;
227
228
		HashSet< String > set = _contactNumbers.get( id );
229
		return set != null && set.contains( number );
230
	}
231
232
	public void addAssociatedNumber( Long id, String number )
233
	{
234
		number = normalisePhoneNumber( number );
235
		if( number == null ) return;
236
237
		HashSet< String > set = _contactNumbers.get( id );
238
		if( set == null ) {
239
			set = new HashSet< String >();
240
			_contactNumbers.put( id, set );
241
		}
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
242
		set.add( number );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
243
	}
244
245
	public boolean hasAssociatedEmail( Long id, String email )
246
	{
247
		email = normaliseEmailAddress( email );
248
		if( email == null ) return false;
249
250
		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
251
		return set != null && set.contains( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
252
	}
253
254
	public void addAssociatedEmail( Long id, String email )
255
	{
256
		email = normaliseEmailAddress( email );
257
		if( email == null ) return;
258
259
		HashSet< String > set = _contactEmails.get( id );
260
		if( set == null ) {
261
			set = new HashSet< String >();
262
			_contactEmails.put( id, set );
263
		}
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
264
		set.add( email );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
265
	}
266
267
	public boolean hasAssociatedAddress( Long id, String address )
268
	{
269
		address = normaliseAddress( address );
270
		if( address == null ) return false;
271
272
		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
273
		return set != null && set.contains( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
274
	}
275
276
	public void addAssociatedAddress( Long id, String address )
277
	{
278
		address = normaliseAddress( address );
279
		if( address == null ) return;
280
281
		HashSet< String > set = _contactAddresses.get( id );
282
		if( set == null ) {
283
			set = new HashSet< String >();
284
			_contactAddresses.put( id, set );
285
		}
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
286
		set.add( address );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
287
	}
288
289
	public boolean hasAssociatedOrganisation( Long id, String organisation )
290
	{
291
		organisation = normaliseOrganisation( organisation );
292
		if( organisation == null ) return false;
293
294
		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
295
		return set != null && set.contains( organisation );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
296
	}
297
298
	public void addAssociatedOrganisation( Long id, String organisation )
299
	{
300
		organisation = normaliseOrganisation( organisation );
301
		if( organisation == null ) return;
302
303
		HashSet< String > set = _contactOrganisations.get( id );
304
		if( set == null ) {
305
			set = new HashSet< String >();
306
			_contactOrganisations.put( id, set );
307
		}
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
308
		set.add( organisation );
309
	}
310
311
	public boolean hasAssociatedNote( Long id, String note )
312
	{
313
		note = normaliseNote( note );
314
		if( note == null ) return false;
315
316
		HashSet< String > set = _contactNotes.get( id );
317
		return set != null && set.contains( note );
318
	}
319
320
	public void addAssociatedNote( Long id, String note )
321
	{
322
		note = normaliseNote( note );
323
		if( note == null ) return;
324
325
		HashSet< String > set = _contactNotes.get( id );
326
		if( set == null ) {
327
			set = new HashSet< String >();
328
			_contactNotes.put( id, set );
329
		}
330
		set.add( note );
39 by edam
- pulled contacts cache out in to seperate class
331
	}
332
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
333
	static public String normaliseName( String name )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
334
	{
335
		if( name == null ) return null;
336
		name = name.trim();
337
		return name.length() > 0? name : null;
338
	}
339
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
340
	static public String normalisePhoneNumber( String number )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
341
	{
342
		if( number == null ) return null;
343
		number = number.trim().replaceAll( "[-\\(\\) ]", "" );
344
		return number.length() > 0? number : null;
345
	}
346
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
347
	static public String normaliseEmailAddress( String email )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
348
	{
349
		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
350
		email = email.trim().toLowerCase( Locale.US );
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
351
		return email.length() > 0? email : null;
352
	}
353
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
354
	static public String normaliseOrganisation( String organisation )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
355
	{
356
		if( organisation == null ) return null;
357
		organisation = organisation.trim();
358
		return organisation.length() > 0? organisation : null;
359
	}
360
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
361
	static public String normaliseAddress( String address )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
362
	{
363
		if( address == null ) return null;
364
		address = address.trim();
365
		return address.length() > 0? address : null;
39 by edam
- pulled contacts cache out in to seperate class
366
	}
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
367
368
	static public String normaliseNote( String note )
369
	{
370
		if( note == null ) return null;
371
		note = note.trim();
372
		return note.length() > 0? note : null;
373
	}
39 by edam
- pulled contacts cache out in to seperate class
374
}