Kotlin: Exoplayer is not playing the video - android

I am learning Kotlin and Exoplayer and I am making an app that allows the user to select a video and play it on the next screen. However, after starting Intent, the selected video is not played.
First Activity:
private fun openGallery() {
intent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "video/*"
startActivityForResult(intent, 1)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
val selectedMediaUri = data!!.getData()
if (selectedMediaUri.toString().contains("video")) {
//handle video
// Get selected gallery image
val selectedVideo = data.getData()
// Get and resize profile image
val filePathColumn = arrayOf(MediaStore.Video.Media.DATA)
val cursor = applicationContext.contentResolver.query(selectedVideo!!, filePathColumn, null, null, null)
cursor!!.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val videoStoragePath = cursor.getString(columnIndex)
cursor.close()
val intent = Intent(this#MainActivity,PostarVideoActivity::class.java)
intent.putExtra("path",videoStoragePath)
startActivity(intent)
}
}
Second Activity:
val path = intent.extras!!.getString("path")
Log.i("mypath", path)
val player = ExoPlayerFactory.newSimpleInstance(applicationContext)
videoPreview.player = player
val dataSourceFactory = DefaultDataSourceFactory(
applicationContext,
Util.getUserAgent(applicationContext, applicationContext.getString(R.string.app_name))
)
// This is the MediaSource representing the media to be played.
val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(path!!))
// Prepare the player with the source.
player.prepare(videoSource)
How to resolve this error? Thanks in advance.

The error was simple ...
Just request READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions
This can be easily resolved with the Dexter library.
Maybe this can help someone

Related

SecurityException using storage access framework in some devices

I want to get content (images & videos) of user selected folder. Code to select the folder is:
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
or Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
startActivityForResult(intent, 1088)
And onActivityResult, I am persisting the permission(even I tested without restarting the device but it is not working):
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK) {
if (requestCode == 1088) {
val selectedDirUri = data!!.data
grantUriPermission(packageName, selectedDirUri, (Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION))
val takeFlags = (data.flags
and (Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION))
contentResolver.takePersistableUriPermission(selectedDirUri!!, takeFlags)
}
}
}
And I am traversing through all files using:
val rootUri: Uri = Uri.parse(selectedDir)
val contentResolver: ContentResolver = context.contentResolver
var childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, DocumentsContract.getTreeDocumentId(rootUri))
val dirNodes: MutableList<Uri> = LinkedList()
dirNodes.add(childrenUri)
while (!dirNodes.isEmpty()) {
childrenUri = dirNodes.removeAt(0) // get the item from top
val c = contentResolver.query(childrenUri,
arrayOf(
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE,
DocumentsContract.Document.COLUMN_LAST_MODIFIED),
null, null, null)
try {
while (c!!.moveToNext()) {
val docId = c.getString(0)
val fileName = c.getString(1)
val mimeType = c.getString(2)
val lastModified = c.getLong(3)
if (isDirectory(mimeType)) {
val newNode = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId)
dirNodes.add(newNode)
} else {
val newNode = DocumentsContract.buildDocumentUriUsingTree(rootUri, docId)
Logger.log("TAG", "========1 Images: $newNode")
val ***sourceFileUri*** = newNode.toString()
}
}
} finally {
closeQuietly(c)
}
}
Then I display images and videos using Glide, it is not displaying.
Even if I try to copy the image using below code:
val inputStream: InputStream? = context.contentResolver.openInputStream(***sourceFileUri***)
I am getting below error, the above line gives an error:
java.lang.SecurityException: com.android.externalstorage has no access
to content://media/external _primary/file/1000008384 at
android.os.Parcel.createException or Null(Parcel.java:2438) at 08
android.os.Parcel.createException(P arcel.java:2422) at
android.os.Parcel.readException(Par cel.java:2405) at
android.database.DatabaseUtils.rea dExceptionFromParcel(DatabaseUtil
s.java:190) at android.database.DatabaseUtils.rea dException
WithFileNotFoundExcepti on From Parcel(DatabaseUtils.java:15 3)
This is happening in Vivo, Oppo and specially in new Samsung phones only which has android OS 11 and 12. I am really frustrated, I tried all possible solution but not able to find any solution till now.
Any solution or advice would be really helpful and appreciated, please please help me.

how to preview video and upload that video file to firebase in android kotlin

