/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/importcontacts/Importer.java

  • Committer: edam
  • Date: 2009-01-11 12:58:54 UTC
  • Revision ID: edam@waxworlds.org-20090111125854-u8ofzso4jatk12me
- added "all done" message
- rewrote Importer.finish() to make the exit process more consistent
- moved Doit's message definitions to Doit
- ensure the importer is destroyed in Doit.onPause()
- only show the toaster popup if a) there is an importer to abort, and b) the abort actually did something (i.e., it's not already aborted)
- bugfix: added some checks for abortion to the Importer after wait()ing after a dialog. Importer.wake() now alsy does a notify() to break out of dialog waits.
- also, made Importer.checkAbort() protected, so it can be checked from specific importers as desired

Show diffs side-by-side

added added

removed removed

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
 
 
24
 
package org.waxworlds.edam.importcontacts;
 
1
package org.waxworlds.importcontacts;
25
2
 
26
3
import java.util.HashMap;
27
4
import java.util.HashSet;
40
17
 
41
18
public class Importer extends Thread
42
19
{
 
20
        public final static int ACTION_GOBACK = 0;
43
21
        public final static int ACTION_ABORT = 1;
44
22
        public final static int ACTION_ALLDONE = 2;
45
23
 
131
109
                        if( _phones == null ) _phones = new HashMap< String, PhoneData >();
132
110
                        if( !_phones.containsKey( number ) )
133
111
                                _phones.put( number,
134
 
                                        new PhoneData( number, type, isPreferred ) );
 
112
                                                new PhoneData( number, type, isPreferred ) );
135
113
                }
136
114
 
137
115
                protected void addEmail( String email, int type, boolean isPreferred )
142
120
                }
143
121
        }
144
122
 
145
 
        @SuppressWarnings("serial")
146
123
        protected class AbortImportException extends Exception { };
147
124
 
148
125
        public Importer( Doit doit )
150
127
                _doit = doit;
151
128
 
152
129
                SharedPreferences prefs = getSharedPreferences();
153
 
                _mergeSetting = prefs.getInt( "merge_setting", Doit.ACTION_PROMPT );
 
130
                _mergeSetting = prefs.getInt( "merge_setting", 0 );
154
131
        }
155
132
 
156
133
        @Override
225
202
        {
226
203
                checkAbort();
227
204
                _doit._handler.sendMessage( Message.obtain(
228
 
                        _doit._handler, Doit.MESSAGE_ERROR, message ) );
 
205
                                _doit._handler, Doit.MESSAGE_ERROR, message ) );
229
206
                try {
230
207
                        wait();
231
208
                }
232
209
                catch( InterruptedException e ) { }
233
 
 
234
210
                // no need to check if an abortion happened during the wait, we are
235
211
                // about to finish anyway!
236
212
                finish( ACTION_ABORT );
246
222
        {
247
223
                checkAbort();
248
224
                _doit._handler.sendMessage( Message.obtain(
249
 
                        _doit._handler, Doit.MESSAGE_ERROR, message ) );
 
225
                                _doit._handler, Doit.MESSAGE_ERROR, message ) );
250
226
                try {
251
227
                        wait();
252
228
                }
253
229
                catch( InterruptedException e ) { }
254
 
 
255
230
                // no need to check if an abortion happened during the wait, we are
256
231
                // about to finish anyway!
257
232
                finish( ACTION_ABORT );
