getting crash trying to upload a sign
Caused by: java.io.IOException: No such file or directory when clicking the submit button
error logs are shown below
class SignatureUploadFragment : BaseFragment() {
private lateinit var viewModel: SelectOptionViewModel
private lateinit var homeViewModel: HomeViewModel
//location
lateinit var mFusedLocationClient: FusedLocationProviderClient
//random id
val PERMISSION_ID = 42
//Define caseId type
private var caseId: String? = ""
//Initialize lat and long to get loc address
var longitude = 0.0
var latitude = 0.0
//Initialize location address
var locationAddress = ""
//Set timestamp when giving name while saving signature image
var addrTimeStamp = ""
//Convert file to string
var signatureFileName: String = ""
companion object {
var args: Bundle? = null
//pass the argument that needs to be displayed
fun newInstance(case_id: String): Fragment {
args = Bundle()
//pass the value caseId
args!!.putString(CASE_ID, case_id)
val fragment = SignatureUploadFragment()
fragment.arguments = args
return fragment
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
//setup view models
viewModel = ViewModelProviders.of(this)[SelectOptionViewModel::class.java]
homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]
val view: View = inflater.inflate(R.layout.signature_upload, container, false)
//get caseId
caseId = arguments?.getString(CASE_ID)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//to clear all the data inside the fragment to avoid multiple API calls
viewModel.signatureUploadresponseLiveData.value = null
viewModel.caseCompleteresponseLiveData.value = null
getLastLocation()
setUpListeners()
setupObserversCaseComplete()
setupObserversSubmitSignature()
}
/**
* Write all LiveData observers in this method
*/
private fun setupObserversCaseComplete() {
// if (isMenuVisible) {
viewModel.caseCompleteresponseLiveData.observe(this, Observer {
if (it != null) {
//user case complete success
if (it.success == 1 && it.result.success == 1) {
//Go back to case listing page
val intent = Intent(context, HomeActivity::class.java)
startActivity(intent)
Toast.makeText(
context,
"Case completed successfully.",
Toast.LENGTH_SHORT
).show()
}
//user case complete fail
else {
Toast.makeText(
context,
it.result.message,
Toast.LENGTH_SHORT
).show()
}
}
})
//observe API call status
viewModel.caseCompleteAPICallStatus.observe(this, Observer {
processStatus(it)
})
}
/**
* Write all LiveData observers in this method
*/
private fun setupObserversSubmitSignature() {
viewModel.signatureUploadresponseLiveData.observe(this, Observer {
if (it != null) {
//signature upload success
if (it.success == 1 && it.result.success == 1) {
Toast.makeText(context, "Signature uploaded successfully.", Toast.LENGTH_SHORT)
.show()
//delete file after upload
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File(root + "/Zion App/nomedia/Signature Images/")
myDir.deleteRecursively()
}
//signature upload fail
else {
Toast.makeText(
context,
"Failed to update signature. Please try again.",
Toast.LENGTH_SHORT
).show()
}
}
})
//observe API call status
viewModel.signatureUploadAPICallStatus.observe(this, Observer {
processStatus(it)
})
}
private fun setUpListeners() {
signature_button_complete.setOnClickListener {
showDialogComplete(caseId)
}
/**
* Create external image file, this file will be passed to Camera for saving the captured image
*/
@Throws(IOException::class)
fun createSignatureImageFile(): File {
// Create an image file name
var timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
//Set timestamp to addrTimeStamp
addrTimeStamp = timeStamp
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File("$root/Zion App/nomedia/Signature Images")
myDir.mkdirs()
return File.createTempFile(
"JPG_${addrTimeStamp}_", /* prefix */
".jpg", /* suffix */
myDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
fileTemp = this
//Save the complete file path to string
signatureFileName = this.toURI().path.toString()
}
}
signature_button_submit.setOnClickListener() {
//to check if signature pad is empty or not
if (signature_view.isBitmapEmpty) {
Toast.makeText(context, "Please sign here.", Toast.LENGTH_SHORT).show()
} else {
val signatureBitmap = signature_view.signatureBitmap
// val signatureBitmap = signature_view.signatureBitmap
createSignatureImageFile()
var imageQuality = 70
val byteArrayOutputStream = ByteArrayOutputStream()
// var capturedBitmap = BitmapFactory.decodeFile(signatureFileName)
var uncompressed = signatureBitmap
var newHeight = 800.00; // default height in pixels
var newWidth = 533.00; // default width in pixels
var oldHeight = uncompressed.getHeight().toDouble()
var oldWidth = uncompressed.getWidth().toDouble()
var aspRatio = 2.00 //default
if (oldHeight > 0 && oldWidth > 0) {
if (oldWidth > oldHeight) {
aspRatio = (oldWidth / oldHeight)
newHeight = newWidth / aspRatio
newWidth = newHeight * aspRatio
} else if (oldWidth < oldHeight) {
aspRatio = (oldHeight / oldWidth)
newHeight = newHeight / aspRatio
newWidth = newWidth * aspRatio
} else {
aspRatio = (oldHeight / oldWidth)
newHeight = newWidth / aspRatio
newWidth = newHeight * aspRatio
}
}
// scale it to 533w * 800h
uncompressed = Bitmap.createScaledBitmap(
uncompressed,
newWidth.toInt(),
newHeight.toInt(),
true
)
//compress by quality
uncompressed.compress(
Bitmap.CompressFormat.JPEG,
imageQuality,
byteArrayOutputStream
)
val byteArray = byteArrayOutputStream.toByteArray()
val compressedSignatureFile = FileOutputStream(signatureFileName)
compressedSignatureFile.write(byteArray)
compressedSignatureFile.flush()
compressedSignatureFile.close()
// val encoded = Base64.encodeToString(byteArray, Base64.DEFAULT)
signature_view.signatureBitmap
var imageType = "sign"
if (getAddress()) {
viewModel.submitSignatureData(
caseId,
imageType,
signatureFileName,
latitude,
longitude,
locationAddress
)
// dismissDialog()
// val progressBar = dialog?.findViewById(com.xyz.zion.R.id.progresbar) as ProgressBar
// progressBar.visibility = View.INVISIBLE
}
}
}
signature_button_clear.setOnClickListener {
signature_view.clearCanvas()
}
}
//popup box for complete case
fun showDialogComplete(caseId: String?) {
val dialog = Dialog(context)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
dialog.setContentView(com.xyz.zionapp.R.layout.popup_menu_complete_case)
var remarkBox =
dialog.findViewById(com.xyz.zionapp.R.id.submit_edittext_remark) as EditText
val submitBtn =
dialog.findViewById(com.xyz.zionapp.R.id.submit_button_submit_case) as Button
submitBtn.setOnClickListener {
var remarks = remarkBox.text.trim().toString();
var caseStatus = "completed"
if (remarks == "") {
Toast.makeText(context, "Please enter your remarks.", Toast.LENGTH_SHORT).show()
} else {
//initiate API call using ViewModel method
viewModel.submitCase(caseId, caseStatus, remarks)
// Toast.makeText(context, "Case completed successfully.", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
}
dialog.show()
}
//get location
//check whether location is enabled for application
@SuppressLint("MissingPermission")
private fun getLastLocation() {
// var latitude = 0.0
if (checkPermissions()) {
//if (isLocationEnabled()) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
getAddress()
// Call API
}
}
} else {
//requestPermissions()
//Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
//to get location in first try itself
var coraseLocationPermission = ContextCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
);
var accessFineLocation = ContextCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
);
if (coraseLocationPermission != PackageManager.PERMISSION_GRANTED && accessFineLocation != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
);
}
}
}
@SuppressLint("MissingPermission")
private fun requestNewLocationData() {
var mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = 0
mLocationRequest.fastestInterval = 0
mLocationRequest.numUpdates = 1
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
mFusedLocationClient!!.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
)
}
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
var mLastLocation: Location = locationResult.lastLocation
latitude = mLastLocation.latitude
longitude = mLastLocation.longitude
}
}
//check location permission
private fun checkPermissions(): Boolean {
if (ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
return true
}
return false
}
//request location permission
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this.activity!!
,
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
// Call API
}
}
requestNewLocationData()
} else {
getLastLocation();
}
}
}
//get address from location
var addresses: List<Address> = emptyList()
private fun getAddress(): Boolean {
// showDialog()
var flag = false
locationAddress = ""
try {
var geocoder = Geocoder(context, Locale.getDefault())
addresses = geocoder.getFromLocation(
latitude,
longitude, 1
) // Here 1 represent max location result to returned, by documents it recommended 1 to 5
//null checking
var address_size = addresses.size
if (address_size > 0) {
locationAddress = addresses.get(0)
.getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
flag = true
}
} catch (ioException: IOException) {
var errorMessage = getString(R.string.service_not_available)
Log.e(TAG, errorMessage + " saf not avail", ioException)
}
dismissDialog()
return flag
}
private fun processStatus(resource: ResourceStatus) {
when (resource.status) {
StatusType.SUCCESS -> {
dismissDialog()
// Toast.makeText(context, resource.message, Toast.LENGTH_SHORT).show()
}
StatusType.EMPTY_RESPONSE -> {
dismissDialog()
}
StatusType.PROGRESSING -> {
showDialog()
}
StatusType.SWIPE_RELOADING -> {
}
StatusType.ERROR -> {
var fail_status = "Failed to update signature. Please try again."
Toast.makeText(context, fail_status, Toast.LENGTH_SHORT).show()
dismissDialog()
}
StatusType.LOADING_MORE -> {
// CommonUtils().showSnackbar(binding.root, "Loading more..")
}
StatusType.NO_NETWORK -> {
var internet_failure = "Please check your internet connection."
Toast.makeText(context, internet_failure, Toast.LENGTH_SHORT).show()
}
StatusType.SESSION_EXPIRED -> {
// var session_expired = "Invalid credentials. Login failed"
// Toast.makeText(this, session_expired, Toast.LENGTH_SHORT).show()
}
}
}
}
Issues are on the line
"return File.createTempFile(
"JPG_${addrTimeStamp}_", /* prefix */
".jpg", /* suffix */
myDir /* directory */
). "
and this function "createSignatureImageFile()."
Fatal Exception: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:642)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)
error logs "java.lang.reflect.InvocationTargetException"
Caused by java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)
error logs "java.io.IOException no such file or directory"
Caused by java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively0(UnixFileSystem.java)
at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
at java.io.File.createTempFile(File.java:2018)
at com.xyz.Zionapp.ui.signature_upload_fragment.SignatureUploadFragment$setUpListeners$2.invoke(SignatureUploadFragment.kt:238)
at com.xyz.app.ui.signature_upload_fragment.SignatureUploadFragment$setUpListeners$3.onClick(SignatureUploadFragment.kt:259)