firescript / nativescript-contacts

A nativescript module that gives access to the native contact directory.
MIT License
28 stars 32 forks source link

Possibly corrupting contacts? #72

Closed cfjedimaster closed 5 years ago

cfjedimaster commented 5 years ago

I'm working on a (dumb) little demo where I get all contacts w/o pictures and then "fix" them by adding a picture from the PlaceKitten service. My demo currently gets all contacts, filters by those w/o pictures, and at this point I stopped and wrote some temp code to test on one contact at a time.

In my test, I saw that it worked, the contact now had a kitten picture, but I noticed something odd. While the contact showed up in my phone's contacts list, I could no longer search for them.

I've now seen this twice in my testing. In my second test, I confirmed a search for the contact worked, I then modified the contact, and now I can't "find" them anymore.

Here's part of the code in question (and it's rough, was going to clean it up more):

    created() {
        this.status = 'Loading up your contacts to find those missing a picture - please stand by!';

        permissions.requestPermissions([android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS], 'I need these permissions to work with your contact.')
            .then(() => {

                var contactFields = ['name','nickname','photo'];
                contacts.getAllContacts(contactFields).then(
                    args => {

                        //get contacts w/o a picture AND with a name
                        let fixableContacts = args.data.filter(c => {
                            if(c.photo) return false;
                            if(!c.nickname && !c.name.family) return false;
                            return true;
                        });

                        //set a proper name value - we filtered out no name folks above
                        fixableContacts = fixableContacts.map(c => {
                            if(c.nickname) c.fixedName = c.nickname;
                            else if(c.name.family) c.fixedName = c.name.given + ' ' + c.name.family;
                            return c;
                        });

    console.log(fixableContacts[0]);

                        this.status = `You have ${fixableContacts.length} named contacts without pictures...`;
                        this.contacts = fixableContacts;
                        this.readyToFix = true;

                        // temp test
                        if(fixableContacts[0].fixedName === 'Susan Oliver') {
                            console.log('testing on zoe');
                            imageSource
                                .fromUrl(getRandomCatURL())
                                .then(function(src) {
                                    console.log('i got the src');
                                    fixableContacts[0].photo = src;
                                    fixableContacts[0].save();
                                    console.log('IT WORKED');
                                });

                        }
                    },
                    err => {
                        console.log("Error: " + err);
                    }
                );

            })
            .catch(e => {
                console.log('error in perms thing',e);
            });

    }

The only thing I can think of is that I modify the contacts to add a name property I can use in my display. Would adding a new field to a contact somehow break it?

jzgoda commented 5 years ago

I'm curious about a couple of things.

First, are you actually seeing your fixedName property in the updated contacts? (I might be wrong, but I didn't think that custom fields were supported.)

Second, if you remove the photo logic, do you run into the same search issue?

cfjedimaster commented 5 years ago

Hey sorry - this came in right after I left for the day.

1) I'm not seeing fixedName in the contact - I thought maybe it ended up in custom fields. 2) Do you want me to still save the record, just don't change the photo property?

cfjedimaster commented 5 years ago

FYI, these are Google Contacts. The record on contacts.google.com is fine and can be found via search.

cfjedimaster commented 5 years ago

I rebooted the phone and it fixed the issue. So as a general question/observation/thought, etc ... :)

1) What should we expect if we set an unknown property on a contact object? c.foo=1 for example? 2) Um never mind - I thought I had more thoughts. oh well.

jzgoda commented 5 years ago

So it makes perfect sense that custom properties aren't being saved to the contact, you can see this in the save function. (Although that might be a useful feature!)

As for the search issue, I'm wondering if a new ID is being assigned, and that's not getting updated in some cache that the search is looking at (this is only a theory). These lines show where the ID is being updated if the returned ID after the save is different.

Maybe check to see if the contact ID is different before and after a save?

@firescript, have you run into this issue? (I may not be the most helpful here, as the app I'm supporting is iOS only, and I haven't had any issue like this after saving.)

firescript commented 5 years ago

@jzgoda nope this hasn't happened to me either.

cfjedimaster commented 5 years ago

@jzgoda the ID thing makes sense - going to try like heck to test today. As for my 'fixedName' thing, I switched to a Vue filter.

cfjedimaster commented 5 years ago

So I'm not having luck recreating this error. I'm using this code now (ugly, sorry):

  for(var i=0;i<args.data.length;i++) {
      // randomchange mb
      if(args.data[i].id === 117) {
          console.log(args.data[i].id+' '+JSON.stringify(args.data[i].name));
          args.data[i].fixedName = "test";
          try {
              args.data[i].save();
          } catch(e) {
              console.log('error', e);
          }
          console.log('MOD THE DOC!');
      }
  }

117 is a contact record for a doctor. The catch is throwing:

[Error: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getLastPathSegment()' on a null object reference
JS:     android.content.ContentUris.parseId(ContentUris.java:85)
JS:     com.tns.Runtime.WorkerObjectOnMessageCallback(Native Method)
JS:     com.tns.Runtime.access$1700(Runtime.java:34)
JS:     com.tns.Runtime$MainThreadHandler.handleMessage(Runtime.java:455)
JS:     android.os.Handler.dispatchMessage(Handler.java:106)
JS:     android.os.Looper.loop(Looper.java:193)
JS:     android.app.ActivityThread.main(ActivityThread.java:6718)
JS:     java.lang.reflect.Method.invoke(Native Method)
JS:     com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
JS:     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)]

I don't know. I'd be fine closing this as it really doesn't feel like "your" fault. :)

jzgoda commented 5 years ago

That error is referring to this line:

// Perform the save
var results = contentResolver.applyBatch(android.provider.ContactsContract.AUTHORITY, ops),
    contactId = android.content.ContentUris.parseId(results[0].uri);

I haven't seen something like this, but I'm guessing that the applyBatch call is failing, and results doesn't have the expected result.

Maybe a race condition where the something got modified / deleted between fetching and before the save happened? :man_shrugging:

It might be best to review your code again, maybe get some smaller chunks working. Like adding a test user, fetch that user w/ the returned ID, and modify/save supported properties (such as the image). You could even break those steps into separate buttons, so you can test your searching between them.

Because I don't think the contacts are being corrupted, I'm going to close this issue. If you feel you're hitting another bug, feel free to open a new issue.

cfjedimaster commented 5 years ago

Thank you for all the help with this!