267
242
        {
268
243
                checkAbort();
269
244
                _doit._handler.sendMessage( Message.obtain(
270
 
                        _doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
 
245
                                _doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
271
246
                try {
272
247
                        wait();
273
248
                }
283
258
        {
284
259
                checkAbort();
285
260
                _doit._handler.sendMessage( Message.obtain( _doit._handler,
286
 
                        Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
 
261
                                Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
287
262
        }
288
263
 
289
264
        protected void setProgressMax( int maxProgress )
291
266
        {
292
267
                checkAbort();
293
268
                _doit._handler.sendMessage( Message.obtain(
294
 
                        _doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
295
 
                        new Integer( maxProgress ) ) );
 
269
                                _doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
 
270
                                new Integer( maxProgress ) ) );
296
271
        }
297
272
 
298
273
        protected void setTmpProgress( int tmpProgress ) throws AbortImportException
299
274
        {
300
275
                checkAbort();
301
276
                _doit._handler.sendMessage( Message.obtain(
302
 
                        _doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
303
 
                        new Integer( tmpProgress ) ) );
 
277
                                _doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
 
278
                                new Integer( tmpProgress ) ) );
304
279
        }
305
280
 
306
281
        protected void setProgress( int progress ) throws AbortImportException
307
282
        {
308
283
                checkAbort();
309
284
                _doit._handler.sendMessage( Message.obtain(
310
 
                        _doit._handler, Doit.MESSAGE_SETPROGRESS,
311
 
                        new Integer( progress ) ) );
 
285
                                _doit._handler, Doit.MESSAGE_SETPROGRESS,
 
286
                                new Integer( progress ) ) );
312
287
        }
313
288
 
314
289
        protected void finish( int action ) throws AbortImportException
317
292
                int message;
318
293
                switch( action )
319
294
                {
320
 
                case ACTION_ALLDONE:    message = Doit.MESSAGE_ALLDONE; break;
 
295
                case ACTION_GOBACK:             message = Doit.MESSAGE_FINISHED_GOBACK; break;
 
296
                case ACTION_ALLDONE:    message = Doit.MESSAGE_FINISHED_ALLDONE; break;
321
297
                default:        // fall through
322
 
                case ACTION_ABORT:              message = Doit.MESSAGE_ABORT; break;
 
298
                case ACTION_ABORT:              message = Doit.MESSAGE_FINISHED; break;
323
299
                }
324
300
                _doit._handler.sendEmptyMessage( message );
325
301
 
347
323
                // handle special cases
348
324
                switch( mergeSetting )
349
325
                {
350
 
                case Doit.ACTION_KEEP:
 
326
                case R.id.merge_keep:
351
327
                        // if we keep contacts on duplicate, we better check for one
352
328
                        return !_contacts.containsKey( name );
353
329
 
354
 
                case Doit.ACTION_PROMPT:
 
330
                case R.id.merge_prompt:
355
331
                        // if we are prompting on duplicate, we better check for one
356
332
                        if( !_contacts.containsKey( name ) )
357
333
                                return true;
358
334
 
359
335
                        // ok, it exists, so do prompt
360
336
                        _doit._handler.sendMessage( Message.obtain(
361
 
                                _doit._handler, Doit.MESSAGE_MERGEPROMPT, name ) );
 
337
                                        _doit._handler, Doit.MESSAGE_MERGEPROMPT, name ) );
362
338
                        try {
363
339
                                wait();
364
340
                        }
371
347
                        if( _responseExtra == RESPONSEEXTRA_ALWAYS )
372
348
                                _mergeSetting = _response;
373
349
 
374
 
                        // recurse, with our new merge setting
 
350
                        // recurse, with out new merge setting
375
351
                        return isImportRequired( name, _response );
376
352
                }
377
353
 
403
379
                if( ( id = (Long)_contacts.get( contact._name ) ) != null )
404
380
                {
405
381
                        // should we skip this import altogether?
406
 
                        if( _lastMergeDecision == Doit.ACTION_KEEP ) return;
 
382
                        if( _lastMergeDecision == R.id.merge_keep ) return;
407
383
 
408
384
                        // get contact's URI
409
385
                        contactUri = ContentUris.withAppendedId(
410
 
                                Contacts.People.CONTENT_URI, id );
 
386
                                        Contacts.People.CONTENT_URI, id );
411
387
 
412
388
                        // should we destroy the existing contact before importing?
