BitmapFactory decodeFile returning null - android

I am trying to take a photo using camera and then trying to save to gallery and decode the stream using BitmapFactory but it returns null and also photo taken is not saved to gallery.
So two things here i noticed is photo taken is not getting saved to GALLERY and decodeFile retuning false.
I have tried using BitmapFactory.decodeStream and also tried getting from Uri but nothing worked.
Here is my code:
Take Photo:
if (ActivityCompat.checkSelfPermission(context!!, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(activity!!, arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), photoWithCamera)
else
displayCamera()
Camera Display:
private fun displayCamera() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(context!!.packageManager)?.also {
// Create the File where the photo should go
createImageFile()?.also {
uri = FileProvider.getUriForFile(context!!,"com.app.android.sample.fileprovider",it)
startActivityForResult(takePictureIntent, photoWithCamera)
}
}
}
}
private fun createImageFile(): File? = try {
File.createTempFile("test", ".png",context?.getExternalFilesDir(DIRECTORY_PICTURES)).apply {
newPicturePath = absolutePath
}
} catch (e: Exception) {
e.printStackTrace()
null
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null && (requestCode == photoWithCamera){
when (requestCode) {
photoWithCamera -> {
galleryAddPic()
setPic()
}
}
}
}
Decode Stream and Set pic (Not Working):
private fun setPic() {
// Get the dimensions of the View
val targetW: Int = headingImg.width
val targetH: Int = headingImg.height
val bmOptions = BitmapFactory.Options().apply {
// Get the dimensions of the bitmap
inJustDecodeBounds = true
val photoW: Int = outWidth
val photoH: Int = outHeight
// Determine how much to scale down the image
val scaleFactor: Int = min(photoW / targetW, photoH / targetH)
// Decode the image file into a Bitmap sized to fill the View
inJustDecodeBounds = false
inSampleSize = scaleFactor
inPurgeable = true
}
//decodeFile returns null here
BitmapFactory.decodeFile(newPicturePath, bmOptions)?.also { bitmap ->
headingImg.setImageBitmap(bitmap)
}
}
Adding photo taken to gallery(Not working):
private fun galleryAddPic() {
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
val f = File(newPicturePath)
mediaScanIntent.data = Uri.fromFile(f)
context!!.sendBroadcast(mediaScanIntent)
}
}
Android Manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:permissionGroup="android.permission-group.STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
Provider Paths:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
The file created using createImageFile() is returning file as below:
/storage/emulated/0/Android/data/com.app.android.sample/files/Pictures/test4153865961621152704.png and I could see the file in the same location
Thanks,
Sindhu

You should use same package name
'com.app.android.sample.fileprovider'
which you are using while opening camera in manifest file - 'com.app.android.sample.fileprovider' instead
android:authorities="${applicationId}.fileprovider".

