/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts
6 by edam
- added GPL header comments to all files
1
/*
2
 * Importer.java
3
 *
4
 * Copyright (C) 2009 Tim Marston <edam@waxworlds.org>
5
 *
6
 * This file is part of the Import Contacts program (hereafter referred
7
 * to as "this program"). For more information, see
8
 * http://www.waxworlds.org/edam/software/android/import-contacts
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
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
24
package org.waxworlds.edam.importcontacts;
1 by edam
Initial import
25
26
import java.util.HashMap;
27
import java.util.Iterator;
28
import java.util.Set;
29
import java.util.regex.Matcher;
30
import java.util.regex.Pattern;
31
32
import android.content.ContentUris;
33
import android.content.ContentValues;
34
import android.content.SharedPreferences;
35
import android.net.Uri;
36
import android.os.Message;
37
import android.provider.Contacts;
38
37 by edam
- updated TODO and NEWS
39
1 by edam
Initial import
40
public class Importer extends Thread
41
{
3 by edam
- added "all done" message
42
	public final static int ACTION_ABORT = 1;
43
	public final static int ACTION_ALLDONE = 2;
1 by edam
Initial import
44
45
	public final static int RESPONSE_NEGATIVE = 0;
46
	public final static int RESPONSE_POSITIVE = 1;
47
48
	public final static int RESPONSEEXTRA_NONE = 0;
49
	public final static int RESPONSEEXTRA_ALWAYS = 1;
50
51
	private Doit _doit;
52
	private int _response;
53
	private int _responseExtra;
54
	private int _mergeSetting;
55
	private int _lastMergeDecision;
56
	private boolean _abort = false;
3 by edam
- added "all done" message
57
	private boolean _isFinished = false;
39 by edam
- pulled contacts cache out in to seperate class
58
	private ContactsCache _contactsCache = null;
1 by edam
Initial import
59
60
	public class ContactData
61
	{
62
		class PhoneData
63
		{
64
			public String _number;
65
			public int _type;
66
			public boolean _isPreferred;
67
68
			public PhoneData( String number, int type, boolean isPreferred ) {
69
				_number = number;
70
				_type = type;
71
				_isPreferred = isPreferred;
72
			}
73
74
			public String getNumber() {
75
				return _number;
76
			}
77
78
			public int getType() {
79
				return _type;
80
			}
81
82
			public boolean isPreferred() {
83
				return _isPreferred;
84
			}
85
		}
86
87
		class EmailData
88
		{
89
			private String _email;
90
			public int _type;
91
			private boolean _isPreferred;
92
93
			public EmailData( String email, int type, boolean isPreferred ) {
94
				_email = email;
95
				_type = type;
96
				_isPreferred = isPreferred;
97
			}
98
99
			public String getAddress() {
100
				return _email;
101
			}
102
103
			public int getType() {
104
				return _type;
105
			}
106
107
			public boolean isPreferred() {
108
				return _isPreferred;
109
			}
110
		}
111
37 by edam
- updated TODO and NEWS
112
		class AddressData
113
		{
114
			private String _address;
115
			public int _type;
116
117
			public AddressData( String address, int type ) {
118
				_address = address;
119
				_type = type;
120
			}
121
122
			public String getAddress() {
123
				return _address;
124
			}
125
126
			public int getType() {
127
				return _type;
128
			}
129
		}
130
1 by edam
Initial import
131
		public String _name = null;
132
		public HashMap< String, PhoneData > _phones = null;
133
		public HashMap< String, EmailData > _emails = null;
37 by edam
- updated TODO and NEWS
134
		public HashMap< String, AddressData > _addresses = null;
1 by edam
Initial import
135
136
		protected void setName( String name )
137
		{
138
			_name = name;
139
		}
140
141
		public String getName()
142
		{
143
			return _name;
144
		}
145
146
		protected void addPhone( String number, int type, boolean isPreferred )
147
		{
148
			if( _phones == null ) _phones = new HashMap< String, PhoneData >();
149
			if( !_phones.containsKey( number ) )
150
				_phones.put( number,
36 by edam
- formatting: removed some double-indents on overrunning lines
151
					new PhoneData( number, type, isPreferred ) );
1 by edam
Initial import
152
		}
153
154
		protected void addEmail( String email, int type, boolean isPreferred )
155
		{
156
			if( _emails == null ) _emails = new HashMap< String, EmailData >();
157
			if( !_emails.containsKey( email ) )
158
				_emails.put( email, new EmailData( email, type, isPreferred ) );
159
		}
37 by edam
- updated TODO and NEWS
160
161
		protected void addAddress( String address, int type )
162
		{
163
			if( _addresses == null ) _addresses =
164
				new HashMap< String, AddressData >();
165
			if( !_addresses.containsKey( address ) )
166
				_addresses.put( address, new AddressData( address, type ) );
167
		}
1 by edam
Initial import
168
	}
169
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
170
	@SuppressWarnings("serial")
1 by edam
Initial import
171
	protected class AbortImportException extends Exception { };
172
173
	public Importer( Doit doit )
174
	{
175
		_doit = doit;
176
177
		SharedPreferences prefs = getSharedPreferences();
9 by edam
- added scroll view to all layouts
178
		_mergeSetting = prefs.getInt( "merge_setting", Doit.ACTION_PROMPT );
1 by edam
Initial import
179
	}
180
181
	@Override
182
	public void run()
183
	{
184
		try
185
		{
39 by edam
- pulled contacts cache out in to seperate class
186
			// update UI
187
			setProgressMessage( R.string.doit_caching );
188
189
			// build a cache of existing contacts
190
			_contactsCache = new ContactsCache();
191
			_contactsCache.buildCache( _doit );
1 by edam
Initial import
192
193
			// do the import
194
			onImport();
195
196
			// done!
3 by edam
- added "all done" message
197
			finish( ACTION_ALLDONE );
1 by edam
Initial import
198
		}
199
		catch( AbortImportException e )
200
		{}
3 by edam
- added "all done" message
201
202
		// flag as finished to prevent interrupts
203
		setIsFinished();
204
	}
205
206
	synchronized private void setIsFinished()
207
	{
208
		_isFinished = true;
1 by edam
Initial import
209
	}
210
211
	protected void onImport() throws AbortImportException
212
	{
213
	}
214
215
	public void wake()
216
	{
217
		wake( 0, RESPONSEEXTRA_NONE );
218
	}
219
220
	public void wake( int response )
221
	{
222
		wake( response, RESPONSEEXTRA_NONE );
223
	}
224
225
	synchronized public void wake( int response, int responseExtra )
226
	{
227
		_response = response;
228
		_responseExtra = responseExtra;
229
		notify();
230
	}
231
3 by edam
- added "all done" message
232
	synchronized public boolean setAbort()
1 by edam
Initial import
233
	{
3 by edam
- added "all done" message
234
		if( !_isFinished && !_abort ) {
235
			_abort = true;
236
			notify();
237
			return true;
238
		}
239
		return false;
1 by edam
Initial import
240
	}
241
242
	protected SharedPreferences getSharedPreferences()
243
	{
244
		return _doit.getSharedPreferences();
245
	}
246
247
	protected void showError( int res ) throws AbortImportException
248
	{
249
		showError( _doit.getText( res ).toString() );
250
	}
251
252
	synchronized protected void showError( String message )
253
			throws AbortImportException
254
	{
255
		checkAbort();
256
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
257
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
1 by edam
Initial import
258
		try {
259
			wait();
260
		}
261
		catch( InterruptedException e ) { }
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
262
3 by edam
- added "all done" message
263
		// no need to check if an abortion happened during the wait, we are
264
		// about to finish anyway!
265
		finish( ACTION_ABORT );
1 by edam
Initial import
266
	}
267
268
	protected void showFatalError( int res ) throws AbortImportException
269
	{
270
		showFatalError( _doit.getText( res ).toString() );
271
	}
272
273
	synchronized protected void showFatalError( String message )
274
			throws AbortImportException
275
	{
276
		checkAbort();
277
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
278
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
1 by edam
Initial import
279
		try {
280
			wait();
281
		}
282
		catch( InterruptedException e ) { }
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
283
3 by edam
- added "all done" message
284
		// no need to check if an abortion happened during the wait, we are
285
		// about to finish anyway!
286
		finish( ACTION_ABORT );
1 by edam
Initial import
287
	}
288
289
	protected boolean showContinue( int res ) throws AbortImportException
290
	{
291
		return showContinue( _doit.getText( res ).toString() );
292
	}
293
294
	synchronized protected boolean showContinue( String message )
295
			throws AbortImportException
296
	{
297
		checkAbort();
298
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
299
			_doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
1 by edam
Initial import
300
		try {
301
			wait();
302
		}
303
		catch( InterruptedException e ) { }
3 by edam
- added "all done" message
304
305
		// check if an abortion happened during the wait
306
		checkAbort();
307
1 by edam
Initial import
308
		return _response == RESPONSE_POSITIVE;
309
	}
310
311
	protected void setProgressMessage( int res ) throws AbortImportException
312
	{
313
		checkAbort();
314
		_doit._handler.sendMessage( Message.obtain( _doit._handler,
36 by edam
- formatting: removed some double-indents on overrunning lines
315
			Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
1 by edam
Initial import
316
	}
317
318
	protected void setProgressMax( int maxProgress )
319
			throws AbortImportException
320
	{
321
		checkAbort();
322
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
323
			_doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
324
			new Integer( maxProgress ) ) );
1 by edam
Initial import
325
	}
326
327
	protected void setTmpProgress( int tmpProgress ) throws AbortImportException
328
	{
329
		checkAbort();
330
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
331
			_doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
332
			new Integer( tmpProgress ) ) );
1 by edam
Initial import
333
	}
334
335
	protected void setProgress( int progress ) throws AbortImportException
336
	{
337
		checkAbort();
338
		_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
339
			_doit._handler, Doit.MESSAGE_SETPROGRESS,
340
			new Integer( progress ) ) );
1 by edam
Initial import
341
	}
342
3 by edam
- added "all done" message
343
	protected void finish( int action ) throws AbortImportException
1 by edam
Initial import
344
	{
3 by edam
- added "all done" message
345
		// update UI to reflect action
346
		int message;
347
		switch( action )
348
		{
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
349
		case ACTION_ALLDONE:	message = Doit.MESSAGE_ALLDONE; break;
3 by edam
- added "all done" message
350
		default:	// fall through
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
351
		case ACTION_ABORT:		message = Doit.MESSAGE_ABORT; break;
3 by edam
- added "all done" message
352
		}
353
		_doit._handler.sendEmptyMessage( message );
1 by edam
Initial import
354
3 by edam
- added "all done" message
355
		// stop
356
		throw new AbortImportException();
1 by edam
Initial import
357
	}
358
359
	protected CharSequence getText( int res )
360
	{
361
		return _doit.getText( res );
362
	}
363
364
	protected boolean isImportRequired( String name )
365
			throws AbortImportException
366
	{
367
		checkAbort();
368
		return isImportRequired( name, _mergeSetting );
369
	}
370
3 by edam
- added "all done" message
371
	synchronized private boolean isImportRequired( String name,
372
			int mergeSetting ) throws AbortImportException
1 by edam
Initial import
373
	{
374
		_lastMergeDecision = mergeSetting;
375
376
		// handle special cases
377
		switch( mergeSetting )
378
		{
9 by edam
- added scroll view to all layouts
379
		case Doit.ACTION_KEEP:
1 by edam
Initial import
380
			// if we keep contacts on duplicate, we better check for one
39 by edam
- pulled contacts cache out in to seperate class
381
			return !_contactsCache.exists( name );
1 by edam
Initial import
382
9 by edam
- added scroll view to all layouts
383
		case Doit.ACTION_PROMPT:
1 by edam
Initial import
384
			// if we are prompting on duplicate, we better check for one
39 by edam
- pulled contacts cache out in to seperate class
385
			if( !_contactsCache.exists( name ) )
1 by edam
Initial import
386
				return true;
387
388
			// ok, it exists, so do prompt
389
			_doit._handler.sendMessage( Message.obtain(
36 by edam
- formatting: removed some double-indents on overrunning lines
390
				_doit._handler, Doit.MESSAGE_MERGEPROMPT, name ) );
1 by edam
Initial import
391
			try {
392
				wait();
393
			}
394
			catch( InterruptedException e ) { }
395
3 by edam
- added "all done" message
396
			// check if an abortion happened during the wait
397
			checkAbort();
398
1 by edam
Initial import
399
			// if "always" was selected, make choice permenant
400
			if( _responseExtra == RESPONSEEXTRA_ALWAYS )
401
				_mergeSetting = _response;
402
36 by edam
- formatting: removed some double-indents on overrunning lines
403
			// recurse, with our new merge setting
1 by edam
Initial import
404
			return isImportRequired( name, _response );
405
		}
406
407
		// for all other cases (either overwriting or merging) we will need the
408
		// imported data
409
		return true;
410
	}
411
412
	protected void skipContact() throws AbortImportException
413
	{
414
		checkAbort();
3 by edam
- added "all done" message
415
		_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
1 by edam
Initial import
416
	}
417
418
	protected void importContact( ContactData contact )
419
			throws AbortImportException
420
	{
421
		checkAbort();
422
3 by edam
- added "all done" message
423
//		if( !showContinue( "====[ IMPORTING ]====\n: " + contact._name ) )
424
//			finish( ACTION_ABORT );
1 by edam
Initial import
425
426
		ContentValues values = new ContentValues();
427
		boolean uiInformed = false;
428
429
		// does contact exist already?
430
		Uri contactUri = null;
431
		Long id;
39 by edam
- pulled contacts cache out in to seperate class
432
		if( ( id = (Long)_contactsCache.getId( contact._name ) ) != null )
1 by edam
Initial import
433
		{
434
			// should we skip this import altogether?
9 by edam
- added scroll view to all layouts
435
			if( _lastMergeDecision == Doit.ACTION_KEEP ) return;
1 by edam
Initial import
436
437
			// get contact's URI
438
			contactUri = ContentUris.withAppendedId(
36 by edam
- formatting: removed some double-indents on overrunning lines
439
				Contacts.People.CONTENT_URI, id );
1 by edam
Initial import
440
441
			// should we destroy the existing contact before importing?
9 by edam
- added scroll view to all layouts
442
			if( _lastMergeDecision == Doit.ACTION_OVERWRITE ) {
1 by edam
Initial import
443
				_doit.getContentResolver().delete( contactUri, null, null );
444
				contactUri = null;
445
36 by edam
- formatting: removed some double-indents on overrunning lines
446
				// update the UI
447
				_doit._handler.sendEmptyMessage(
448
						Doit.MESSAGE_CONTACTOVERWRITTEN );
1 by edam
Initial import
449
				uiInformed = true;
450
451
				// update cache
39 by edam
- pulled contacts cache out in to seperate class
452
				_contactsCache.remove( contact._name );
1 by edam
Initial import
453
			}
454
		}
455
456
		// if we don't have a contact URI it is because the contact never
457
		// existed or because we deleted it
458
		if( contactUri == null )
459
		{
460
			// create a new contact
461
			values.put( Contacts.People.NAME, contact._name );
462
			contactUri = _doit.getContentResolver().insert(
36 by edam
- formatting: removed some double-indents on overrunning lines
463
				Contacts.People.CONTENT_URI, values );
1 by edam
Initial import
464
			id = ContentUris.parseId( contactUri );
465
			if( id <= 0 ) return;	// shouldn't happen!
466
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
467
			// try to add them to the "My Contacts" group
468
			try {
469
				Contacts.People.addToMyContactsGroup(
12 by edam
- bugfix: add contacts to the "my contacts" group didn't actually work on a real device. So we're doing it a different way.
470
					_doit.getContentResolver(), id );
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
471
			}
36 by edam
- formatting: removed some double-indents on overrunning lines
472
			catch( IllegalStateException e ) {
473
				// ignore any failure
474
			}
1 by edam
Initial import
475
476
			// update cache
39 by edam
- pulled contacts cache out in to seperate class
477
			_contactsCache.put( id, contact._name );
1 by edam
Initial import
478
479
			// update UI
480
			if( !uiInformed ) {
3 by edam
- added "all done" message
481
				_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTCREATED );
1 by edam
Initial import
482
				uiInformed = true;
483
			}
484
		}
485
486
		// update UI
487
		if( !uiInformed )
3 by edam
- added "all done" message
488
			_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTMERGED );
1 by edam
Initial import
489
490
		// import contact parts
491
		if( contact._phones != null )
492
			importContactPhones( contactUri, contact._phones );
493
		if( contact._emails != null )
494
			importContactEmails( contactUri, contact._emails );
37 by edam
- updated TODO and NEWS
495
		if( contact._addresses != null )
496
			importContactAddresses( contactUri, contact._addresses );
1 by edam
Initial import
497
	}
498
499
	private void importContactPhones( Uri contactUri,
500
			HashMap< String, ContactData.PhoneData > phones )
501
	{
502
		Long contactId = ContentUris.parseId( contactUri );
503
		Uri contactPhonesUri = Uri.withAppendedPath( contactUri,
504
				Contacts.People.Phones.CONTENT_DIRECTORY );
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
505
		Set< String > phonesKeys = phones.keySet();
7 by edam
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)
506
507
		// add phone numbers
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
508
		Iterator< String > i = phonesKeys.iterator();
1 by edam
Initial import
509
		while( i.hasNext() ) {
510
			ContactData.PhoneData phone = phones.get( i.next() );
511
512
			// we don't want to add this number if it's crap, or it already
513
			// exists (which would cause a duplicate to be created). We don't
514
			// take in to account the type when checking for duplicates. This is
515
			// intentional: types aren't really very reliable. We assume that
516
			// if the number exists at all, it doesn't need importing. Because
517
			// of this, we also can't update the cache (which we don't need to
518
			// anyway, so it's not a problem).
519
			String number = sanitisePhoneNumber( phone._number );
520
			if( number == null ) continue;
39 by edam
- pulled contacts cache out in to seperate class
521
			if( _contactsCache.hasNumber( contactId, number ) ) continue;
1 by edam
Initial import
522
523
			// add phone number
524
			ContentValues values = new ContentValues();
525
			values.put( Contacts.Phones.TYPE, phone._type );
526
			values.put( Contacts.Phones.NUMBER, phone._number );
527
			if( phone._isPreferred ) values.put( Contacts.Phones.ISPRIMARY, 1 );
528
			_doit.getContentResolver().insert( contactPhonesUri, values );
37 by edam
- updated TODO and NEWS
529
530
			// and add this address to the cache to prevent a addition of
531
			// duplicate date from another file
39 by edam
- pulled contacts cache out in to seperate class
532
			_contactsCache.addNumber( contactId, number );
7 by edam
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)
533
		}
1 by edam
Initial import
534
	}
535
536
	private void importContactEmails( Uri contactUri,
537
			HashMap< String, ContactData.EmailData > emails )
538
	{
539
		Long contactId = ContentUris.parseId( contactUri );
540
		Uri contactContactMethodsUri = Uri.withAppendedPath( contactUri,
541
				Contacts.People.ContactMethods.CONTENT_DIRECTORY );
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
542
		Set< String > emailsKeys = emails.keySet();
7 by edam
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)
543
544
		// add email addresses
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
545
		Iterator< String > i = emailsKeys.iterator();
1 by edam
Initial import
546
		while( i.hasNext() ) {
547
			ContactData.EmailData email = emails.get( i.next() );
548
37 by edam
- updated TODO and NEWS
549
			// we don't want to add this email address if it exists already or
550
			// we would introduce duplicates.
1 by edam
Initial import
551
			String address = sanitiseEmailAddress( email.getAddress() );
552
			if( address == null ) continue;
39 by edam
- pulled contacts cache out in to seperate class
553
			if( _contactsCache.hasEmail( contactId, address ) ) continue;
1 by edam
Initial import
554
555
			// add phone number
556
			ContentValues values = new ContentValues();
557
			values.put( Contacts.ContactMethods.KIND, Contacts.KIND_EMAIL );
558
			values.put( Contacts.ContactMethods.DATA, email.getAddress() );
559
			values.put( Contacts.ContactMethods.TYPE, email.getType() );
560
			if( email.isPreferred() )
561
				values.put( Contacts.ContactMethods.ISPRIMARY, 1 );
562
			_doit.getContentResolver().insert( contactContactMethodsUri,
36 by edam
- formatting: removed some double-indents on overrunning lines
563
				values );
37 by edam
- updated TODO and NEWS
564
565
			// and add this address to the cache to prevent a addition of
566
			// duplicate date from another file
39 by edam
- pulled contacts cache out in to seperate class
567
			_contactsCache.addEmail( contactId, address );
1 by edam
Initial import
568
		}
37 by edam
- updated TODO and NEWS
569
	}
570
571
	private void importContactAddresses( Uri contactUri,
572
		HashMap< String, ContactData.AddressData > addresses )
573
	{
574
		Long contactId = ContentUris.parseId( contactUri );
575
		Uri contactContactMethodsUri = Uri.withAppendedPath( contactUri,
576
				Contacts.People.ContactMethods.CONTENT_DIRECTORY );
577
		Set< String > addressesKeys = addresses.keySet();
578
579
		// add addresses
580
		Iterator< String > i = addressesKeys.iterator();
7 by edam
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)
581
		while( i.hasNext() ) {
37 by edam
- updated TODO and NEWS
582
			ContactData.AddressData address = addresses.get( i.next() );
583
584
			// we don't want to add this address if it exists already or we
585
			// would introduce duplicates
586
			if( address == null ) continue;
39 by edam
- pulled contacts cache out in to seperate class
587
			if( _contactsCache.hasAddress( contactId, address.getAddress() ) )
37 by edam
- updated TODO and NEWS
588
				continue;
589
590
			// add postal address
591
			ContentValues values = new ContentValues();
592
			values.put( Contacts.ContactMethods.KIND, Contacts.KIND_POSTAL );
593
			values.put( Contacts.ContactMethods.DATA, address.getAddress() );
594
			values.put( Contacts.ContactMethods.TYPE, address.getType() );
595
			_doit.getContentResolver().insert( contactContactMethodsUri,
596
				values );
597
598
			// and add this address to the cache to prevent a addition of
599
			// duplicate date from another file
39 by edam
- pulled contacts cache out in to seperate class
600
			_contactsCache.addAddress( contactId, address.getAddress() );
7 by edam
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)
601
		}
1 by edam
Initial import
602
	}
603
3 by edam
- added "all done" message
604
	synchronized protected void checkAbort() throws AbortImportException
1 by edam
Initial import
605
	{
606
		if( _abort ) {
607
			// stop
608
			throw new AbortImportException();
609
		}
610
	}
611
39 by edam
- pulled contacts cache out in to seperate class
612
	static public String sanitisePhoneNumber( String number )
1 by edam
Initial import
613
	{
614
		number = number.replaceAll( "[-\\(\\) ]", "" );
24 by edam
- import phone numbers even when they have no specified type (default to mobile)
615
		Pattern p = Pattern.compile( "^[\\+0-9#*]+" );
1 by edam
Initial import
616
		Matcher m = p.matcher( number );
617
		if( m.lookingAt() ) return m.group( 0 );
618
		return null;
619
	}
620
39 by edam
- pulled contacts cache out in to seperate class
621
	static public String sanitiseEmailAddress( String address )
1 by edam
Initial import
622
	{
623
		address = address.trim();
624
		Pattern p = Pattern.compile(
36 by edam
- formatting: removed some double-indents on overrunning lines
625
			"^[^ @]+@[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?(\\.[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?)+$" );
1 by edam
Initial import
626
		Matcher m = p.matcher( address );
627
		if( m.matches() ) {
628
			String[] bits = address.split( "@" );
629
			return bits[ 0 ] + "@" + bits[ 1 ].toLowerCase();
630
		}
631
		return null;
632
	}
633
}