413
 
                        if( _lastMergeDecision == Doit.ACTION_OVERWRITE ) {
 
389
                        if( _lastMergeDecision == R.id.merge_overwrite ) {
414
390
                                _doit.getContentResolver().delete( contactUri, null, null );
415
391
                                contactUri = null;
416
392
 
417
 
                                // update the UI
418
 
                                _doit._handler.sendEmptyMessage(
419
 
                                                Doit.MESSAGE_CONTACTOVERWRITTEN );
 
393
                                // upate the UI
 
394
                                _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTOVERWRITTEN );
420
395
                                uiInformed = true;
421
396
 
422
397
                                // update cache
431
406
                        // create a new contact
432
407
                        values.put( Contacts.People.NAME, contact._name );
433
408
                        contactUri = _doit.getContentResolver().insert(
434
 
                                Contacts.People.CONTENT_URI, values );
 
409
                                        Contacts.People.CONTENT_URI, values );
435
410
                        id = ContentUris.parseId( contactUri );
436
411
                        if( id <= 0 ) return;   // shouldn't happen!
437
412
 
438
 
                        // try to add them to the "My Contacts" group
439
 
                        try {
440
 
                                Contacts.People.addToMyContactsGroup(
441
 
                                        _doit.getContentResolver(), id );
442
 
                        }
443
 
                        catch( IllegalStateException e ) {
444
 
                                // ignore any failure
445
 
                        }
 
413
                        // add them to the "My Contacts" group
 
414
                        Contacts.People.addToGroup(
 
415
                                        _doit.getContentResolver(), id,
 
416
                                        Contacts.Groups.GROUP_MY_CONTACTS );
446
417
 
447
418
                        // update cache
448
419
                        _contacts.put( contact._name, id );
471
442
                Long contactId = ContentUris.parseId( contactUri );
472
443
                Uri contactPhonesUri = Uri.withAppendedPath( contactUri,
473
444
                                Contacts.People.Phones.CONTENT_DIRECTORY );
474
 
                Set< String > phonesKeys = phones.keySet();
475
445
 
476
446
                // add phone numbers
477
 
                Iterator< String > i = phonesKeys.iterator();
 
447
                Set phonesKeys = phones.keySet();
 
448
                Iterator i = phonesKeys.iterator();
478
449
                while( i.hasNext() ) {
479
450
                        ContactData.PhoneData phone = phones.get( i.next() );
480
451
 
497
468
                        if( phone._isPreferred ) values.put( Contacts.Phones.ISPRIMARY, 1 );
498
469
                        _doit.getContentResolver().insert( contactPhonesUri, values );
499
470
                }
500
 
 
501
 
                // now add those phone numbers to the cache to prevent the addition of
502
 
                // duplicate data from another file
503
 
                i = phonesKeys.iterator();
504
 
                while( i.hasNext() ) {
505
 
                        ContactData.PhoneData phone = phones.get( i.next() );
506
 
 
507
 
                        String number = sanitisePhoneNumber( phone._number );
508
 
                        if( number != null ) {
509
 
                                HashSet< String > numbers = _contactNumbers.get( contactId );
510
 
                                if( numbers == null ) {
511
 
                                        _contactNumbers.put( contactId, new HashSet< String >() );
512
 
                                        numbers = _contactNumbers.get( contactId );
513
 
                                }
514
 
                                numbers.add( number );
515
 
                        }
516
 
                }
517
471
        }
518
472
 
