/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts

« back to all changes in this revision

Viewing changes to src/org/waxworlds/edam/importcontacts/Importer.java

  • Committer: edam
  • Date: 2011-03-19 20:33:09 UTC
  • Revision ID: edam@waxworlds.org-20110319203309-5dzfyqrxwk94jtin
- formatting: removed some double-indents on overrunning lines
- updated TODO and NEWS
- rewrote central logic of parser so it makes more sense, looks nicer and has a small optimisation (getting name and params from line only when necessary)
- optimised unnecessary mutliple converting of lines to US-ASCII
- re-wrote line extraction from vcards so that we can lookahead for v3 folded lines
- added support for v3 folded lines

Show diffs side-by-side

added added

removed removed

21
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
22
 */
23
23
 
24
 
package org.waxworlds.importcontacts;
 
24
package org.waxworlds.edam.importcontacts;
25
25
 
26
26
import java.util.HashMap;
27
27
import java.util.HashSet;
40
40
 
41
41
public class Importer extends Thread
42
42
{
43
 
        public final static int ACTION_GOBACK = 0;
44
43
        public final static int ACTION_ABORT = 1;
45
44
        public final static int ACTION_ALLDONE = 2;
46
45
 
132
131
                        if( _phones == null ) _phones = new HashMap< String, PhoneData >();
133
132
                        if( !_phones.containsKey( number ) )
134
133
                                _phones.put( number,
135
 
                                                new PhoneData( number, type, isPreferred ) );
 
134
                                        new PhoneData( number, type, isPreferred ) );
136
135
                }
137
136
 
138
137
                protected void addEmail( String email, int type, boolean isPreferred )
143
142
                }
144
143
        }
145
144
 
 
145
        @SuppressWarnings("serial")
146
146
        protected class AbortImportException extends Exception { };
147
147
 
148
148
        public Importer( Doit doit )
225
225
        {
226
226
                checkAbort();
227
227
                _doit._handler.sendMessage( Message.obtain(
228
 
                                _doit._handler, Doit.MESSAGE_ERROR, message ) );
 
228
                        _doit._handler, Doit.MESSAGE_ERROR, message ) );
229
229
                try {
230
230
                        wait();
231
231
                }
232
232
                catch( InterruptedException e ) { }
 
233
 
233
234
                // no need to check if an abortion happened during the wait, we are
234
235
                // about to finish anyway!
235
236
                finish( ACTION_ABORT );
245
246
        {
246
247
                checkAbort();
247
248
                _doit._handler.sendMessage( Message.obtain(
248
 
                                _doit._handler, Doit.MESSAGE_ERROR, message ) );
 
249
                        _doit._handler, Doit.MESSAGE_ERROR, message ) );
249
250
                try {
250
251
                        wait();
251
252
                }
252
253
                catch( InterruptedException e ) { }
 
254
 
253
255
                // no need to check if an abortion happened during the wait, we are
254
256
                // about to finish anyway!
255
257
                finish( ACTION_ABORT );
265
267
        {
266
268
                checkAbort();
267
269
                _doit._handler.sendMessage( Message.obtain(
268
 
                                _doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
 
270
                        _doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
269
271
                try {
270
272
                        wait();
271
273
                }
281
283
        {
282
284
                checkAbort();
283
285
                _doit._handler.sendMessage( Message.obtain( _doit._handler,
284
 
                                Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
 
286
                        Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
285
287
        }
286
288
 
287
289
        protected void setProgressMax( int maxProgress )
289
291
        {
290
292
                checkAbort();
291
293
                _doit._handler.sendMessage( Message.obtain(
292
 
                                _doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
293
 
                                new Integer( maxProgress ) ) );
 
294
                        _doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
 
295
                        new Integer( maxProgress ) ) );
294
296
        }
295
297
 
296
298
        protected void setTmpProgress( int tmpProgress ) throws AbortImportException
297
299
        {
298
300
                checkAbort();
299
301
                _doit._handler.sendMessage( Message.obtain(
300
 
                                _doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
301
 
                                new Integer( tmpProgress ) ) );
 
302
                        _doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
 
303
                        new Integer( tmpProgress ) ) );
302
304
        }
303
305
 
304
306
        protected void setProgress( int progress ) throws AbortImportException
305
307
        {
306
308
                checkAbort();
307
309
                _doit._handler.sendMessage( Message.obtain(
308
 
                                _doit._handler, Doit.MESSAGE_SETPROGRESS,
309
 
                                new Integer( progress ) ) );
 
310
                        _doit._handler, Doit.MESSAGE_SETPROGRESS,
 
311
                        new Integer( progress ) ) );