I am trying to upload a video file to firebase.:-
this is the code:-
lateinit var file: Any
private fun selectingVideo() {
val videoPickIntent = Intent(Intent.ACTION_PICK)
videoPickIntent.type = "video/*"
startActivityForResult(Intent.createChooser(videoPickIntent, "Please pick a video"), videoRequest )
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == videoRequest && resultCode == Activity.RESULT_OK && null != data) {
feedImageSelect.visibility = View.GONE
feedVideoSelect.visibility = View.VISIBLE
val pickedVideoUrl = getRealPathFromUri(applicationContext, data.data!!)
file = pickedVideoUrl
feedVideoSelect.setVideoPath(pickedVideoUrl)
// Default Media-Controller
feedVideoSelect.setMediaController(MediaController(this))
// start playing
feedVideoSelect.start()
}
}
// Retrieve Video Path from URI.
private fun getRealPathFromUri(context: Context, contentUri: Uri): String {
var cursor: Cursor? = null
try {
val proj = arrayOf(MediaStore.Images.Media.DATA)
cursor = context.contentResolver.query(contentUri, proj, null, null, null)
val columnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
return cursor.getString(columnIndex)
} finally {
cursor?.close()
}
}
I am getting this as the error.:-
java.lang.ClassCastException: java.lang.String cannot be cast to android.net.Uri
I have tried all the possible ways to solve it. But Still I am getting this error. I tried other methods as well still they are not working for my requirements.
Make these changes to the code:-
val pickedVideoUrl = data.data
feedVideoSelect.setVideoPath(pickedVideoUrl.toString())

Get Image URI from Gallery and passing it to another activity, cannot see image, get an exception

