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

  • Committer: edam
  • Date: 2012-12-19 17:50:33 UTC
  • Revision ID: tim@ed.am-20121219175033-61acsxzjulqpnian
made contacts backend throw exceptions when it can't create contacts on the device; specified Locale in lower/upper case conversions; stripped old Contacts types from Importer (and replaced with our own types, which are now converted in the backend; switched using Integer() constructors to Integer.valueOf(); rewrote the main importer routine a bit

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import java.util.HashMap;
28
28
import java.util.HashSet;
29
29
import java.util.Iterator;
 
30
import java.util.Locale;
30
31
import java.util.Set;
31
32
import java.util.regex.Matcher;
32
33
import java.util.regex.Pattern;
33
34
 
 
35
import am.ed.importcontacts.Backend.ContactCreationException;
34
36
import android.content.SharedPreferences;
35
37
import android.os.Message;
36
 
import android.provider.Contacts.PhonesColumns;
37
38
 
38
39
public class Importer extends Thread
39
40
{
61
62
         */
62
63
        public class ContactData
63
64
        {
 
65
                public final static int TYPE_HOME = 0;
 
66
                public final static int TYPE_WORK = 1;
 
67
                public final static int TYPE_MOBILE = 2;        // only used with phones
 
68
                public final static int TYPE_FAX_HOME = 3;      // only used with phones
 
69
                public final static int TYPE_FAX_WORK = 4;      // only used with phones
 
70
                public final static int TYPE_PAGER = 5;         // only used with phones
 
71
 
64
72
                class TypeDetail
65
73
                {
66
74
                        protected int _type;
224
232
                                        new PreferredDetail( type, false ) );
225
233
 
226
234
                        final Set< Integer > non_voice_types = new HashSet< Integer >(
227
 
                                Arrays.asList( PhonesColumns.TYPE_FAX_HOME,
228
 
                                        PhonesColumns.TYPE_FAX_WORK, PhonesColumns.TYPE_PAGER ) );
 
235
                                Arrays.asList( TYPE_FAX_HOME, TYPE_FAX_WORK, TYPE_PAGER ) );
229
236
 
230
237
                        // if this is the first number added, or it's a preferred number
231
238
                        // and the current primary number isn't, or this number is on equal
392
399
                        Matcher m = p.matcher( email );
393
400
                        if( m.matches() ) {
394
401
                                String[] bits = email.split( "@" );
395
 
                                return bits[ 0 ] + "@" + bits[ 1 ].toLowerCase();
 
402
                                return bits[ 0 ] + "@" + bits[ 1 ].toLowerCase( Locale.US );
396
403
                        }
397
404
                        return null;
398
405
                }
558
565
                checkAbort();
559
566
                _doit._handler.sendMessage( Message.obtain(
560
567
                        _doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
561
 
                        new Integer( max_progress ) ) );
 
568
                        Integer.valueOf( max_progress ) ) );
562
569
        }
563
570
 
564
571
        protected void setTmpProgress( int tmp_progress )
567
574
                checkAbort();
568
575
                _doit._handler.sendMessage( Message.obtain(
569
576
                        _doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
570
 
                        new Integer( tmp_progress ) ) );
 
577
                        Integer.valueOf( tmp_progress ) ) );
571
578
        }
572
579
 
573
580
        protected void setProgress( int progress ) throws AbortImportException
575
582
                checkAbort();
576
583
                _doit._handler.sendMessage( Message.obtain(
577
584
                        _doit._handler, Doit.MESSAGE_SETPROGRESS,
578
 
                        new Integer( progress ) ) );
 
585
                        Integer.valueOf( progress ) ) );
579
586
        }
580
587
 
581
588
        protected void finish( int action ) throws AbortImportException
599
606
                return _doit.getText( res );
600
607
        }
601
608
 
602
 
        synchronized private boolean checkForDuplicate(
603
 
                ContactsCache.CacheIdentifier cache_identifier, int merge_setting )
604
 
                throws AbortImportException
 
609
        /**
 
610
         * Should we skip a contact, given whether it exists or not and the current
 
611
         * merge setting?  This routine handles throwing up a prompt, if required.
 
612
         * @param contact_detail the display name of the contact
 
613
         * @param exists true if this contact matches one in the cache
 
614
         * @param merge_setting the merge setting to use
 
615
         * @return true if the contact should be skipped outright
 
616
         * @throws AbortImportException
 
617
         */
 
618
        synchronized private boolean shouldWeSkipContact( String contact_detail,
 
619
                boolean exists, int merge_setting ) throws AbortImportException