310
312
        }
311
313
 
312
314
        protected void finish( int action ) throws AbortImportException
315
317
                int message;
316
318
                switch( action )
317
319
                {
318
 
                case ACTION_GOBACK:             message = Doit.MESSAGE_FINISHED_GOBACK; break;
319
 
                case ACTION_ALLDONE:    message = Doit.MESSAGE_FINISHED_ALLDONE; break;
 
320
                case ACTION_ALLDONE:    message = Doit.MESSAGE_ALLDONE; break;
320
321
                default:        // fall through
321
 
                case ACTION_ABORT:              message = Doit.MESSAGE_FINISHED; break;
 
322
                case ACTION_ABORT:              message = Doit.MESSAGE_ABORT; break;
322
323
                }
323
324
                _doit._handler.sendEmptyMessage( message );
324
325
 
357
358
 
358
359
                        // ok, it exists, so do prompt
359
360
                        _doit._handler.sendMessage( Message.obtain(
360
 
                                        _doit._handler, Doit.MESSAGE_MERGEPROMPT, name ) );
 
361
                                _doit._handler, Doit.MESSAGE_MERGEPROMPT, name ) );
361
362
                        try {
362
363
                                wait();
363
364
                        }
370
371
                        if( _responseExtra == RESPONSEEXTRA_ALWAYS )
371
372
                                _mergeSetting = _response;
372
373
 
373
 
                        // recurse, with out new merge setting
 
374
                        // recurse, with our new merge setting
374
375
                        return isImportRequired( name, _response );
375
376
                }
376
377
 
406
407
 
407
408
                        // get contact's URI
408
409
                        contactUri = ContentUris.withAppendedId(
409
 
                                        Contacts.People.CONTENT_URI, id );
 
410
                                Contacts.People.CONTENT_URI, id );
410
411
 
411
412
                        // should we destroy the existing contact before importing?
412
413
                        if( _lastMergeDecision == Doit.ACTION_OVERWRITE ) {
413
414
                                _doit.getContentResolver().delete( contactUri, null, null );
414
415
                                contactUri = null;
415
416
 
416
 
                                // upate the UI
417
 
                                _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTOVERWRITTEN );
 
417
                                // update the UI
 
418
                                _doit._handler.sendEmptyMessage(
 
419
                                                Doit.MESSAGE_CONTACTOVERWRITTEN );
418
420
                                uiInformed = true;
419
421
 
420
422
                                // update cache
429
431
                        // create a new contact
430
432
                        values.put( Contacts.People.NAME, contact._name );
431
433
                        contactUri = _doit.getContentResolver().insert(
432
 
                                        Contacts.People.CONTENT_URI, values );
 
434
                                Contacts.People.CONTENT_URI, values );
433
435
                        id = ContentUris.parseId( contactUri );
434
436
                        if( id <= 0 ) return;   // shouldn't happen!
435
437
 
436
 
                        // add them to the "My Contacts" group