I have an activity from which I launch the gallery, select an image, and want to display the selected image in another activity. I have referred to the following solution and implemented the same.
How to get Image URI from Gallery?
Though I am able to pass the URI to the next activity, I cannot see anything on the image view. Any help as to where I am going wrong, appreciated.
btn_launch_gallery.setOnClickListener {
val requestCode = 0
val launchGalleryIntent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(launchGalleryIntent, requestCode)
}
My OnActivityResult looks like this, basically implemented the same as given in the example cited above.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode === 0 && resultCode === Activity.RESULT_OK ) {
val selectedImage: Uri? = data?.data
val picturePath = getRealPathFromURI(
selectedImage,
this
)
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery", picturePath)
try {
startActivity(intent)
}
catch (e: Exception)
{
e.printStackTrace()
Log.e("Error",e.printStackTrace().toString())
}
}
}
fun getRealPathFromURI(contentURI: Uri?, context: Activity): String? {
val projection =
arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.managedQuery(
contentURI, projection, null,
null, null
)
?: return null
val column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
return if (cursor.moveToFirst()) {
// cursor.close();
cursor.getString(column_index)
} else null
// cursor.close();
}
In my next activity, I getting the intent like this and passing the URI to ImageView. However, I cannot see the image. I get the following error - W/System.err: java.io.FileNotFoundException: No content provider: /storage/emulated/0/DCIM/Camera/***.jpg
val resId = intent.getStringExtra("image_from_gallery")
val imgThumbnail: ImageView = findViewById(R.id.food_thumbnail)
try{
val imageStream: InputStream? = contentResolver.openInputStream(Uri.parse(resId))
val bitmap = BitmapFactory.decodeStream(imageStream)
imgThumbnail.setImageBitmap(bitmap)
}
catch (e: Exception)
{
e.printStackTrace()
}
I see the following image in the next activity:
UPDATE:
As commented by #blackapps in his answer passing the URI as a string to the next activity on an intent.putExtra() and resolving the URI in the subsequent activity solved it, the updated code in OnActivityResult() is,
...
val selectedImage: Uri? = data?.data
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery",
selectedImage.toString())
startActivity(intent)
Dont convert a nice uri to a file system path.
Uri uri = data.getData();
Pass the obtained uri directly to the next activity.
And there you can use it for
imageView.setImageUri(uri);
Instead of the uri you can also pass the uri as string with uri.toString().
You can directly load an local image Uri using:
imgThumbnail.setImageUri(yourUri);
Instead of sending the string path to the activity, you should send the raw uri and then set it directly to the imageView.

how to play hardcoded content uri of local media file in exoplayer

Initially I choose a Intent chooser to pick up a media file, and in onActivityResult i got the uri
fun openVideo(view: View) {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
intent.type = "video/*"
startActivityForResult(
Intent.createChooser(intent, "Select video"),
REQUEST_TAKE_GALLERY_VIDEO
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
...
...
val selectedVideoUri: Uri? = data!!.data
val vidPath: String = selectedVideoUri.toString()
video_uri = Uri.parse(vidPath)
// the video uri looks like below
//content://com.mi.android.globalFileexplorer.myprovider/external_files/Download/Dolittle%20(2020)%20%5B720p%5D%20%5BBluRay%5D%20%5BYTS.MX%5D/Dolittle.2020.720p.BluRay.x264.AAC-%5BYTS.MX%5D.mp4
initializePlayer(video_uri)
...
...
}
}
Then I was able to playing the local file in exoplayer.
fun initializePlayer(video_uri) {
println("log initializePlayer called")
player = ExoPlayerFactory.newSimpleInstance(this) // `player` was defined in GlobalVariables
id_player_view.player = player
if (video_uri != null) {
println("log $video_uri ${video_uri!!::class.simpleName}")
id_player_view.useController = true
var mediaSource: MediaSource = buildMediaSource(video_uri!!)
player?.playWhenReady = playWhenReady!!
player?.seekTo(currentWindow!!, playBackPosition!!)
player?.prepare(mediaSource, false, false)
}
}
But now, think that I saved the uri in database as a string.
Then, assume I retrieved the content from database and pass it as a intent to video playing activity
now, if i write a code like this, and call initializePlayer the video is not playing.
video_uri = Uri.parse((intent.getStringExtra("video_url")))
println("log $video_uri ${video_uri!!::class.simpleName}")
initializePlayer(video_uri)
i.e for all hardcoded content uri of local media files. the exoplayer is not working.
How to solve this issue ?
think that I saved the uri in database as a string
You no longer have rights to access the content.
How to solve this issue ?
Use ACTION_OPEN_DOCUMENT to let the user choose the content. Then, in onActivityResult(), call takePersistableUriPermission() on a ContentResolver, to have access to that content for a longer period of time. See this blog post and the documentation for more.

select multiple images from gallery in KOTLIN (want image path) [duplicate]

This question already has answers here:
Error "must not be null" in Kotlin
(3 answers)
Closed 4 years ago.
I am working on an Application for making a video from multiple images in kotlin. I got many code of java but can not convert it in propare way to kotlin code. Alwayse got an error cursor.getString(column_index) must not be null. I am just beginner at Kotlin. so can anyone give a brief solution for my problem.
val cursor = contentResolver.query(uri, filePathColumn, null, null, null)
cursor!!.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
Hey I m also suffering with same issue nd got the solution. just follow my code.
private var context: Context? = null
var PICK_IMAGE_MULTIPLE = 1
lateinit var imagePath: String
var imagesPathList: MutableList<String> = arrayListOf()
call gallery intent first
if (Build.VERSION.SDK_INT < 19) {
var intent = Intent()
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(
Intent.createChooser(intent, "Select Picture")
, PICK_IMAGE_MULTIPLE
)
} else {
var intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, PICK_IMAGE_MULTIPLE);
}
now check onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// When an Image is picked
if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == Activity.RESULT_OK
&& null != data
) {
if (data.getClipData() != null) {
var count = data.clipData.itemCount
for (i in 0..count - 1) {
var imageUri: Uri = data.clipData.getItemAt(i).uri
getPathFromURI(imageUri)
}
} else if (data.getData() != null) {
var imagePath: String = data.data.path
Log.e("imagePath", imagePath);
}
displayImageData()
}
}
private fun getPathFromURI(uri: Uri) {
var path: String = uri.path // uri = any content Uri
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (path.contains("/document/image:")) { // files selected from "Documents"
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
databaseUri = uri
selection = null
selectionArgs = null
}
try {
val projection = arrayOf(
MediaStore.Images.Media.DATA,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.DATE_TAKEN
) // some example data you can query
val cursor = contentResolver.query(
databaseUri,
projection, selection, selectionArgs, null
)
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(projection[0])
imagePath = cursor.getString(columnIndex)
// Log.e("path", imagePath);
imagesPathList.add(imagePath)
}
cursor.close()
} catch (e: Exception) {
Log.e(TAG, e.message, e)
}
}
This is a solution using Github repo for your requirement.
In your app gradle file add these lines
implementation 'com.github.esafirm.android-image-picker:imagepicker:1.13.1'
// for experimental rx picker
implementation 'com.github.esafirm.android-image-picker:rximagepicker:1.13.1'
// If you have a problem with Glide, please use the same Glide version or simply open an issue
implementation 'com.github.bumptech.glide:glide:4.8.0'
in Java class call this to pick or take image
startActivityForResult(ImagePicker.create(getActivity())
.multi()
.folderMode(true)
.returnMode(ReturnMode.ALL)
.getIntent(getActivity()), IpCons.RC_IMAGE_PICKER);
and in onActivityResult() get the arraylist of selected images
#Override
protected void onActivityResult(int requestCode, final int resultCode, Intent data) {
if (ImagePicker.shouldHandle(requestCode, resultCode, data)) {
// Get a list of picked images
List<Image> images = ImagePicker.getImages(data)
// do your stuff here
// or get a single image only
//Image image = ImagePicker.getFirstImageOrNull(data)
}
super.onActivityResult(requestCode, resultCode, data);
}
This code is less complex and no need to handle image multiple selection , just adding multi() to enable multiple selection.
Note:- Copy this code and paste in your kotlin project , the converter will
automatically convert it to kotlin

Categories

Resources