Uploaded image for project: 'Apache Cordova'
  1. Apache Cordova
  2. CB-6761

Calling a function the first time no callbacks are being executed

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Blocker
    • Resolution: Fixed
    • Affects Version/s: 3.5.0
    • Fix Version/s: None
    • Component/s: Android, CordovaJS
    • Environment:

      Nexus 5, Android 4.4.2

      Description

      Using different functions the same error occurs. Calling a function the first time no callbacks are being executed. There is no error in the log. Using the same function again for a second call, everything works fine. Now the first call is being executed as well and I receive the callback from the first excution.
      It looks like something is wainting. It is odd that the second call works and executes the first call as well.

      I found this bug on this calls:

      • window.requestFileSystem(LocalFileSystem.PERSISTENT, 3097152, gotFS, fail);
      • navigator.camera.getPicture(onSuccessCapturePhoto, onFailCamera, { targetWidth: 1200, targetHeight: 1200, quality: 55, destinationType: Camera.DestinationType.FILE_URI, saveToPhotoAlbum: true, correctOrientation:true}

        );

      • navigator.camera.getPicture(onSuccessGetPhoto, onFailCamera, { targetWidth: 1000,targetHeight: 1000, quality: 65, destinationType: Camera.DestinationType.FILE_URI , saveToPhotoAlbum: false , sourceType: Camera.PictureSourceType.SAVEDPHOTOALBUM, correctOrientation:true}

        );

      1. sidemenu.tar.gz
        1.45 MB
        Zhang Zengbo

        Issue Links

          Activity

          Hide
          iclelland Ian Clelland added a comment -

          Do you have a small test case that shows this behaviour? I haven't been seeing it on any of my test devices. (And I think that mobile spec would surface a problem like this)

          Show
          iclelland Ian Clelland added a comment - Do you have a small test case that shows this behaviour? I haven't been seeing it on any of my test devices. (And I think that mobile spec would surface a problem like this)
          Hide
          cgrassick Clayton Grassick added a comment -

          I've narrowed this problem (it is the same as CB-6667) to the OnlineEventsBridgeMode. This depends on the online flag flipping each time, but I see a reset() being called on it which messes up the parity. That means that the next notification fails to trigger a native event since the online status has not changed.

          When reset is called, online is false, but setNetworkAvailable is true. So the next time a notifyOfFlush(true) is called, online becomes true and no event is triggered.

          No idea yet why reset is called there. The concept of having online and setNetworkAvailable initially different is good, unless notifyOfFlush is called first. Looking further...

          Show
          cgrassick Clayton Grassick added a comment - I've narrowed this problem (it is the same as CB-6667 ) to the OnlineEventsBridgeMode. This depends on the online flag flipping each time, but I see a reset() being called on it which messes up the parity. That means that the next notification fails to trigger a native event since the online status has not changed. When reset is called, online is false, but setNetworkAvailable is true. So the next time a notifyOfFlush(true) is called, online becomes true and no event is triggered. No idea yet why reset is called there. The concept of having online and setNetworkAvailable initially different is good, unless notifyOfFlush is called first. Looking further...
          Hide
          iclelland Ian Clelland added a comment -

          Thanks for diving into this, Clayton.

          This code was in response to a previous issue (CB-6047) that started coming up with Android 4.3 (Jellybean MR2). I'm looking into why it looks like that, and how it could get out of sync.

          Show
          iclelland Ian Clelland added a comment - Thanks for diving into this, Clayton. This code was in response to a previous issue ( CB-6047 ) that started coming up with Android 4.3 (Jellybean MR2). I'm looking into why it looks like that, and how it could get out of sync.
          Hide
          cgrassick Clayton Grassick added a comment -

          Aha: If the initial actual online/offline state is false, then the following sequence happens:

          reset puts the online flag = false and the actual online state to true.

          This triggers an online event, which calls popAndEncode and thus notifyOfFlush(true).

          This sets online flag = true, which means that no events will ever be triggered again.

          A safer way might be to set online true if there are messages pending, and false if not. reset would set it to offline. Then only listen to online events and in the flush event, set online back to false.

          Show
          cgrassick Clayton Grassick added a comment - Aha: If the initial actual online/offline state is false, then the following sequence happens: reset puts the online flag = false and the actual online state to true. This triggers an online event, which calls popAndEncode and thus notifyOfFlush(true). This sets online flag = true, which means that no events will ever be triggered again. A safer way might be to set online true if there are messages pending, and false if not. reset would set it to offline. Then only listen to online events and in the flush event, set online back to false.
          Hide
          cgrassick Clayton Grassick added a comment -

          Also, my release is completely blocked by this issue: Is there an official way to use a different bridge mode without hacks?

          Show
          cgrassick Clayton Grassick added a comment - Also, my release is completely blocked by this issue: Is there an official way to use a different bridge mode without hacks?
          Hide
          iclelland Ian Clelland added a comment -

          Well, on Android, you can call cordova.exec.setNativeToJsBridgeMode() – it's not a hack (but not very well documented either).

          The only issue with this is that you have to wait for Cordova to initialize before you can call it. If you need it to be set by default, you have to edit the default bridge mode both in cordova.js and in org.apache.cordova.NativeToJsMessageQueue

          Show
          iclelland Ian Clelland added a comment - Well, on Android, you can call cordova.exec.setNativeToJsBridgeMode() – it's not a hack (but not very well documented either). The only issue with this is that you have to wait for Cordova to initialize before you can call it. If you need it to be set by default, you have to edit the default bridge mode both in cordova.js and in org.apache.cordova.NativeToJsMessageQueue
          Hide
          cgrassick Clayton Grassick added a comment -

          Changing bridge modes didn't work out so good. There's a reason we are using OnlineEvents.

          I did get myself out of the pickle by changing the code in NativeToJsMessageQueue.java to:

              /** Uses online/offline events to tell the JS when to poll for messages. */
              private class OnlineEventsBridgeMode extends BridgeMode {
                  final Runnable runnable = new Runnable() {
                      public void run() {
                          if (!queue.isEmpty()) {
                              webView.setNetworkAvailable(true);
                          }
                      }                
                  };
          
                  final Runnable runnableFlush = new Runnable() {
                      public void run() {
                          webView.setNetworkAvailable(false);
                      }                
                  };
                  @Override void reset() {
                      webView.setNetworkAvailable(false);
                  }
                  @Override void onNativeToJsMessageAvailable() {
                      cordova.getActivity().runOnUiThread(runnable);
                  }
                  // Track when online/offline events are fired so that we don't fire excess events.
                  @Override void notifyOfFlush(boolean fromOnlineEvent) {
                      if (fromOnlineEvent) {
                          cordova.getActivity().runOnUiThread(runnableFlush);
                      }
                  }
              }
          

          I have no more bad behavior, but I don't have the deeper knowledge of the bridges to see if my solution has its own flaws. At least I can release my update for now.

          Show
          cgrassick Clayton Grassick added a comment - Changing bridge modes didn't work out so good. There's a reason we are using OnlineEvents. I did get myself out of the pickle by changing the code in NativeToJsMessageQueue.java to: /** Uses online/offline events to tell the JS when to poll for messages. */ private class OnlineEventsBridgeMode extends BridgeMode { final Runnable runnable = new Runnable() { public void run() { if (!queue.isEmpty()) { webView.setNetworkAvailable(true); } } }; final Runnable runnableFlush = new Runnable() { public void run() { webView.setNetworkAvailable(false); } }; @Override void reset() { webView.setNetworkAvailable(false); } @Override void onNativeToJsMessageAvailable() { cordova.getActivity().runOnUiThread(runnable); } // Track when online/offline events are fired so that we don't fire excess events. @Override void notifyOfFlush(boolean fromOnlineEvent) { if (fromOnlineEvent) { cordova.getActivity().runOnUiThread(runnableFlush); } } } I have no more bad behavior, but I don't have the deeper knowledge of the bridges to see if my solution has its own flaws. At least I can release my update for now.
          Hide
          agrieve Andrew Grieve added a comment -

          Thanks for working on this. I'm having trouble reproducing the bug. Would you be able to upload a .zip of your app (or even better - a minimal repro case?)

          Show
          agrieve Andrew Grieve added a comment - Thanks for working on this. I'm having trouble reproducing the bug. Would you be able to upload a .zip of your app (or even better - a minimal repro case?)
          Hide
          cgrassick Clayton Grassick added a comment -

          Alas, my app only does it when doing a rather complex update from the server in the release version.

          Here is the circumstance:

          Open a cordova page. Then, in a callback from a cordova file operation, immediately load another cordova page instead. The first cordova calls in the new page will not fire the callbacks (sometimes).

          I know it's a strange scenario, but it's the only one I've seen it happen in. I captured extensive logging to figure out where things were going wrong and for me, it was definitely due to the online/offline flag failing to trigger an event because the true state and the flag were out of sync. The code that I suggested above could be further improved by having cordova.js not listen on offline events, but only on online events, I think.

          Show
          cgrassick Clayton Grassick added a comment - Alas, my app only does it when doing a rather complex update from the server in the release version. Here is the circumstance: Open a cordova page. Then, in a callback from a cordova file operation, immediately load another cordova page instead. The first cordova calls in the new page will not fire the callbacks (sometimes). I know it's a strange scenario, but it's the only one I've seen it happen in. I captured extensive logging to figure out where things were going wrong and for me, it was definitely due to the online/offline flag failing to trigger an event because the true state and the flag were out of sync. The code that I suggested above could be further improved by having cordova.js not listen on offline events, but only on online events, I think.
          Hide
          agrieve Andrew Grieve added a comment -

          Hmm, okay, from that description it may actually be that this bug is the same as CB-6047, and is fixed in 3.5.0. Would be great if you could test this out.

          Show
          agrieve Andrew Grieve added a comment - Hmm, okay, from that description it may actually be that this bug is the same as CB-6047 , and is fixed in 3.5.0. Would be great if you could test this out.
          Hide
          cgrassick Clayton Grassick added a comment -

          I am using Cordova 3.5.0-0.2.4, so I think it's a different bug.

          Show
          cgrassick Clayton Grassick added a comment - I am using Cordova 3.5.0-0.2.4, so I think it's a different bug.
          Hide
          dotnetwise DotNetWise added a comment -

          We can confirm the same bug. It started on 3.5.0 and it sucks. You select a picture but your callbacks are never being called when you select a file and the camera/gallery closes.
          ```
          navigator.camera.getPicture(uploadPicture_step1, uploadError, chooseOptions);
          ```

          If you somehow execute whatever any other cordova native code via `exec` then you'll get both answers!!

          Show
          dotnetwise DotNetWise added a comment - We can confirm the same bug. It started on 3.5.0 and it sucks. You select a picture but your callbacks are never being called when you select a file and the camera/gallery closes. ``` navigator.camera.getPicture(uploadPicture_step1, uploadError, chooseOptions); ``` If you somehow execute whatever any other cordova native code via `exec` then you'll get both answers!!
          Hide
          dotnetwise DotNetWise added a comment -

          Cordova team, is anyone even aware of this? This is a SHOW STOPPER for us
          We had to rollback to 3.4.0!

          Show
          dotnetwise DotNetWise added a comment - Cordova team, is anyone even aware of this? This is a SHOW STOPPER for us We had to rollback to 3.4.0!
          Hide
          agrieve Andrew Grieve added a comment -

          Able to repro this in mobilespec on my Nexus 7 (using camera manual test)

          Leaving for a 4-day weekend, but will look next week once I'm back.

          Raising priority.

          Show
          agrieve Andrew Grieve added a comment - Able to repro this in mobilespec on my Nexus 7 (using camera manual test) Leaving for a 4-day weekend, but will look next week once I'm back. Raising priority.
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 445ddd89fb3269a772978a9860247065e5886249 in cordova-android's branch refs/heads/master from Andrew Grieve
          [ https://git-wip-us.apache.org/repos/asf?p=cordova-android.git;h=445ddd8 ]

          CB-6761 Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly

          Show
          jira-bot ASF subversion and git services added a comment - Commit 445ddd89fb3269a772978a9860247065e5886249 in cordova-android's branch refs/heads/master from Andrew Grieve [ https://git-wip-us.apache.org/repos/asf?p=cordova-android.git;h=445ddd8 ] CB-6761 Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 445ddd89fb3269a772978a9860247065e5886249 in cordova-android's branch refs/heads/4.0.x from Andrew Grieve
          [ https://git-wip-us.apache.org/repos/asf?p=cordova-android.git;h=445ddd8 ]

          CB-6761 Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly

          Show
          jira-bot ASF subversion and git services added a comment - Commit 445ddd89fb3269a772978a9860247065e5886249 in cordova-android's branch refs/heads/4.0.x from Andrew Grieve [ https://git-wip-us.apache.org/repos/asf?p=cordova-android.git;h=445ddd8 ] CB-6761 Fix native->JS bridge ceasing to fire when page changes and online is set to false and the JS loads quickly
          Hide
          agrieve Andrew Grieve added a comment -

          Fixed in 3.6.0-dev (so maybe in 3.5.1 or 3.6.0 release)

          Show
          agrieve Andrew Grieve added a comment - Fixed in 3.6.0-dev (so maybe in 3.5.1 or 3.6.0 release)
          Hide
          amgibson Andrew Gibson added a comment -

          I had this issue with Cordova 2.9.1 (on a Samsung Galaxy Tab 2 10.1 running Android 4.1.1).

          It looks like this fix (along with that for CB-6047) could be backported to 2.9.1. Does that sound reasonable? I tried and it seems to work, but I wasn't sure whether I'd need to backport other changes from 3.x.

          I am considering upgrading to the latest version of Cordova anyway. Does anyone know when this fix will be available in an official release?

          Show
          amgibson Andrew Gibson added a comment - I had this issue with Cordova 2.9.1 (on a Samsung Galaxy Tab 2 10.1 running Android 4.1.1). It looks like this fix (along with that for CB-6047 ) could be backported to 2.9.1. Does that sound reasonable? I tried and it seems to work, but I wasn't sure whether I'd need to backport other changes from 3.x. I am considering upgrading to the latest version of Cordova anyway. Does anyone know when this fix will be available in an official release?
          Hide
          agrieve Andrew Grieve added a comment -

          It's likely that we'll have another android release in the next few weeks.

          Show
          agrieve Andrew Grieve added a comment - It's likely that we'll have another android release in the next few weeks.
          Hide
          amgibson Andrew Gibson added a comment -

          Thanks for your reply

          Show
          amgibson Andrew Gibson added a comment - Thanks for your reply
          Hide
          keldar Kelvin Dart added a comment -

          I now see there's a specific Android release of Cordova - 3.5.1. But it appears to be a security fix. Can somebody confirm whether this fix has indeed been fixed in 3.5.1 or will we need to wait for 3.6.0?

          Show
          keldar Kelvin Dart added a comment - I now see there's a specific Android release of Cordova - 3.5.1. But it appears to be a security fix. Can somebody confirm whether this fix has indeed been fixed in 3.5.1 or will we need to wait for 3.6.0?
          Hide
          agrieve Andrew Grieve added a comment -

          You'll need to wait for 3.6.0.

          Show
          agrieve Andrew Grieve added a comment - You'll need to wait for 3.6.0.
          Hide
          keldar Kelvin Dart added a comment -

          No problem! I've applied the patch manually for now. Thanks.

          Show
          keldar Kelvin Dart added a comment - No problem! I've applied the patch manually for now. Thanks.
          Hide
          cmarcelk Marcel Kinard added a comment -

          3.5.1 contains only the security fix on top of 3.5.0.

          Show
          cmarcelk Marcel Kinard added a comment - 3.5.1 contains only the security fix on top of 3.5.0.
          Hide
          captain_morgan Morgan Allen added a comment -

          Is there a way to externally tell if this has occurred? online/offline event maybe? I'd like to at least be able to call requestFileSystem again if this message queue does get cleared.

          Show
          captain_morgan Morgan Allen added a comment - Is there a way to externally tell if this has occurred? online/offline event maybe? I'd like to at least be able to call requestFileSystem again if this message queue does get cleared.
          Hide
          pluswave Zhang Zengbo added a comment -

          reproduce this issue with 3.6.x dev version.

          Show
          pluswave Zhang Zengbo added a comment - reproduce this issue with 3.6.x dev version.
          Hide
          pluswave Zhang Zengbo added a comment -

          Hi , I think I am facing the same issue but it seems not fixed even I upgrade to use 3.6.x dev branch. could somebody confirm this ? please download attached tarball and extract to an empty dir for test. I test it on a Nexus 5 with 4.4.4, the first time I take the picture, it doesn't show; the second time I take the picture, even I cancel it, the first picture shows.

          Show
          pluswave Zhang Zengbo added a comment - Hi , I think I am facing the same issue but it seems not fixed even I upgrade to use 3.6.x dev branch. could somebody confirm this ? please download attached tarball and extract to an empty dir for test. I test it on a Nexus 5 with 4.4.4, the first time I take the picture, it doesn't show; the second time I take the picture, even I cancel it, the first picture shows.
          Hide
          seemaalbal Seema Albal added a comment -

          This issues is persisting for me too in 3.6.3. Can it be reopened?

          Show
          seemaalbal Seema Albal added a comment - This issues is persisting for me too in 3.6.3. Can it be reopened?
          Hide
          agrieve Andrew Grieve added a comment -

          Debugged the attached app, but I believe the bug is in the app - it's not calling $scope.$apply() from the getPicture success callback like it should.

          If anyone has an app that shows a bridge problem, please attach it and I'll re-open.

          Show
          agrieve Andrew Grieve added a comment - Debugged the attached app, but I believe the bug is in the app - it's not calling $scope.$apply() from the getPicture success callback like it should. If anyone has an app that shows a bridge problem, please attach it and I'll re-open.

            People

            • Assignee:
              agrieve Andrew Grieve
              Reporter:
              roy_lecare Roy Ackermann
            • Votes:
              7 Vote for this issue
              Watchers:
              14 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development