I forgot to add the file uri before starting the Camera intent. So i changed my code from
createImageFile()?.also {
uri = FileProvider.getUriForFile(
context!!,
"com.app.android.traderpro.etx.fileprovider",
it
)
startActivityForResult(takePictureIntent, photoWithCamera)
}
to this:
createImageFile()?.also {
uri = FileProvider.getUriForFile(
context!!,
"com.app.android.traderpro.etx.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
startActivityForResult(takePictureIntent, photoWithCamera)
}

I faced the same issue and I fixed it by adding android:requestLegacyExternalStorage="true" under the application tag in the AndroidMaifest.xml file.

Related

Android intent always has null in callback (using registerForActivityResult)

I am using this code and I am missing something, because almost everything is working, but I get a null in the data when the callback responds:
private inner class JavascriptInterface {
#android.webkit.JavascriptInterface
fun image_capture() {
val photoFileName = "photo.jpg"
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
var photoFile = getPhotoFileUri(photoFileName)
if (photoFile != null) {
fileProvider = FileProvider.getUriForFile(applicationContext, "com.codepath.fileprovider", photoFile!!)
intent.putExtra(EXTRA_OUTPUT, fileProvider)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
if (intent.resolveActivity(packageManager) != null) {
getContent.launch(intent)
}
}
}
}
val getContent = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent:Intent? = result.data // <- PROBLEM: data is ALWAYS null
}
}
My manifest snippet related to this looks like this:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and my fileprovider.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="images" path="Pictures" />
</paths>
Any help is appreciated. Thanks!
That is supposed to be null, as ACTION_IMAGE_CAPTURE is not documented to return a Uri. You are using EXTRA_OUTPUT. The image should be stored in the location that you specified using EXTRA_OUTPUT.
Note, though, that you should be adding both FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION to the Intent, as the camera app needs to be able to write the image to the desired location.
So, I ended up checking out the TakePicture contract #ian (thanks for that tip!) and after a lot of cobbling together various resources I found, I finally got it to work. This is the pertinent kotlin code for the webview Activity:
class WebViewShell : AppCompatActivity() {
val APP_TAG = "MyApp"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_web_view)
// Storing data into SharedPreferences
val sharedPreferences = getSharedPreferences("MySharedPrefs", MODE_PRIVATE)
val storedurl: String = sharedPreferences.getString("url", "").toString()
val myWebView: WebView = findViewById(R.id.webview_webview)
myWebView.clearCache(true)
myWebView.settings.setJavaScriptCanOpenWindowsAutomatically(true)
myWebView.settings.setJavaScriptEnabled(true)
myWebView.settings.setAppCacheEnabled(true)
myWebView.settings.setAppCacheMaxSize(10 * 1024 * 1024)
myWebView.settings.setAppCachePath("")
myWebView.settings.setDomStorageEnabled(true)
myWebView.settings.setRenderPriority(android.webkit.WebSettings.RenderPriority.HIGH)
WebView.setWebContentsDebuggingEnabled(true)
myWebView.addJavascriptInterface(JavascriptInterface(),"Android")
myWebView.loadUrl(storedurl)
}
private inner class JavascriptInterface {
#android.webkit.JavascriptInterface
fun image_capture() { // opens Camera
takeImage()
}
}
private fun takeImage() {
try {
val uri = getTmpFileUri()
lifecycleScope.launchWhenStarted {
takeImageResult.launch(uri)
}
}
catch (e: Exception) {
android.widget.Toast.makeText(applicationContext, e.message, android.widget.Toast.LENGTH_LONG).show()
}
}
private val takeImageResult = registerForActivityResult(TakePictureWithUriReturnContract()) { (isSuccess, imageUri) ->
val myWebView: android.webkit.WebView = findViewById(R.id.webview_webview)
if (isSuccess) {
val imageStream: InputStream? = contentResolver.openInputStream(imageUri)
val selectedImage = BitmapFactory.decodeStream(imageStream)
val scaledImage = scaleDown(selectedImage, 800F, true)
val baos = ByteArrayOutputStream()
scaledImage?.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val byteArray: ByteArray = baos.toByteArray()
val dataURL: String = Base64.encodeToString(byteArray, Base64.DEFAULT)
myWebView.loadUrl( "JavaScript:fnWebAppReceiveImage('" + dataURL + "')" )
}
else {
android.widget.Toast.makeText(applicationContext, "Image capture failed", android.widget.Toast.LENGTH_LONG).show()
}
}
private inner class TakePictureWithUriReturnContract : ActivityResultContract<Uri, Pair<Boolean, Uri>>() {
private lateinit var imageUri: Uri
#CallSuper
override fun createIntent(context: Context, input: Uri): Intent {
imageUri = input
return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, input)
}
override fun getSynchronousResult(
context: Context,
input: Uri
): SynchronousResult<Pair<Boolean, Uri>>? = null
#Suppress("AutoBoxing")
override fun parseResult(resultCode: Int, intent: Intent?): Pair<Boolean, Uri> {
return (resultCode == Activity.RESULT_OK) to imageUri
}
}
private fun getTmpFileUri(): Uri? {
val mediaStorageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), APP_TAG)
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) {
throw Exception("Failed to create directory to store media temp file")
}
return FileProvider.getUriForFile(applicationContext, getApplicationContext().getPackageName() + ".provider", File(mediaStorageDir.path + File.separator + "photo.jpg"))
}
fun scaleDown(realImage: Bitmap, maxImageSize: Float, filter: Boolean): Bitmap? {
val ratio = Math.min(maxImageSize / realImage.width, maxImageSize / realImage.height)
val width = Math.round(ratio * realImage.width)
val height = Math.round(ratio * realImage.height)
return Bitmap.createScaledBitmap(realImage, width, height, filter)
}
}
To round things out, here is the pertinent JavaScript code - which the Activity is loading via the myWebView.loadUrl(storedurl) statement.
This is the JavaScript code which calls the Android code:
if (window.Android) {
Android.image_capture();
}
And when the picture has been taken, and sized by the Android code, it sends the Base64 back to JavaScript with:
myWebView.loadUrl("JavaScript:fnWebAppReceiveImage('" + dataURL + "')")
Note how weirdly you have to specify function arguments. There probably is a better way, but this code works. If there are any suggestions about how to specify a function argument easier than this, please let me know.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.MyApp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>
</manifest>
And the provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="external_files" path="." />
</paths>
Hope this helps someone - it took me days of research to figure this one out!