437
 
                        Contacts.People.addToMyContactsGroup(
 
438
                        // try to add them to the "My Contacts" group
 
439
                        try {
 
440
                                Contacts.People.addToMyContactsGroup(
438
441
                                        _doit.getContentResolver(), id );
 
442
                        }
 
443
                        catch( IllegalStateException e ) {
 
444
                                // ignore any failure
 
445
                        }
439
446
 
440
447
                        // update cache
441
448
                        _contacts.put( contact._name, id );
464
471
                Long contactId = ContentUris.parseId( contactUri );
465
472
                Uri contactPhonesUri = Uri.withAppendedPath( contactUri,
466
473
                                Contacts.People.Phones.CONTENT_DIRECTORY );
467
 
                Set phonesKeys = phones.keySet();
 
474
                Set< String > phonesKeys = phones.keySet();
468
475
 
469
476
                // add phone numbers
470
 
                Iterator i = phonesKeys.iterator();
 
477
                Iterator< String > i = phonesKeys.iterator();
471
478
                while( i.hasNext() ) {
472
479
                        ContactData.PhoneData phone = phones.get( i.next() );
473
480
 
515
522
                Long contactId = ContentUris.parseId( contactUri );
516
523
                Uri contactContactMethodsUri = Uri.withAppendedPath( contactUri,
517
524
                                Contacts.People.ContactMethods.CONTENT_DIRECTORY );
518
 
                Set emailsKeys = emails.keySet();
 
525
                Set< String > emailsKeys = emails.keySet();
519
526
 
520
527
                // add email addresses
521
 
                Iterator i = emailsKeys.iterator();
 
528
                Iterator< String > i = emailsKeys.iterator();
522
529
                while( i.hasNext() ) {
523
530
                        ContactData.EmailData email = emails.get( i.next() );
524
531
 
537
544
                        if( email.isPreferred() )
538
545
                                values.put( Contacts.ContactMethods.ISPRIMARY, 1 );
539
546
                        _doit.getContentResolver().insert( contactContactMethodsUri,
540
 
                                        values );
 
547
                                values );
541
548
                }
542
549
 
543
550
                // now add those email addresses to the cache to prevent the addition of
582
589
                // query and store map of contact names to ids
583
590
                cols = new String[] { Contacts.People._ID, Contacts.People.NAME };
584
591
                cur = _doit.managedQuery( Contacts.People.CONTENT_URI,
585
 
                                cols, null, null, null);
 
592
                        cols, null, null, null);
586
593
                if( cur.moveToFirst() ) {
587
594
                        int idCol = cur.getColumnIndex( Contacts.People._ID );
588
595
                        int nameCol = cur.getColumnIndex( Contacts.People.NAME );
595
602
                cols = new String[] { Contacts.Phones.PERSON_ID,
596
603
                                Contacts.Phones.NUMBER };
597
604
                cur = _doit.managedQuery( Contacts.Phones.CONTENT_URI,
598
 
                                cols, null, null, null);
 
605
                        cols, null, null, null);
599
606
                if( cur.moveToFirst() ) {
600
607
                        int personIdCol = cur.getColumnIndex( Contacts.Phones.PERSON_ID );
601
608
                        int numberCol = cur.getColumnIndex( Contacts.Phones.NUMBER );
622
629
                                new String[] { "" + Contacts.KIND_EMAIL }, null );
623
630
                if( cur.moveToFirst() ) {
624
631
                        int personIdCol = cur.getColumnIndex(
625
 
                                        Contacts.ContactMethods.PERSON_ID );
 
632
                                Contacts.ContactMethods.PERSON_ID );
626
633
                        int addressCol = cur.getColumnIndex(
627
 
                                        Contacts.ContactMethods.DATA );
 
634
                                Contacts.ContactMethods.DATA );
628
635
                        do {
629
636
                                Long id = cur.getLong( personIdCol );
630
637
                                String address = sanitiseEmailAddress(
631
 
                                                cur.getString( addressCol ) );
 
638
                                        cur.getString( addressCol ) );
632
639
                                if( address != null ) {
633
640
                                        HashSet< String > addresses = _contactEmails.get( id );
634
641
                                        if( addresses == null ) {
644
651
        private String sanitisePhoneNumber( String number )
645
652
        {
646
653
                number = number.replaceAll( "[-\\(\\) ]", "" );
647
 
                Pattern p = Pattern.compile( "^\\+?[0-9]+" );
 
654
                Pattern p = Pattern.compile( "^[\\+0-9#*]+" );
648
655
                Matcher m = p.matcher( number );
649
656
                if( m.lookingAt() ) return m.group( 0 );
650
657
                return null;
654
661
        {
655
662
                address = address.trim();
656
663
                Pattern p = Pattern.compile(
657
 
                                "^[^ @]+@[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?(\\.[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?)+$" );
 
664
                        "^[^ @]+@[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?(\\.[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?)+$" );
658
665
                Matcher m = p.matcher( address );
659
666
                if( m.matches() ) {
660
667
                        String[] bits = address.split( "@" );