519
473
        private void importContactEmails( Uri contactUri,
522
476
                Long contactId = ContentUris.parseId( contactUri );
523
477
                Uri contactContactMethodsUri = Uri.withAppendedPath( contactUri,
524
478
                                Contacts.People.ContactMethods.CONTENT_DIRECTORY );
525
 
                Set< String > emailsKeys = emails.keySet();
526
479
 
527
 
                // add email addresses
528
 
                Iterator< String > i = emailsKeys.iterator();
 
480
                // add phone numbers
 
481
                Set emailsKeys = emails.keySet();
 
482
                Iterator i = emailsKeys.iterator();
529
483
                while( i.hasNext() ) {
530
484
                        ContactData.EmailData email = emails.get( i.next() );
531
485
 
544
498
                        if( email.isPreferred() )
545
499
                                values.put( Contacts.ContactMethods.ISPRIMARY, 1 );
546
500
                        _doit.getContentResolver().insert( contactContactMethodsUri,
547
 
                                values );
548
 
                }
549
 
 
550
 
                // now add those email addresses to the cache to prevent the addition of
551
 
                // duplicate data from another file
552
 
                i = emailsKeys.iterator();
553
 
                while( i.hasNext() ) {
554
 
                        ContactData.EmailData email = emails.get( i.next() );
555
 
 
556
 
                        String address = sanitiseEmailAddress( email.getAddress() );
557
 
                        if( address != null ) {
558
 
                                HashSet< String > addresses = _contactEmails.get( contactId );
559
 
                                if( addresses == null ) {
560
 
                                        _contactEmails.put( contactId, new HashSet< String >() );
561
 
                                        addresses = _contactEmails.get( contactId );
562
 
                                }
563
 
                                addresses.add( address );
564
 
                        }
 
501
                                        values );
565
502
                }
566
503
        }
567
504
 
589
526
                // query and store map of contact names to ids
590
527
                cols = new String[] { Contacts.People._ID, Contacts.People.NAME };
591
528
                cur = _doit.managedQuery( Contacts.People.CONTENT_URI,
592
 
                        cols, null, null, null);
 
529
                                cols, null, null, null);
593
530
                if( cur.moveToFirst() ) {
594
531
                        int idCol = cur.getColumnIndex( Contacts.People._ID );
595
532
                        int nameCol = cur.getColumnIndex( Contacts.People.NAME );
602
539
                cols = new String[] { Contacts.Phones.PERSON_ID,
603
540
                                Contacts.Phones.NUMBER };
604
541
                cur = _doit.managedQuery( Contacts.Phones.CONTENT_URI,
605
 
                        cols, null, null, null);
 
542
                                cols, null, null, null);
606
543
                if( cur.moveToFirst() ) {
607
544
                        int personIdCol = cur.getColumnIndex( Contacts.Phones.PERSON_ID );
608
545
                        int numberCol = cur.getColumnIndex( Contacts.Phones.NUMBER );
629
566
                                new String[] { "" + Contacts.KIND_EMAIL }, null );
630
567
                if( cur.moveToFirst() ) {
631
568
                        int personIdCol = cur.getColumnIndex(
632
 
                                Contacts.ContactMethods.PERSON_ID );
 
569
                                        Contacts.ContactMethods.PERSON_ID );
633
570
                        int addressCol = cur.getColumnIndex(
634
 
                                Contacts.ContactMethods.DATA );
 
571
                                        Contacts.ContactMethods.DATA );
635
572
                        do {
636
573
                                Long id = cur.getLong( personIdCol );
637
574
                                String address = sanitiseEmailAddress(
638
 
                                        cur.getString( addressCol ) );
 
575
                                                cur.getString( addressCol ) );
639
576
                                if( address != null ) {
640
577
                                        HashSet< String > addresses = _contactEmails.get( id );
641
578
                                        if( addresses == null ) {
651
588
        private String sanitisePhoneNumber( String number )
652
589
        {
653
590
                number = number.replaceAll( "[-\\(\\) ]", "" );
654
 
                Pattern p = Pattern.compile( "^[\\+0-9#*]+" );
 
591
                Pattern p = Pattern.compile( "^\\+?[0-9]+" );
655
592
                Matcher m = p.matcher( number );
656
593
                if( m.lookingAt() ) return m.group( 0 );
657
594
                return null;
661
598
        {
662
599
                address = address.trim();
663
600
                Pattern p = Pattern.compile(
664
 
                        "^[^ @]+@[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?(\\.[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?)+$" );
 
601
                                "^[^ @]+@[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?(\\.[a-zA-Z]([-a-zA-Z0-9]*[a-zA-z0-9])?)+$" );
665
602
                Matcher m = p.matcher( address );
666
603
                if( m.matches() ) {
667
604
                        String[] bits = address.split( "@" );