How to get Image URI by intent MediaStore.ACTION_IMAGE_CAPTURE in Android 10 and above

FOR MODERATORS: I know there are already questions like this but all of those approaches endup giving bitmap through data.getExtra("data") which is actually just thumbnail. I want to get URI not bitmap and I need to get URI of ACTUAL IMAGE not its thumbnail with approach available in 2021. PLEASE CONSIDER THIS BEFORE TAGGING QUESTION AS DUPLICATE!
I am getting image from camera and its working fine on lower devices but its giving null in data when onActivityResult is called only in Android 10 and 11.
That's what I am doing
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, ACTION_REQUEST_CAMERA)
Here is my onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == ACTION_REQUEST_CAMERA) {
data?.data?.let { uri ->
Toast.makeText(context, "Got URI", Toast.LENGTH_LONG).show()
}
}
}
This approach worked for me
In Manifest file
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.android.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
...
</application
created a file /res/xml/file_paths.xml and specified path in that
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
</paths>
In my activity
created a global variable var cameraPhotoFilePath: Uri? = null
this is how I started Camera acitivity for results
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val photoFile: File? = try {
createImageFileInAppDir()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
photoFile?.also { file ->
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.example.android.provider",
file
)
cameraPhotoFilePath = photoURI
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
startActivityForResult(intent, ACTION_REQUEST_CAMERA)
here is a helper function that i used in above code
#Throws(IOException::class)
private fun createImageFileInAppDir(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val imagePath = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File(imagePath, "JPEG_${timeStamp}_" + ".jpg")
}
At the end in onActivityResult thats how I got image Uri
if (resultCode == RESULT_OK && requestCode == ACTION_REQUEST_CAMERA) {
cameraPhotoFilePath?.let { uri ->
// here uri is image Uri that was captured by camera
}
}
You should pass your own uri (path) to intent with action MediaStore.ACTION_IMAGE_CAPTURE
putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(
applicationContext,
"$packageName.your_file_provider",
File("path/to")
))
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
More info about FileProvider
Android developer have good documentation about how to get full sized photos . You can also get the uri of full size image .Please visit this link Get full size image

Take photo programmatically and return file name and path

