The process is to create a jpg file based on the timestamp, add the uri to the list, and display it through the lisetview
the first picture is normal,but Error will be reported when the second picture is obtained
The error occurred before Log.e("addiamge","====" )
E Writing exception to parcel
java.lang.SecurityException: Permission Denial: writing
net.qingmowan.Inspection.custom.MyFileProvider uri
content://net.aaaa.bbb.fileprovider/my_image/inspection_16679577393117723686263338001557.jpg
from pid=30798, uid=10084 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:919)
at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:698)
at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:669)
at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:493)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:272)
at android.os.Binder.execTransactInternal(Binder.java:1154)
at android.os.Binder.execTransact(Binder.java:1123)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
var photoURI: Uri? = null
val imageUris = LinkedList<Uri>();
val adapter = ImageAdapter(this, imageUris, layoutInflater)
val imageList = findViewById<ListView>(R.id.imageList)
imageList.adapter = adapter
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK && photoURI != null) {
Log.e("addiamge","====" )
imageUris.add(photoURI!!)
Log.e("images", imageUris.toString())
adapter.notifyDataSetChanged()
}
}
image.setOnClickListener {
photoURI = getPhotoUri()
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
launcher.launch(intent)
}
private fun getPhotoUri(): Uri? {
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
Log.e("获取拍照文件", "失败", ex)
null
}
photoFile?.also {
val uri = FileProvider.getUriForFile(this, "net.aaa.bbb.fileprovider", it)
return uri
}
return null
}
private fun createImageFile(): File {
val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val timeStamp = Date()
val file = File.createTempFile("inspection_${timeStamp.time}", ".jpg", storageDir).absoluteFile
Log.e("file_message", String.format("name:%s, file.absolutePath))
return file
}
Every time you get a photo from the camera, you need to create a new intent and reset the action
Move the definition of intent to the clickListener
image.setOnClickListener {
photoURI = getPhotoUri()
intent1.action = MediaStore.ACTION_IMAGE_CAPTURE
intent1.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
launcher.launch(intent1)
}
As for why I don't know, I hope someone can supplement my answer
Related
This question already has answers here:
Having trouble implementing ACTION_OPEN_DOCUMENT to my project
(4 answers)
Closed 6 months ago.
for the last 2 days I've been trying to implement a profile picture feature into an application using Uri and it works... for android versions < 11, and this is probably the reason, so I wanted to ask, how should I handle this problem ? Should I copy the files, store them application storage and then get the Uri? The code I'm currently using is based on this:
private var currentPhotoUri: Uri = Uri.EMPTY
private var isChanged = false
// intent launcher used for the profile picture image, on result it updates the picture
private val intentLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
val photoResult: Uri? = it.data?.data
if(photoResult != null) {
// user picked from gallery
currentPhotoUri = photoResult
changeProfilePicture(photoResult) // just a function that saves the Uri with room
} else {
// user made a photo
changeProfilePicture(currentPhotoUri)
}
}
}
private fun openIntentChooserForImageSources() {
// creating gallery intent
val galleryIntent = Intent(Intent.ACTION_OPEN_DOCUMENT, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
galleryIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
// creating camera intent
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.also { takePictureIntent ->
takePictureIntent.resolveActivity(requireActivity().packageManager)?.also {
val photoFile: File? = try {
createImageFile()
} catch (e: IOException){
null
}
photoFile?.also {
val photoFileUri: Uri = FileProvider.getUriForFile(
requireContext(),
requireActivity().packageName,
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoFileUri)
}
}
}
val intentChooser = Intent.createChooser(galleryIntent, "Select an app")
intentChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(cameraIntent))
intentLauncher.launch(intentChooser)
}
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir = requireActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
currentPhotoUri = this.toUri()
}
}
the error I get: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord (...) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
For the case where you use ACTION_OPEN_DOCUMENT, call takePersistableUriPermission() on a ContentResolver to get durable access to the content.
I'm trying to follow https://developer.android.com/training/camera/photobasics to get original image size, but I got null on the bitmap
lateinit var currentPhotoPath: String
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
private fun dispatchTakePictureIntent(numbers: Int) {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(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,
BuildConfig.APPLICATION_ID + ".provider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, numbers)
}
}
}
}
onActivityResult :
val bitmap = data?.extras?.get("data") as Bitmap
strImageTabungan1 = ConvertBase64().getStringImage(bitmap)
img_1.setImageBitmap(bitmap)
I can open the camera activity, but when trying to get the result, it returns
**java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=888, result=-1, data=Intent { }} to activity {com.example.abcdef/com.example.abcdef.form.ExampleActivity}: kotlin.TypeCastException: null cannot be cast to non-null type android.graphics.Bitmap**
What's wrong with it?
All is in the title.
I'm able to get a File object by using the File constructor but using the toFile() extension on the Uri led to an error.
java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://***.provider/files/06082021_113127.jpg
What I do :
private var uri: Uri? = null
binding.camera.setOnClickListener {
val name = LocalDateTime.now().generateFileName()
val file = File(requireContext().filesDir, "$name.jpg")
uri = FileProvider.getUriForFile(
requireContext(),
requireContext().packageName + ".provider",
file
)
takePicture.launch(uri)
}
private val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { success: Boolean ->
val test = uri?.path?.let { File(it) }
val test2 = uri?.toFile()
Log.e("test", "${test?.name}")
Log.e("test2", "${test2?.name}")
}
Can someone help shed some light ?
I send intent for recording video in this way
private fun openCamera(url: String) {
if (!viewModel.isAttachmentSaved) {
val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
val file = File(url)
val videoURI = if (Build.VERSION_CODES.N <= android.os.Build.VERSION.SDK_INT) {
FileProvider.getUriForFile(
localActivity,
BuildConfig.APPLICATION_ID + ".fileprovider",
file
)
} else {
Uri.fromFile(file)
}
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoURI)
val resInfoList = requireActivity()
.packageManager
.queryIntentActivities(takeVideoIntent, PackageManager.MATCH_DEFAULT_ONLY)
for (resolveInfo in resInfoList) {
val packageName = resolveInfo.activityInfo.packageName
localActivity?.grantUriPermission(
packageName, Uri.parse(url),
Intent.FLAG_GRANT_WRITE_URI_PERMISSION and Intent.FLAG_GRANT_READ_URI_PERMISSION
)
}
takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION and
Intent.FLAG_GRANT_WRITE_URI_PERMISSION and
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION and
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
startActivityForResult(takeVideoIntent, REQUEST_VIDEO)
}
}
After I that record video and play it in Mi Video, press back and confirm video file. And try to get video in onActivityResult but there are null file. Intent contains uri like this content:///external_files/..... FileProvider path is external_files
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_VIDEO && resultCode == Activity.RESULT_OK) {
Log.d("bouxView", "onActivityResult $data $requestCode")
//Toast.makeText(localActivity, R.string.text_start_compressing, Toast.LENGTH_LONG).show()
if (isViewModelInitialized()) {
val path = viewModel.videoPathLiveData.value?.run {
substringBeforeLast(FilesRepository.DELIMITER) + "copied" + FilesRepository.DELIMITER + substringAfterLast(FilesRepository.DELIMITER)
}
data?.data?.let {
try {
val fis: InputStream? = context?.contentResolver?.openInputStream(data?.data)
val videoFile = File(path)
val fos = FileOutputStream(videoFile)
val buffer = ByteArray(1024)
var length: Int = 0
var oldLength:Int = 0
while (fis?.read(buffer).also { length = (it ?: 0) } ?: 0 > 0) {
if (oldLength==0){
oldLength = length
}
fos.write(buffer, 0, length)
}
fis?.close()
fos.close()
Toast.makeText(requireContext(),"oldLength = $oldLength, path = $path, data = ${data.data.toString()}, pathLiveData = ${viewModel.videoPathLiveData.value}", Toast.LENGTH_LONG).show()
} catch (e: IOException) {
}
}
viewModel.onVideoSaved(path?:viewModel.videoPathLiveData.value)
}
}
}
If I record video and confirm it without playing all fine. What can be wrong? I also tried to find video in videoUri path that I put into MediaStore.EXTRA_OUTPUT parameter, no success. Tried to get video path from uri (How to get the Full file path from URI), no success.
It reproduced only in MIUI 11, android version 9
Looks like MIUI bug. This issue was resolved after updating MIUI.
This question already has answers here:
onActivityResult's intent.getPath() doesn't give me the correct filename
(2 answers)
Getting the Absolute File Path from Content URI for searched images
(2 answers)
Android - Get real path of a .txt file selected from the file explorer
(1 answer)
Closed 3 years ago.
I have an activity where the user can select an image/video from gallery. For images everything is working fine, however i'm struggling with videos.
This is how i call to open the gallery in case of videos:
fun getVideoFromGallery() {
if (Build.VERSION.SDK_INT < 19) {
var intent = Intent()
intent.type = "video/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(
Intent.createChooser(intent, "Select Picture")
, GALLERY_VIDEO
)
} else {
var videopicker = Intent(Intent.ACTION_OPEN_DOCUMENT);
videopicker.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
videopicker.addCategory(Intent.CATEGORY_OPENABLE)
videopicker.type = "video/*"
startActivityForResult(videopicker, GALLERY_VIDEO);
}
}
I receive the notification when the user selected the video in:
public override fun onActivityResult(requestCode:Int, resultCode:Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == GALLERY_VIDEO)
{
if (data != null)
{
val contentURI = data.data
try {
if (data.getData() != null) {
var videoURI = data.getData()
val cR = this#EnviarMultimediaActivity.getContentResolver();
val type = cR.getType(videoURI);
if(!type.isNullOrEmpty() && type.contains("video/", true)){
val videopath = videoURI.getPath()
val file = File(videopath)
Log.d(TAG, "Video uri: "+videoURI)
Log.d(TAG, "Video path: "+file.getAbsolutePath())
var videoCopy = File(Environment.getExternalStorageDirectory().absolutePath+ IMAGE_DIRECTORY + ((Calendar.getInstance().getTimeInMillis()).toString() + ".mp4"))
//file.copyTo(videoCopy, true)
copyVideoFile(file, videoCopy)
Glide
.with(this#EnviarMultimediaActivity)
.asBitmap()
.load(videoURI)
.into(object : CustomTarget<Bitmap>(){
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val thumbnail = saveImage(resource)
val thumbnailUri = Uri.parse(thumbnail);
val videoCopyURI = Uri.parse(videoCopy.getPath())
listaFicherosEnviar.add(EnviarMultimediaFichero(null, false, 3, videoCopyURI, thumbnailUri))
adapterEnviarMultimediaImagen.swapData(listaFicherosEnviar)
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
}
}
}
catch (e: IOException) {
e.printStackTrace()
Toast.makeText(this#EnviarMultimediaActivity, "Failed!", Toast.LENGTH_SHORT).show()
}
}
}
}
My onActivityResult is bigger but i just pasted the relevant part for videos.
If i don't try to make the copy Glide created the thumbnail and is displayed in the view.
The problem is that the copy don't work, i tried the File method copyTo and also another method implemented that receive a copy source and copy destination as parameter.
private fun copyVideoFile(sourceFile: File, destFile: File){
if (!sourceFile.exists()) {
return;
}
val source = FileInputStream(sourceFile).getChannel();
val destination = FileOutputStream(destFile).getChannel();
if (destination != null && source != null) {
destination.transferFrom(source, 0, source.size());
}
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
The problem is that sourceFile.exists() returns false, so no copy is done.
I tried to lod path and uri and is this:
Video uri: content://com.android.providers.downloads.documents/document/36
Video path: /document/36
I'm a bit lost as i don't understand why if the uri is correct (as Glide works) i can't create a File and make a copy to another File.
I requested permission and in my manifest i have:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.CAMERA
android.permission.INTERNET
android.permission.READ_EXTERNAL_STORAGE
Later i have retrofit2 api that creates a post to the server where sends as multipart:
val requestBody: RequestBody = RequestBody.create(MediaType.parse("video/*"), file)
val multiPart: MultipartBody.Part = MultipartBody.Part.createFormData("file", file.name, requestBody)
val name = RequestBody.create(MediaType.parse("text/plain"), file.name);
This is why i need an instance of File. As said the copy is just a test, but the File instance i think is required (unless i have a different code in the retrofir2 api to add the file to the post request).
Any help is appreciated.