/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;
28
29
public class ContactsCache
30
{
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
31
	/**
32
	 * Information that can be used to identify a contact within the cache
33
	 */
34
	static public class CacheIdentifier
35
	{
36
		public enum Type {
37
			NONE, NAME, ORGANISATION, PRIMARY_NUMBER, PRIMARY_EMAIL }
38
39
		private Type _type;
40
		private String _detail;
41
42
		protected CacheIdentifier()
43
		{
44
			_type = Type.NONE;
45
		}
46
47
		protected CacheIdentifier( Type type, String detail )
48
		{
49
			_type = type;
50
			_detail = detail;
51
		}
52
53
		public Type getType()
54
		{
55
			return _type;
56
		}
57
58
		public String getDetail()
59
		{
60
			return _detail;
61
		}
62
	}
63
64
	// 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
65
	private HashMap< String, Long > _contactsByName
66
		= new HashMap< String, Long >();
67
	private HashMap< String, Long > _contactsByOrg
68
		= new HashMap< String, Long >();
69
	private HashMap< String, Long > _contactsByNumber
70
		= new HashMap< String, Long >();
71
	private HashMap< String, Long > _contactsByEmail
72
		= new HashMap< String, Long >();
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
73
74
	// 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
75
	private HashMap< Long, HashSet< String > > _contactNumbers
76
		= new HashMap< Long, HashSet< String > >();
77
	private HashMap< Long, HashSet< String > > _contactEmails
78
		= new HashMap< Long, HashSet< String > >();
79
	private HashMap< Long, HashSet< String > > _contactAddresses
80
		= new HashMap< Long, HashSet< String > >();
81
	private HashMap< Long, HashSet< String > > _contactOrganisations
82
		= new HashMap< Long, HashSet< String > >();
83
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
84
	public static CacheIdentifier createIdentifier(
85
		Importer.ContactData contact )
86
	{
87
		if( contact.hasName() ) {
88
			String name = normaliseName( contact.getName() );
89
			if( name != null )
90
				return new CacheIdentifier(
91
					CacheIdentifier.Type.NAME, name );
92
		}
93
94
		if( contact.hasPrimaryOrganisation() ) {
95
			String organisation = normaliseOrganisation(
96
				contact.getPrimaryOrganisation() );
97
			if( organisation != null )
98
				return new CacheIdentifier(
99
					CacheIdentifier.Type.ORGANISATION, organisation );
100
		}
101
102
		if( contact.hasPrimaryNumber() ) {
103
			String number = normalisePhoneNumber( contact.getPrimaryNumber() );
104
			if( number != null )
105
			return new CacheIdentifier(
106
				CacheIdentifier.Type.PRIMARY_NUMBER, number );
107
		}
108
109
		if( contact.hasPrimaryEmail() ) {
110
			String email = normaliseEmailAddress( contact.getPrimaryEmail() );
111
			if( email != null )
112
			return new CacheIdentifier(
113
				CacheIdentifier.Type.PRIMARY_EMAIL, email );
114
		}
115
116
		return null;
117
	}
118
119
	public boolean canLookup( CacheIdentifier identifier )
120
	{
121
		return lookup( identifier ) != null;
122
	}
123
124
	public Long lookup( CacheIdentifier identifier )
125
	{
126
		switch( identifier.getType() )
127
		{
128
		case NAME:
129
			return _contactsByName.get( identifier.getDetail() );
130
		case ORGANISATION:
131
			return _contactsByOrg.get( identifier.getDetail() );
132
		case PRIMARY_NUMBER:
133
			return _contactsByNumber.get( identifier.getDetail() );
134
		case PRIMARY_EMAIL:
135
			return _contactsByEmail.get( identifier.getDetail() );
136
		}
137
		return null;
138
	}
139
140
	public Long removeLookup( CacheIdentifier identifier )
141
	{
142
		switch( identifier.getType() )
143
		{
144
		case NAME:
145
			return _contactsByName.remove( identifier.getDetail() );
146
		case ORGANISATION:
147
			return _contactsByOrg.remove( identifier.getDetail() );
148
		case PRIMARY_NUMBER:
149
			return _contactsByNumber.remove( identifier.getDetail() );
150
		case PRIMARY_EMAIL:
151
			return _contactsByEmail.remove( identifier.getDetail() );
152
		}
153
		return null;
154
	}
155
156
	public void addLookup( CacheIdentifier identifier, Long id )
157
	{
158
		switch( identifier.getType() )
159
		{
160
		case NAME:
161
			_contactsByName.put( identifier.getDetail(), id );
162
			break;
163
		case ORGANISATION:
164
			_contactsByOrg.put( identifier.getDetail(), id );
165
			break;
166
		case PRIMARY_NUMBER:
167
			_contactsByNumber.put( identifier.getDetail(), id );
168
			break;
169
		case PRIMARY_EMAIL:
170
			_contactsByEmail.put( identifier.getDetail(), id );
171
			break;
172
		}
173
	}
174
175
	public void removeAssociatedData( Long id )
176
	{
177
		_contactNumbers.remove( id );
178
		_contactEmails.remove( id );
179
		_contactAddresses.remove( id );
180
		_contactOrganisations.remove( id );
181
	}
182
183
	public boolean hasAssociatedNumber( Long id, String number )
184
	{
185
		number = normalisePhoneNumber( number );
186
		if( number == null ) return false;
187
188
		HashSet< String > set = _contactNumbers.get( id );
189
		return set != null && set.contains( number );
190
	}
191
192
	public void addAssociatedNumber( Long id, String number )
193
	{
194
		number = normalisePhoneNumber( number );
195
		if( number == null ) return;
196
197
		HashSet< String > set = _contactNumbers.get( id );
198
		if( set == null ) {
199
			set = new HashSet< String >();
200
			_contactNumbers.put( id, set );
201
		}
202
		set.add( normalisePhoneNumber( number ) );
203
	}
204
205
	public boolean hasAssociatedEmail( Long id, String email )
206
	{
207
		email = normaliseEmailAddress( email );
208
		if( email == null ) return false;
209
210
		HashSet< String > set = _contactEmails.get( id );
211
		return set != null && set.contains( normaliseEmailAddress( email ) );
212
	}
213
214
	public void addAssociatedEmail( Long id, String email )
215
	{
216
		email = normaliseEmailAddress( email );
217
		if( email == null ) return;
218
219
		HashSet< String > set = _contactEmails.get( id );
220
		if( set == null ) {
221
			set = new HashSet< String >();
222
			_contactEmails.put( id, set );
223
		}
224
		set.add( normaliseEmailAddress( email ) );
225
	}
226
227
	public boolean hasAssociatedAddress( Long id, String address )
228
	{
229
		address = normaliseAddress( address );
230
		if( address == null ) return false;
231
232
		HashSet< String > set = _contactAddresses.get( id );
233
		return set != null && set.contains( normaliseAddress( address ) );
234
	}
235
236
	public void addAssociatedAddress( Long id, String address )
237
	{
238
		address = normaliseAddress( address );
239
		if( address == null ) return;
240
241
		HashSet< String > set = _contactAddresses.get( id );
242
		if( set == null ) {
243
			set = new HashSet< String >();
244
			_contactAddresses.put( id, set );
245
		}
246
		set.add( normaliseAddress( address ) );
247
	}
248
249
	public boolean hasAssociatedOrganisation( Long id, String organisation )
250
	{
251
		organisation = normaliseOrganisation( organisation );
252
		if( organisation == null ) return false;
253
254
		HashSet< String > set = _contactOrganisations.get( id );
255
		return set != null && set.contains(
256
			normaliseOrganisation( organisation ) );
257
	}
258
259
	public void addAssociatedOrganisation( Long id, String organisation )
260
	{
261
		organisation = normaliseOrganisation( organisation );
262
		if( organisation == null ) return;
263
264
		HashSet< String > set = _contactOrganisations.get( id );
265
		if( set == null ) {
266
			set = new HashSet< String >();
267
			_contactOrganisations.put( id, set );
268
		}
269
		set.add( normaliseOrganisation( organisation ) );
39 by edam
- pulled contacts cache out in to seperate class
270
	}
271
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
272
	static public String normaliseName( String name )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
273
	{
274
		if( name == null ) return null;
275
		name = name.trim();
276
		return name.length() > 0? name : null;
277
	}
278
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
279
	static public String normalisePhoneNumber( String number )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
280
	{
281
		if( number == null ) return null;
282
		number = number.trim().replaceAll( "[-\\(\\) ]", "" );
283
		return number.length() > 0? number : null;
284
	}
285
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
286
	static public String normaliseEmailAddress( String email )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
287
	{
288
		if( email == null ) return null;
289
		email = email.trim().toLowerCase();
290
		return email.length() > 0? email : null;
291
	}
292
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
293
	static public String normaliseOrganisation( String organisation )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
294
	{
295
		if( organisation == null ) return null;
296
		organisation = organisation.trim();
297
		return organisation.length() > 0? organisation : null;
298
	}
299
53 by edam
abstracted the android contacts API in to an interface, ready to be switched to
300
	static public String normaliseAddress( String address )
40 by edam
- fixed logic for vcard field types (home, work, cell, etc) so it works
301
	{
302
		if( address == null ) return null;
303
		address = address.trim();
304
		return address.length() > 0? address : null;
39 by edam
- pulled contacts cache out in to seperate class
305
	}
306
}