javascriptandroid-webviewwebchromeclient

Result from OpenFileChooser in Android Webview cause the app unrespond


I am developing the hybrid application in android. In this application I am trying to get the image (either from camera or gallery) as user profile picture. Here is the code that i use to get the image.

    @Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    webView = (WebView) findViewById(R.id.webview);

    try {
        WebSettings webSettings = webView.getSettings();
        webSettings.setDatabaseEnabled(true);
        webSettings.setDatabasePath("/data/data/"
                + getApplicationContext().getPackageName() + "/databases");

        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setAllowFileAccess(true);
        webSettings.setLoadsImagesAutomatically(true);

        webSettings.setRenderPriority(RenderPriority.HIGH);
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

        webSettings.setSupportZoom(false);
        webSettings.setBuiltInZoomControls(false);
        webSettings.setDisplayZoomControls(false);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setUseWideViewPort(false);

        webView.addJavascriptInterface(_jsInterface, "JSInterface");
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageStarted(WebView view, String url,
                    Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }
        });
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url,
                    String message, JsResult result) {
                return super.onJsAlert(view, url, message, result);
            }

            @SuppressWarnings("unused")
            public void openFileChooser(ValueCallback<Uri> uploadMsg,
                    String acceptType, String capture) {
                openFileChooser(uploadMsg, acceptType);
            }

            private void openFileChooser(ValueCallback<Uri> uploadMsg,
                    String acceptType) {
                mUploadMessage = uploadMsg;
                try {
                    File imageStorageDir = new File(
                            Environment
                                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                            "AndroidImageFolder");
                    if (!imageStorageDir.exists()) {
                        imageStorageDir.mkdirs();
                    }
                    File file = new File(imageStorageDir + File.separator
                            + "CAPTURE_"
                            + String.valueOf(System.currentTimeMillis())
                            + ".jpg");
                    mCapturedImageURI = Uri.fromFile(file);
                    final Intent captureIntent = new Intent(
                            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                            mCapturedImageURI);

                    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                    i.addCategory(Intent.CATEGORY_OPENABLE);
                    i.setType("image/*");
                    Intent chooserIntent = Intent.createChooser(i,
                            "Pick your avatar");
                    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,
                            new Parcelable[] { captureIntent });
                    startActivityForResult(chooserIntent,
                            REQUEST_CODE_FILE_CHOOSER);

                } catch (Exception e) {
                }

            }
        });

        if (savedInstanceState == null) {
            webView.loadUrl("file:///android_asset/index.html");
        }
    } catch (Exception ex) {
        Log.d(TAG, ex.getCause().toString());
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    webView.saveState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    webView.restoreState(savedInstanceState);
}

@Override
protected void onResume() {
    super.onResume();
}

@Override
protected void onStart() {
    super.onStart();
}

@Override
public void onStop() {
    super.onStop();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_CANCELED) {
            //Intent returnIntent = new Intent();
            //setResult(RESULT_CANCELED, returnIntent);
        } else if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
            case REQUEST_CODE_FILE_CHOOSER:
                if (null == mUploadMessage)
                    return;
                Uri result = (data == null || resultCode != RESULT_OK) ? mCapturedImageURI
                        : data.getData();
                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;

                if (result != null) {
                    String imagePath = "";
                    String[] imgData = { MediaStore.Images.Media.DATA };
                    @SuppressWarnings("deprecation")
                    Cursor imgCursor = managedQuery(result, imgData, null,
                            null, null);
                    if (imgCursor != null) {
                        int index = imgCursor
                                .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                        imgCursor.moveToFirst();
                        imagePath = imgCursor.getString(index);
                    } else {
                        imagePath = result.getPath();
                    }
                    Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                    bitmap = ExifUtil.rotateBitmap(imagePath, bitmap);
                    // Here goes the bitmap to base64 conversion
                    try {
                        handler.post(new Runnable() {
                            public void run() {
                                webView.loadUrl("javascript:myJSFunction()"); // Here I return the base64 code (after bitmap conversion)
                            }
                        });
                    } catch (Exception Ex) {
                    }
                }
                break;
            }
        }
    } catch (Exception ex) {
    }
}

It successfully open the 'FileChooser' window with Camera and Gallery option. If I choose the image then the application works perfectly. The problem is, when i coming back to app without choosing any file (via back press or click the screen on app) then the application is stuck (Not able to click any of the link in webview).

For test purpose (Whether webview Activity is in active state) i tried to call the JS function in RESULT_CANCELED condition. Here is my test code

  if(resultCode == Activity.RESULT_CANCELED){
      try {
           handler.post(new Runnable() {
              public void run() {
                webView.loadUrl("javascript:myJSFunction()");
              }
           });
        } catch (Exception Ex) {
        }
  }
  else if(resultCode == Activity.RESULT_OK){
    ..... // Rest of the code
  }

This function is also not called. (but function is called when the resultCode is RESULT_OK)

Test Device OS version: Android JB 4.3

I stuck in this situation. Can you guys please help me to handle the RESULT_CANCELED situation and mark this problem solved. Thanks in advance.


Solution

  • You still need to call mUploadMessage.onReceiveValue when you get RESULT_CANCELLED.

    I think you can pass null in this case.