605
620
        {
606
621
                _last_merge_decision = merge_setting;
607
622
 
608
 
                // it is ok to use contact.getCacheIdentifier(). The contact has already
609
 
                // been finalised, which means a valid cache identifier will have been
610
 
                // created for it (or it would have been skipped)
611
 
 
612
623
                // handle special cases
613
624
                switch( merge_setting )
614
625
                {
615
626
                case Doit.ACTION_KEEP:
616
 
                        // if we keep contacts on duplicate, we better check for one
617
 
                        return !_contacts_cache.canLookup( cache_identifier );
 
627
                        // if we are skipping on a duplicate, check for one
 
628
                        return exists;
618
629
 
619
630
                case Doit.ACTION_PROMPT:
620
 
                        // if we are prompting on duplicate, we better check for one and if
621
 
                        // the contact doesn'te exist, we want to import it
622
 
                        if( !_contacts_cache.canLookup( cache_identifier ) )
623
 
                                return true;
 
631
                        // if we are prompting on duplicate, then we can say that we won't
 
632
                        // skip if there isn't one
 
633
                        if( !exists ) return false;
624
634
 
625
 
                        // ok, it exists, so do prompt
 
635
                        // ok, duplicate exists, so do prompt
626
636
                        _doit._handler.sendMessage( Message.obtain( _doit._handler,
627
 
                                Doit.MESSAGE_MERGEPROMPT, cache_identifier.getDetail() ) );
 
637
                                Doit.MESSAGE_MERGEPROMPT, contact_detail ) );
628
638
                        try {
629
639
                                wait();
630
640
                        }
638
648
                                _merge_setting = _response;
639
649
 
640
650
                        // recurse, with our new merge setting
641
 
                        return checkForDuplicate( cache_identifier, _response );
 
651
                        return shouldWeSkipContact( contact_detail, exists, _response );
642
652
                }
643
653
 
644
 
                // for all other cases (either overwriting or merging) we will need the
645
 
                // imported data
646
 
                return true;
 
654
                // for all other cases (either overwriting or merging) we don't skip
 
655
                return false;
647
656
        }
648
657
 
649
658
        protected void skipContact() throws AbortImportException
650
659
        {
651
660
                checkAbort();
 
661
 
 
662
                // show that we're skipping a new contact
652
663
                _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
653
664
        }
654
665
 
663
674
                ContactsCache.CacheIdentifier cache_identifier =
664
675
                        contact.getCacheIdentifier();
665
676
 
666
 
                // check to see if this contact is a duplicate and should be skipped
667
 
                if( !checkForDuplicate( cache_identifier, _merge_setting ) ) {
668
 
                        skipContact();
669
 
                        return;
670
 
                }
671
 
 
672
677
//              if( !showContinue( "====[ IMPORTING ]====\n: " + contact._name ) )
673
678
//                      finish( ACTION_ABORT );
674
679
 
675
 
                // keep track of whether we've informed the UI of what we're doing
676
 
                boolean ui_informed = false;
677
 
 
678
680
                // attempt to lookup the id of an existing contact in the cache with
679
681
                // this contact data's cache identifier
680
682
                Long id = (Long)_contacts_cache.lookup( cache_identifier );
681
683
 
682
 
                // does contact exist already?
683
 
                if( id != null )
684
 
                {
685
 
                        // should we skip this import altogether?
686
 
                        if( _last_merge_decision == Doit.ACTION_KEEP ) return;
687
 
 
688
 
                        // should we destroy the existing contact before importing?
689
 
                        if( _last_merge_decision == Doit.ACTION_OVERWRITE )
 
684
                // check to see if this contact should be skipped
 
685
                if( shouldWeSkipContact( cache_identifier.getDetail(), id != null,
 
686
                        _merge_setting ) )
 
687
                {
 
688
                        // show that we're skipping a contact
 
689
                        _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
 
690
                        return;
 
691
                }
 
692
 
 
693
                // if a contact exists, and we're overwriting, destroy the existing
 
694
                // contact before importing
 
695
                boolean contact_deleted = false;
 
696
                if( id != null && _last_merge_decision == Doit.ACTION_OVERWRITE )
 
697
                {
 
698
                        contact_deleted = true;
 
699
 
 
700
                        // remove from device
 
701
                        _backend.deleteContact( id );
 
702
 
 
703
                        // update cache
 
704
                        _contacts_cache.removeLookup( cache_identifier );
 
705
                        _contacts_cache.removeAssociatedData( id );
 
706
 
 
707
                        // show that we're overwriting a contact
 
708
                        _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTOVERWRITTEN );
 
709
 
 
710
                        // discard the contact id
 
711
                        id = null;
 
712
                }
 
