Apache Cordova
  1. Apache Cordova
  2. CB-5294

File input element not opening file picker in Android 4.4

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Incomplete
    • Affects Version/s: 3.1.0
    • Fix Version/s: None
    • Component/s: Android
    • Labels:
      None
    • Environment:

      Android 4.4.2, partially fixed in Android 4.4.3

      Description

      The file input field doesn't respond when clicked/tapped in Android 4.4. Works fine in previous Android versions. This is regardless of whether the Target Level is set to 18 or 19.

      To reproduce, I created a fresh Cordova 3.1.0 project for Android. The only modification I made to the default (placeholder) index.html file was adding a <form> element with a single <input type="file"> element inside. Clicking the "Choose File" button does nothing. No Logcat output or errors. Normally at this point a dialogue would open allowing me to select an image from the gallery or take a picture, which is what happens in older Android versions.

        Issue Links

          Activity

          Hide
          Joe Bowser added a comment -

          I think Incomplete is better as Won't Fix. We can always take another stab at this later, but this is too hard with not enough reward for anyone to want to take on at the moment.

          Show
          Joe Bowser added a comment - I think Incomplete is better as Won't Fix. We can always take another stab at this later, but this is too hard with not enough reward for anyone to want to take on at the moment.
          Hide
          Andrew Grieve added a comment -

          Seems this is infeasible to fix . Closing.

          Show
          Andrew Grieve added a comment - Seems this is infeasible to fix . Closing.
          Hide
          Ian Clelland added a comment -

          I see the same behaviour as Mike, on my N7 (4.4.3, KTU84L, Chrome 33.0.0.0). The files are renamed – I don't know if that is a privacy measure, to avoid leaking information about the device or user – but the information is always there.

          I can get at the file through remote inspector:

          › f = document.forms[0]
            ▶ <form>​…​</form>​
          › fe = f.children[0]
            <input type=​"file">​
          › fe.value
            "C:\fakepath\image%3A2438"
          › fe.files[0]
            ▼ File {webkitRelativePath: "", lastModifiedDate: Fri May 09 2014 14:53:33 GMT-0400 (EDT), name: "image%3A2438", type: "", size: 8079…}
              ▶ lastModifiedDate: Fri May 09 2014 14:53:33 GMT-0400 (EDT)
                name: "image%3A2438"
                size: 8079
                type: ""
                webkitRelativePath: ""
              ▶ __proto__: File
          

          "C:\fakepath\image%3A2438" is amusing, and is what makes me think that Chrome is deliberately obscuring the filenames: just making up something using the last filename component that looks like a full path.

          Show
          Ian Clelland added a comment - I see the same behaviour as Mike, on my N7 (4.4.3, KTU84L, Chrome 33.0.0.0). The files are renamed – I don't know if that is a privacy measure, to avoid leaking information about the device or user – but the information is always there. I can get at the file through remote inspector: › f = document.forms[0] ▶ <form>​…​</form>​ › fe = f.children[0] <input type=​ "file" >​ › fe.value "C:\fakepath\image%3A2438" › fe.files[0] ▼ File {webkitRelativePath: "", lastModifiedDate: Fri May 09 2014 14:53:33 GMT-0400 (EDT), name: " image%3A2438 ", type: " ", size: 8079…} ▶ lastModifiedDate: Fri May 09 2014 14:53:33 GMT-0400 (EDT) name: "image%3A2438" size: 8079 type: "" webkitRelativePath: "" ▶ __proto__: File " C:\fakepath\image%3A2438 " is amusing, and is what makes me think that Chrome is deliberately obscuring the filenames: just making up something using the last filename component that looks like a full path.
          Hide
          Joe Bowser added a comment -

          It is only half-fixed. I wouldn't update those docs just yet.

          Show
          Joe Bowser added a comment - It is only half-fixed. I wouldn't update those docs just yet.
          Hide
          ASF subversion and git services added a comment -

          Commit 9ef8c3d61c74c5c681a0242afaccd77857460603 in cordova-docs's branch refs/heads/master from Mike Billau
          [ https://git-wip-us.apache.org/repos/asf?p=cordova-docs.git;h=9ef8c3d ]

          CB-5294 fixed by Android 4.4.3

          Show
          ASF subversion and git services added a comment - Commit 9ef8c3d61c74c5c681a0242afaccd77857460603 in cordova-docs's branch refs/heads/master from Mike Billau [ https://git-wip-us.apache.org/repos/asf?p=cordova-docs.git;h=9ef8c3d ] CB-5294 fixed by Android 4.4.3
          Hide
          Mike Billau added a comment -

          I tested with Firefox and Chrome and both of them upload an image with the exact same filename as the one you select, so we are doing something different somewhere. At least the data gets transferred.

          Show
          Mike Billau added a comment - I tested with Firefox and Chrome and both of them upload an image with the exact same filename as the one you select, so we are doing something different somewhere. At least the data gets transferred.
          Hide
          Mike Billau added a comment -

          Seems mostly fixed for me on Nexus 5 running 4.4.3. The button opens the file chooser dialog. No matter what source I select, the asset does seem to be uploaded. However, if you select from "Recent" or "Images", the file will be renamed from something like IMG_234234.jpg --> image%3A24. If you select from "Downloads", or "Gallery", the image will be renamed from: IMG_23432423.jpg --> 24

          Show
          Mike Billau added a comment - Seems mostly fixed for me on Nexus 5 running 4.4.3. The button opens the file chooser dialog. No matter what source I select, the asset does seem to be uploaded. However, if you select from "Recent" or "Images", the file will be renamed from something like IMG_234234.jpg --> image%3A24. If you select from "Downloads", or "Gallery", the image will be renamed from: IMG_23432423.jpg --> 24
          Hide
          jcesarmobile added a comment -

          wasn't the kitkat webview supposed to autoupdate?
          If they fixed or partially fixed it on 4.4.3, the problem will remain in devices that can't be updated

          Show
          jcesarmobile added a comment - wasn't the kitkat webview supposed to autoupdate? If they fixed or partially fixed it on 4.4.3, the problem will remain in devices that can't be updated
          Hide
          Joe Bowser added a comment -

          This was fixed in CR-33, can you take a look at this? If you don't have the time, fire it back.

          Show
          Joe Bowser added a comment - This was fixed in CR-33, can you take a look at this? If you don't have the time, fire it back.
          Hide
          Joe Bowser added a comment - - edited

          As of Android 4.4.3. First click opens the documents browser, but this does not update the file selected. This was listed as fixed in CR-33, so something on our end isn't working correctly.

          Show
          Joe Bowser added a comment - - edited As of Android 4.4.3. First click opens the documents browser, but this does not update the file selected. This was listed as fixed in CR-33, so something on our end isn't working correctly.
          Hide
          Cesidio DiBenedetto added a comment -

          Hey all, I've been experiencing this issue as well so I wrote a Cordova FileChooser plugin to a "band-aid" for the time being. Basically, in Android 4.4(KitKat), as mentioned in previous comments, the file dialog is not opened. However the onclick event is still fired on <input type=file> so you can call the FileChooser plugin to open a file dialog and upon selection, you can set a variable that contains the full path to the file. At this point, you can use the FileTransfer plugin to upload to your server and hook into the onprogress event to show progress. This plugin is mainly configured for Android 4.4 so I would recommend to continue to use the native file dialogs for earlier versions of Android. There might be issues with the plugin as I have not fully tested all possible scenarios on many devices, but I have installed it on a Nexus 5 and it worked fine.

          https://github.com/cdibened/filechooser

          Show
          Cesidio DiBenedetto added a comment - Hey all, I've been experiencing this issue as well so I wrote a Cordova FileChooser plugin to a "band-aid" for the time being. Basically, in Android 4.4(KitKat), as mentioned in previous comments, the file dialog is not opened. However the onclick event is still fired on <input type=file> so you can call the FileChooser plugin to open a file dialog and upon selection, you can set a variable that contains the full path to the file. At this point, you can use the FileTransfer plugin to upload to your server and hook into the onprogress event to show progress. This plugin is mainly configured for Android 4.4 so I would recommend to continue to use the native file dialogs for earlier versions of Android. There might be issues with the plugin as I have not fully tested all possible scenarios on many devices, but I have installed it on a Nexus 5 and it worked fine. https://github.com/cdibened/filechooser
          Hide
          Mike Billau added a comment -

          I've added a note to the Platform Upgrade Guide about this bug (it's kinda weird, we don't list Android platform-wide quirks anywhere so the Upgrade Guide seemed like a decent enough place to stick it.)

          Lets keep this ticket open so that every Android update we can check to see if this has been resolved, and if so, remove the quirk.

          Show
          Mike Billau added a comment - I've added a note to the Platform Upgrade Guide about this bug (it's kinda weird, we don't list Android platform-wide quirks anywhere so the Upgrade Guide seemed like a decent enough place to stick it.) Lets keep this ticket open so that every Android update we can check to see if this has been resolved, and if so, remove the quirk.
          Hide
          ASF subversion and git services added a comment -

          Commit de8a4181cdf51ab40e4bc95e1d12f567a1c14ea8 in branch refs/heads/master from Mike Billau
          [ https://git-wip-us.apache.org/repos/asf?p=cordova-docs.git;h=de8a418 ]

          CB-5294: Add input type=file Android quirk

          Show
          ASF subversion and git services added a comment - Commit de8a4181cdf51ab40e4bc95e1d12f567a1c14ea8 in branch refs/heads/master from Mike Billau [ https://git-wip-us.apache.org/repos/asf?p=cordova-docs.git;h=de8a418 ] CB-5294 : Add input type=file Android quirk
          Hide
          jcesarmobile added a comment - - edited

          No, the chromium bug is a different one, the chromium bug is related to the new android 4.4 storage framework ( same problem as this phonegap bug I've opened https://issues.apache.org/jira/browse/CB-5398, and affects chrome too, and any other app that try to get an url from the result of an Intent.ACTION_GET_CONTENT ).

          the problem here is the file picker isn't even called because overwriting openFileChooser private function isn't working on android 4.4
          the file picker is opened on chrome and chromium, but not on the webview.

          But you are right, it isn't really a cordova bug, it's a android 4.4 webview bug. The problem is cordova is based on the webview, so the bug extends to cordova

          Show
          jcesarmobile added a comment - - edited No, the chromium bug is a different one, the chromium bug is related to the new android 4.4 storage framework ( same problem as this phonegap bug I've opened https://issues.apache.org/jira/browse/CB-5398 , and affects chrome too, and any other app that try to get an url from the result of an Intent.ACTION_GET_CONTENT ). the problem here is the file picker isn't even called because overwriting openFileChooser private function isn't working on android 4.4 the file picker is opened on chrome and chromium, but not on the webview. But you are right, it isn't really a cordova bug, it's a android 4.4 webview bug. The problem is cordova is based on the webview, so the bug extends to cordova
          Hide
          Marcel Kinard added a comment -

          This is not a bug in Cordova. It is a bug in the Chromium webview, and Google needs to fix it. According to https://code.google.com/p/chromium/issues/detail?id=278640 it appears the bug might be fixed in Chromium 33, whereas Android 4.4 currently has Chromium 30. It is unclear when Android 4.4 will get updated to Chromium 33, and how it will get it (Android system update or an app/component self-update). See https://developers.google.com/chrome/mobile/docs/webview/overview#will_the_new_webview_auto-update . To suggest that this would happen in the next 3 months is a wild uninformed guess. (No winking implied, seriously.)

          I don't think this issue is specific to any Cordova versions. It is specific to Android 4.4, and probably occurs on all Cordova versions that run there.

          Show
          Marcel Kinard added a comment - This is not a bug in Cordova. It is a bug in the Chromium webview, and Google needs to fix it. According to https://code.google.com/p/chromium/issues/detail?id=278640 it appears the bug might be fixed in Chromium 33, whereas Android 4.4 currently has Chromium 30. It is unclear when Android 4.4 will get updated to Chromium 33, and how it will get it (Android system update or an app/component self-update). See https://developers.google.com/chrome/mobile/docs/webview/overview#will_the_new_webview_auto-update . To suggest that this would happen in the next 3 months is a wild uninformed guess. (No winking implied, seriously.) I don't think this issue is specific to any Cordova versions. It is specific to Android 4.4, and probably occurs on all Cordova versions that run there.
          Hide
          Albert Bellonch Llargués added a comment -

          It happens to me too on Cordova 3.2.0. Any idea on when is this going to be solved, and with which Cordova version will this be released?

          Thanks,

          Show
          Albert Bellonch Llargués added a comment - It happens to me too on Cordova 3.2.0. Any idea on when is this going to be solved, and with which Cordova version will this be released? Thanks,
          Hide
          jcesarmobile added a comment -

          I changed my app to use FileTransfer for android and kept input file on iOS

          Show
          jcesarmobile added a comment - I changed my app to use FileTransfer for android and kept input file on iOS
          Hide
          Marcel Kinard added a comment -

          I've looked at this a bit, to see if there is a workaround, especially a workaround that could be transparent to app developers. Here is what I've found thus far.

          Prior to Android 4.4, Android's WebChromeClient class had an undocumented public openFileChooser() method that had a default implementation to ignore what was passed to it. CordovaChromeClient.java would override that method to grab a reference to the ValueCallback, start a file picker activity and get the result, and pass the value back by invoking ValueCallback.onReceiveValue(filePickerResult). I think that is basically the callback which allows us to take the result from the file picker and set the value of the form's input object. There has been chatter that this undocumented public method has disappeared in 4.4, but I think that is a red herring, it should still be there: see https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1/core/java/android/webkit/WebChromeClient.java - it is still there and unchanged from 4.3. But note that the javadoc for that method has always had a "@hide" tag, which keeps it out of the generated javadoc and appears to also remove that method from the android.jar in the SDK on the workstation (which is why Eclipse complains if @Override is used in CordovaChromeClient.java - android.jar on the workstation has only the non-hidden public methods). That's fine, because the android.jar from the workstation doesn't go into the apk, I'm assuming that the full class with public-hidden and private methods (in dex format) gets resolved at runtime on the device, which includes the openFileChooser() method in WebChromeClient. So I think it is safe to ignore the "openFileChooser() method was removed in 4.4" discussion, though it is hard to explicitly prove it other than looking at the Android source.

          So then that means that our openFileChooser() probably isn't getting called. https://code.google.com/p/android/issues/detail?id=62220 fits right on that, and reading comment #24 there indicates there is a Chromium bug that was fixed in the Chromium source on Nov 19, which will be shippable in a later version of Chromium. So the hope is that fixes it, assuming there is a way to get that newer Chromium on the device ( see https://plus.google.com/+GoogleChromeDevelopers/posts/4QYG9AE589M )

          So on to looking for any viable workarounds...

          The type="file" input button does generate an onClick event. So anyone can write js to respond to that event. But the value property of the type="file" input object in the DOM is read-only in js, so it isn't possible to set it from js. That is for security reasons.

          So if it is not possible to set the input value via js, and openFileChooser() in CordovaChromeClient no longer gets called so we never get a handle to the ValueCallback, I'm not seeing any way that we could set the value of the file input button, even if we were to provide our own picker activity. This means there is no way for a type="file" input to be used to store the result from a picker.

          So then that leaves the us with having to use some other type of input object to store the filename. And the expected issue with that is the browser's form processing wouldn't know to send the file's contents instead of the filename. Perhaps we could take over the submit action and do an xhr2.send(FormData) using a transient form we constructed ourselves from the original HTML one, with the same action and method. But this sounds like a bad idea, similar to our earlier effort to recreate a camera app to keep our suspended activity from getting killed when RAM runs short.

          So now it sounds like there is no viable way to workaround this in a way that is transparent to an app developer. The only workaround is for them to modify their app to use the FileTransfer plugin in the case of Android 4.4, assuming their server's service endpoint can deal with that input/upload.

          Does anyone have other ideas on a viable workaround? Anything I've gotten wrong?

          Show
          Marcel Kinard added a comment - I've looked at this a bit, to see if there is a workaround, especially a workaround that could be transparent to app developers. Here is what I've found thus far. Prior to Android 4.4, Android's WebChromeClient class had an undocumented public openFileChooser() method that had a default implementation to ignore what was passed to it. CordovaChromeClient.java would override that method to grab a reference to the ValueCallback, start a file picker activity and get the result, and pass the value back by invoking ValueCallback.onReceiveValue(filePickerResult). I think that is basically the callback which allows us to take the result from the file picker and set the value of the form's input object. There has been chatter that this undocumented public method has disappeared in 4.4, but I think that is a red herring, it should still be there: see https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1/core/java/android/webkit/WebChromeClient.java - it is still there and unchanged from 4.3. But note that the javadoc for that method has always had a "@hide" tag, which keeps it out of the generated javadoc and appears to also remove that method from the android.jar in the SDK on the workstation (which is why Eclipse complains if @Override is used in CordovaChromeClient.java - android.jar on the workstation has only the non-hidden public methods). That's fine, because the android.jar from the workstation doesn't go into the apk, I'm assuming that the full class with public-hidden and private methods (in dex format) gets resolved at runtime on the device, which includes the openFileChooser() method in WebChromeClient. So I think it is safe to ignore the "openFileChooser() method was removed in 4.4" discussion, though it is hard to explicitly prove it other than looking at the Android source. So then that means that our openFileChooser() probably isn't getting called. https://code.google.com/p/android/issues/detail?id=62220 fits right on that, and reading comment #24 there indicates there is a Chromium bug that was fixed in the Chromium source on Nov 19, which will be shippable in a later version of Chromium. So the hope is that fixes it, assuming there is a way to get that newer Chromium on the device ( see https://plus.google.com/+GoogleChromeDevelopers/posts/4QYG9AE589M ) So on to looking for any viable workarounds... The type="file" input button does generate an onClick event. So anyone can write js to respond to that event. But the value property of the type="file" input object in the DOM is read-only in js, so it isn't possible to set it from js. That is for security reasons. So if it is not possible to set the input value via js, and openFileChooser() in CordovaChromeClient no longer gets called so we never get a handle to the ValueCallback, I'm not seeing any way that we could set the value of the file input button, even if we were to provide our own picker activity. This means there is no way for a type="file" input to be used to store the result from a picker. So then that leaves the us with having to use some other type of input object to store the filename. And the expected issue with that is the browser's form processing wouldn't know to send the file's contents instead of the filename. Perhaps we could take over the submit action and do an xhr2.send(FormData) using a transient form we constructed ourselves from the original HTML one, with the same action and method. But this sounds like a bad idea, similar to our earlier effort to recreate a camera app to keep our suspended activity from getting killed when RAM runs short. So now it sounds like there is no viable way to workaround this in a way that is transparent to an app developer. The only workaround is for them to modify their app to use the FileTransfer plugin in the case of Android 4.4, assuming their server's service endpoint can deal with that input/upload. Does anyone have other ideas on a viable workaround? Anything I've gotten wrong?
          Hide
          jcesarmobile added a comment -

          I've read that android 4.4 won't include a web browser, and vendors will have to create their own using a webview or license chrome, so if they don't license chrome they will have this bug on their browsers. If this happens, maybe they fix it.

          Show
          jcesarmobile added a comment - I've read that android 4.4 won't include a web browser, and vendors will have to create their own using a webview or license chrome, so if they don't license chrome they will have this bug on their browsers. If this happens, maybe they fix it.
          Hide
          Paul Kane added a comment -

          Android 4.4 Kitkat is expanding its roll-out to Nexus tablets in the next couple of days, so the impact of this issue is only going to widen. Perhaps that will get it more attention.

          Show
          Paul Kane added a comment - Android 4.4 Kitkat is expanding its roll-out to Nexus tablets in the next couple of days, so the impact of this issue is only going to widen. Perhaps that will get it more attention.
          Hide
          Mike Billau added a comment -

          Andrew Grieve, it doesn't look like they are paying attention to the android issues list above. Are you seeing this getting more attention somewhere else? I'd just like to follow the progress.

          Show
          Mike Billau added a comment - Andrew Grieve , it doesn't look like they are paying attention to the android issues list above. Are you seeing this getting more attention somewhere else? I'd just like to follow the progress.
          Hide
          Joe Bowser added a comment -

          Kitkat is only on Nexus devices, this is not a blocker.

          Show
          Joe Bowser added a comment - Kitkat is only on Nexus devices, this is not a blocker.
          Hide
          Andrew Grieve added a comment -

          So, apparently <input type=file> is even causing trouble for Chrome on KitKat. There's no quick fix we can use, so will need to hack it up if we want to make it work. Likely it will be fixed in a future update.

          Show
          Andrew Grieve added a comment - So, apparently <input type=file> is even causing trouble for Chrome on KitKat. There's no quick fix we can use, so will need to hack it up if we want to make it work. Likely it will be fixed in a future update.
          Hide
          jcesarmobile added a comment -

          We can't answer there, right?
          I've looked into android 4.4 source code and the openFileChooser with the 4.1+ syntax (public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture))
          but it just doesn't work now, and by the google's answer, it seems that they have intentionally removed it

          Show
          jcesarmobile added a comment - We can't answer there, right? I've looked into android 4.4 source code and the openFileChooser with the 4.1+ syntax (public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)) but it just doesn't work now, and by the google's answer, it seems that they have intentionally removed it
          Hide
          Marcel Kinard added a comment -

          FYI, discussion in the dev mailing list: http://markmail.org/thread/zmwtu4fi56r4dnqq

          Show
          Marcel Kinard added a comment - FYI, discussion in the dev mailing list: http://markmail.org/thread/zmwtu4fi56r4dnqq
          Hide
          Paul Kane added a comment -

          If truly a feature-regression on Android 4.4 that's bad news. Would expect to hear more about this as more people upgrade to 4.4 and their Cordova (or other webview-based) apps start breaking.

          Our Cordova app requires image uploading to be useful at all, so this is a show-stopper for us.

          Would like to hear more confirmation from the Android and Cordova crews. Perhaps there's some kind of work around that can be hacked together involving Cordova file access... just don't know, haven't had to look into that before. I wouldn't be crazy about having to have a separate image-upload workflow for Cordova users and web users.

          Show
          Paul Kane added a comment - If truly a feature-regression on Android 4.4 that's bad news. Would expect to hear more about this as more people upgrade to 4.4 and their Cordova (or other webview-based) apps start breaking. Our Cordova app requires image uploading to be useful at all, so this is a show-stopper for us. Would like to hear more confirmation from the Android and Cordova crews. Perhaps there's some kind of work around that can be hacked together involving Cordova file access... just don't know, haven't had to look into that before. I wouldn't be crazy about having to have a separate image-upload workflow for Cordova users and web users.
          Hide
          jcesarmobile added a comment -

          Bad news, I opened an issue on the android open source project and the answer was:

          Status: WorkingAsIntended
          unfortunately, openFileChooser is not a public API. We are working on a public API in future releases of Android.

          http://code.google.com/p/android/issues/detail?id=62220

          Show
          jcesarmobile added a comment - Bad news, I opened an issue on the android open source project and the answer was: Status: WorkingAsIntended unfortunately, openFileChooser is not a public API. We are working on a public API in future releases of Android. http://code.google.com/p/android/issues/detail?id=62220
          Hide
          jcesarmobile added a comment -

          I've been looking into this as it affects to my current project and it seems it doesn't have an easy fix as this is a webview problem, not just phonegap.

          It seems to me that the new webview ignores the setWebChromeClient parameter, or at least the openFileChooser function.

          I've opended a stackoverflow thread asking about the input file on android 4.4 webview and started a bounty: http://stackoverflow.com/questions/19882331/html-file-input-in-android-webview-android-4-4-kitkat
          If I get some answers I'll fix it on cordova too.

          Show
          jcesarmobile added a comment - I've been looking into this as it affects to my current project and it seems it doesn't have an easy fix as this is a webview problem, not just phonegap. It seems to me that the new webview ignores the setWebChromeClient parameter, or at least the openFileChooser function. I've opended a stackoverflow thread asking about the input file on android 4.4 webview and started a bounty: http://stackoverflow.com/questions/19882331/html-file-input-in-android-webview-android-4-4-kitkat If I get some answers I'll fix it on cordova too.

            People

            • Assignee:
              Unassigned
              Reporter:
              Paul Kane
            • Votes:
              5 Vote for this issue
              Watchers:
              14 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development