I read this so that upon clicking the button, the Camera intent is opened, and returned the saved picture file and path to the activity that called it, but I got my app crashed and restarted without opening the camera intent.
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.oryx.geoop">
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA"/>
<application android:theme="#style/AppTheme">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
<activity android:name=".AnotherActivity">
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
The xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Activity
class AnotherActivity : AppCompatActivity() {
val REQUEST_TAKE_PHOTO = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_another)
// Grant permissions
Dexter.withActivity(this)
.withPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
/* ... */
}
})
save_local.setOnClickListener { captureFromCamera(this) }
}
#Throws(IOException::class)
private fun createImageFile(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val dir =
"""${getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)}/geoOp/"""
val storageDir = File(dir)
storageDir.mkdirs()
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
val currentPhotoPath = absolutePath
}
}
private fun captureFromCamera(context: Context) {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(context.packageManager)?.also {
// Create the File where the photo should go
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.oryx.geoop.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
}
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Result code is RESULT_OK only if the user captures an Image
if (resultCode == Activity.RESULT_OK && resultCode == RESULT_OK) {
Toast.makeText(this, "pic saved", Toast.LENGTH_SHORT).show()
println("pic saved")
}
}
}
UPDATE
As getExternalStoragePublicDirectory is deprecated in Android Q, and to be replaced by below code, as shown here:
Kotlin
val resolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "CuteKitten001")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/PerracoLabs")
}
val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
resolver.openOutputStream(uri).use {
// TODO something with the stream
}
How can I use it in my code above, noting that this update return Uri, while original code returnfile` for image location:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
// return Uri
} else {
// return file
}

How to save camera captured image with custom file name in Android?

I am trying to take a picture from camera in Android and I want to save it with a custom file name using UUID (eg: f12b5700-1d92-11e9-ab14-d663bd873d93.jpg).
In the following code, in onActivityResult, I do get the f12b5700-1d92-11e9-ab14-d663bd873d93.jpg in photoPath but when I check the actual image on device, it is saved as timestamp.jpg (eg: 1548082653944.jpg). My question is how can I make the image to be saved with custom name?
private var photoURI: Uri? = null
private fun takePhoto()
{
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, UUID.randomUUID().toString() + ".jpg")
photoURI = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(packageManager) != null)
{
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(intent, PHOTO_REQUEST_CODE);
}
}
in onActivityResult handler, the code looks like this:
if (requestCode == PHOTO_REQUEST_CODE)
{
if (resultCode == Activity.RESULT_OK)
{
val proj = arrayOf(MediaStore.Images.Media.TITLE)
val cursor = contentResolver.query(photoURI!!, proj, null, null, null)
val index = cursor!!.getColumnIndex(MediaStore.Images.Media.TITLE)
cursor.moveToFirst()
photoPath = cursor.getString(index)
cursor.close()
Toast.makeText(this, photoPath, Toast.LENGTH_LONG).show()
}
else
{
capturedImage.setImageURI(null)
Toast.makeText(this, "Photo was not taken", Toast.LENGTH_SHORT).show()
}
}
With some struggle, I was able to solve the problem with the help of CommonsWare link:
https://github.com/commonsguy/cw-omnibus/tree/v8.13/Camera/FileProvider
Additionally I took help from these links:
https://guides.codepath.com/android/Accessing-the-Camera-and-Stored-Media
https://guides.codepath.com/android/Sharing-Content-with-Intents#sharing-files-with-api-24-or-higher
https://developer.android.com/training/camera/photobasics
https://developer.android.com/reference/android/os/Environment.html#getExternalStorageState(java.io.File)
The trick is to use FileProvider.
I had to add <provider> in AndroidManifest.xml
Working code looks like this:
if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED)
{
Toast.makeText(this, "Storage is not available", Toast.LENGTH_LONG).show()
return
}
var imageName = UUID.randomUUID().toString() + ".jpg"
var output = File(Environment.getExternalStoragePublicDirectory(appName), imageName)
if (!output.parentFile.exists() && !output.parentFile.mkdir())
{
Toast.makeText(this, "Unable to create storage folder", Toast.LENGTH_LONG).show()
return
}
photoURI = FileProvider.getUriForFile(this, authority, output)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(packageManager) != null)
{
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(intent, PHOTO_REQUEST_CODE);
}
Provider:
<provider
android:authorities="com.domain.appname.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="appname" path="appname" />
</paths>
Change com.domain.appname and appname accordingly.

Struggling with trying to get image from camera to upload to Firebase - java.lang.IllegalStateException: uri must not be null

I've been reading through every post on here relating (as well as the documentation) to this topic and for some reason I just can't get it working. I get to the point where the user takes a photo, hits the checkmark to continue, and then the app crashes.
Specifically at this line:
val filepath = mFirebaseStorage.child("Users").child(prefs.UID).child(uri.lastPathSegment)
My code looks something like this:
onLaunchCamera - called when user selects "Camera" from alert box
private fun onLaunchCamera() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
//Ensure there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(packageManager) != null) {
var photoFile: File? = null
try {
photoFile = createImageFile()
} catch (e: IOException) {
//log error
Log.e(TAG, e.toString())
}
//continue only if file was successfully created!
if (photoFile != null) {
val photoURI = FileProvider.getUriForFile(this,
"com.android.projectrc.fileprovider",
photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
onActivityResult
override protected fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val progressDialog = indeterminateProgressDialog("Uploading...")
progressDialog.show()
Log.d(TAG,"URI:: ${photoURI}")
val uri = data.data
val filePath = mFirebaseStorage.child("Users").child(prefs.UID)
.child("ProfileImage").child(uri.lastPathSegment)
filePath.putFile(photoURI!!).addOnSuccessListener(OnSuccessListener <UploadTask.TaskSnapshot >() {
fun onSuccess(taskSnapshot : UploadTask.TaskSnapshot) {
toast("Upload Successful!")
progressDialog.dismiss()
}
}).addOnFailureListener(OnFailureListener () {
fun onFailure(e : Exception) {
Log.e(TAG, e.toString())
toast("Upload Failed!")
}
});
//val bundle = data.extras
}
}
createImageFile
private fun createImageFile(): File {
// Create an image file name
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
val imageFileName = "JPEG_" + timeStamp + "_";
val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.absolutePath;
return image
}
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.android.projectrc.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
files_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.android.projectrc/files/Pictures" />
</paths>
Even photoURI shows up null when the console outputs it - I'm at quite a loss and would appreciate any help!
The answer to this related question explains that when a URI is passed as EXTRA_OUTPUT on the ACTION_IMAGE_CAPTURE intent, the URI is not returned as data on the intent parameter to onActivityResult().
This means you must save the URI in a class variable when it is generated so that it is available in onActivityResult(). It appears you already have photoURI declared as a class variable and that you intended to define it's value with this code in onLaunchCamera():
val photoURI = FileProvider.getUriForFile(this,
"com.android.projectrc.fileprovider",
photoFile)
But the val is creating a new instance of photoURI and the value is not stored in the class field as you want. Remove val.

Categories

Resources