713
 
 
714
                try {
 
715
                        // if we don't have a contact id yet (or we did, but we destroyed it
 
716
                        // when we deleted the contact), we'll have to create a new contact
 
717
                        if( id == null )
690
718
                        {
691
 
                                // remove from device
692
 
                                _backend.deleteContact( id );
 
719
                                // create a new contact
 
720
                                id = _backend.addContact( contact._name );
693
721
 
694
722
                                // update cache
695
 
                                _contacts_cache.removeLookup( cache_identifier );
696
 
                                _contacts_cache.removeAssociatedData( id );
697
 
 
698
 
                                // show that we're overwriting a contact
699
 
                                _doit._handler.sendEmptyMessage(
700
 
                                                Doit.MESSAGE_CONTACTOVERWRITTEN );
701
 
                                ui_informed = true;
702
 
 
703
 
                                // discard the contact id
704
 
                                id = null;
 
723
                                _contacts_cache.addLookup( cache_identifier, id );
 
724
 
 
725
                                // if we haven't already shown that we're overwriting a contact,
 
726
                                // show that we're creating a new contact
 
727
                                if( !contact_deleted )
 
728
                                        _doit._handler.sendEmptyMessage(
 
729
                                                Doit.MESSAGE_CONTACTCREATED );
705
730
                        }
 
731
                        else
 
732
                                // show that we're merging with an existing contact
 
733
                                _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTMERGED );
 
734
 
 
735
                        // import contact parts
 
736
                        if( contact.hasNumbers() )
 
737
                                importContactPhones( id, contact.getNumbers() );
 
738
                        if( contact.hasEmails() )
 
739
                                importContactEmails( id, contact.getEmails() );
 
740
                        if( contact.hasAddresses() )
 
741
                                importContactAddresses( id, contact.getAddresses() );
 
742
                        if( contact.hasOrganisations() )
 
743
                                importContactOrganisations( id, contact.getOrganisations() );
706
744
                }
707
 
 
708
 
                // if we don't have a contact id yet (or we did, but we destroyed it
709
 
                // when we deleted the contact), we'll have to create a new contact
710
 
                if( id == null )
 
745
                catch( Backend.ContactCreationException e )
711
746
                {
712
 
                        // create a new contact
713
 
                        id = _backend.addContact( contact._name );
714
 
                        if( id == null )
715
 
                                showError( R.string.error_unabletoaddcontact );
716
 
 
717
 
                        // update cache
718
 
                        _contacts_cache.addLookup( cache_identifier, id );
719
 
 
720
 
                        // if we haven't already shown that we're overwriting a contact,
721
 
                        // show that we're creating a new contact
722
 
                        if( !ui_informed ) {
723
 
                                _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTCREATED );
724
 
                                ui_informed = true;
725
 
                        }
 
747
                        showError( R.string.error_unabletoaddcontact );
726
748
                }
727
 
 
728
 
                // if we haven't already shown that we're overwriting or creating a
729
 
                // contact, show that we're merging a contact
730
 
                if( !ui_informed )
731
 
                        _doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTMERGED );
732
 
 
733
 
                // import contact parts
734
 
                if( contact.hasNumbers() )
735
 
                        importContactPhones( id, contact.getNumbers() );
736
 
                if( contact.hasEmails() )
737
 
                        importContactEmails( id, contact.getEmails() );
738
 
                if( contact.hasAddresses() )
739
 
                        importContactAddresses( id, contact.getAddresses() );
740
 
                if( contact.hasOrganisations() )
741
 
                        importContactOrganisations( id, contact.getOrganisations() );
742
749
        }
743
750
 
744
751
        private void importContactPhones( Long id,
745
 
                        HashMap< String, ContactData.PreferredDetail > datas )
 
752
                HashMap< String, ContactData.PreferredDetail > datas )
 
753
                throws ContactCreationException
746
754
        {
747
755
                // add phone numbers
748
756
                Set< String > datas_keys = datas.keySet();
771
779
        }
772
780
 
773
781
        private void importContactEmails( Long id,
774
 
                        HashMap< String, ContactData.PreferredDetail > datas )
 
782
                HashMap< String, ContactData.PreferredDetail > datas )
 
783
                throws ContactCreationException
775
784
        {
776
785
                // add email addresses
777
786
                Set< String > datas_keys = datas.keySet();
796
805
 
797
806
        private void importContactAddresses( Long id,
798
807
                HashMap< String, ContactData.TypeDetail > datas )
 
808
                throws ContactCreationException
799
809
        {
800
810
                // add addresses
801
811
                Set< String > datas_keys = datas.keySet();
820
830
 
821
831
        private void importContactOrganisations( Long id,
822
832
                HashMap< String, ContactData.ExtraDetail > datas )
 
833
                throws ContactCreationException
823
834
        {
824
835
                // add addresses
825
836
                Set< String > datas_keys = datas.keySet();