I am trying to open a file chooser from a Webview and select a file. But in certain phones after the camera is opened, My activity gets destroyed and when the user clicks a picture and comes back, the activity is recreated. I maintain the webview state using the URL, but the callback is lost.
class SampleWebActivity : AppCompatActivity() {
private var mUploadMessage: ValueCallback<Array<Uri>>? = null
private var mCM: String? = null
private val FILE_CHOOSER_REQUEST_CODE = 1111
private var uploadType: Int = TYPE_BOTH
private lateinit var binding: ActivitySampleWebActivity
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySampleWebActivity.inflate(layoutInflater)
setContentView(binding.root)
binding.sampleWebView.settings.javaScriptEnabled = true
binding.sampleWebView.settings.domStorageEnabled = true
binding.sampleWebView.webChromeClient = sampleChromeClient()
binding.sampleWebView.webViewClient = sampleWebViewClient()
loadUrl()
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
intent: Intent?
) {
super.onActivityResult(requestCode, resultCode, intent)
var results: Array<Uri>? = null
//Check if response is positive
if (resultCode == Activity.RESULT_OK) {
if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
if (null == mUploadMessage) { //this returns true as callback is null
return
}
if (intent == null) {
//Capture Photo if no image available
if (mCM != null) {
results = arrayOf(Uri.parse(mCM))
}
} else {
val dataString = intent.dataString
if (dataString != null) {
results = arrayOf(Uri.parse(dataString))
}else{
if (mCM != null) {
results = arrayOf(Uri.parse(mCM))
}
}
}
}
}
mUploadMessage?.onReceiveValue(results)
mUploadMessage = null
}
private inner class sampleChromeClient : WebChromeClient() {
@SuppressLint("LogNotTimber")
override fun onShowFileChooser(
mWebView: WebView,
filePathCallback: ValueCallback<Array<Uri>>,
fileChooserParams: FileChooserParams
): Boolean {
if (mUploadMessage != null){
mUploadMessage?.onReceiveValue(null)
}
cameraPermissionIntentData = CameraPermissionIntentData(null, arrayOf(), null, null)
mUploadMessage = filePathCallback
var takePictureIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent!!.resolveActivity(this@sampleWebActivity.packageManager) != null) {
var photoFile: File? = null
try {
photoFile = createImageFile()
} catch (ex: IOException) {
Log.e(TAG, "Image file creation failed", ex)
}
if (photoFile != null) {
mCM = "file:" + photoFile.absolutePath
takePictureIntent.putExtra("PhotoPath", mCM)
val uri = FileProvider.getUriForFile(this@sampleWebActivity, this@sampleWebActivity.applicationContext.packageName + ".provider", photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
} else {
takePictureIntent = null
}
}
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
val intentArray: Array<Intent?>
val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
contentSelectionIntent.type = "*/*"
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Select file to send")
when(uploadType){
TYPE_CAMERA -> {
if(takePictureIntent != null) {
cameraPermissionIntentData.takePictureIntent = takePictureIntent
checkCameraPermission(
SnackBarRationale(
context = this@sampleWebActivity,
view = binding.sampleWebView,
rationaleText = getString(R.string.camera_access_required),
requestCode = TYPE_CAMERA
)
, openCamera = {
cameraPermissionIntentData.takePictureIntent?.let {
startActivityForResult(it, FILE_CHOOSER_REQUEST_CODE)
} ?: Log.logToCrashlytics(" +++++ take picture intent is null , permission already present")
})
} else {
return false
}
}
TYPE_GALLERY -> {
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
startActivityForResult(chooserIntent, FILE_CHOOSER_REQUEST_CODE)
}
TYPE_BOTH -> {
intentArray = if (takePictureIntent != null) {
arrayOf(takePictureIntent)
} else {
arrayOf()
}
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
cameraPermissionIntentData.apply {
this.takePictureIntent = takePictureIntent
this.intentArray = intentArray
this.contentSelectionIntent = contentSelectionIntent
this.chooserIntent = chooserIntent
}
checkCameraPermission(
SnackBarRationale(
context = this@sampleWebActivity,
view = binding.sampleWebView,
rationaleText = getString(R.string.camera_access_required),
requestCode = TYPE_BOTH
)
, openCamera = {
cameraPermissionIntentData.chooserIntent?.let {
startActivityForResult(it, FILE_CHOOSER_REQUEST_CODE)
} ?: Log.logToCrashlytics(" +++++ chooser intent is null , permission already present")
})
}
}
return true
}
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
if (newProgress == 100) {
binding.sampleWebPb.postDelayed({
binding.sampleWebPb.visibility = View.GONE
}, 2000)
}
}
}
I tried to save the callback and file path outside the activity (in a singleton) and using it again when activity is created, but it didn't work. I even tried to save the SampleChromeClient and use the same instance again but still the selected file doesn't load. What can I do?