Read about Kotlin Select Multiple Video From Gallery programmatically.
We will create video picker which enables the user to select multiple videos.
Once the user selects multiple videos, compiler will get the paths of all the selected videos.
When you are making app application when you need to select one or more video from internal storage of the android device, this tutorial will help you to implement this feature.
After selecting the videos, we will preview them inside the video view thus we will be able to get the video paths also.
First of all, see the below video to learn how our example will work.
Step 1. Granting Permission
Make a new project in the android studio with kotlin as the main source language.
Along with this, also make empty activity as the default one.
Now in your new project, open AndroidManifest.xml file. You need to add the below line in it
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
This line will allow us to read all the video of the android device.
If do not ask permission from user then we will not be able to read video from the android device.
This permission is some what dangerous for the user privacy, thus we will write runtime permission for it in the Main activity kotlin file.
Step 2. Writing Gradle
Asking runtime permission from user with android’s native code lines is little complex.
So we will use external library for this purpose.
Now open build.gradle(Module:app) file. Add the following in it
implementation 'com.karumi:dexter:5.0.0'
This line will add some code lines in our project which creates the dexter library.
Dexter library can save our time and coding lines in the process of asking runtime permission from the user.
This library will help us to implement the runtime permissions in the smoothest possible way.
Step 3. Main Files Alteration
There should be two files in your project : activity_main.xml and MainActivity.kt
In your activity_main.xml file, add the below code lines
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <VideoView android:layout_width="150dp" android:layout_height="150dp" android:id="@+id/vv" android:layout_marginTop="10dp" android:layout_marginLeft="10dp"/> <VideoView android:layout_width="150dp" android:layout_height="150dp" android:id="@+id/vv2" android:layout_marginTop="10dp" android:layout_marginLeft="10dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn" android:layout_marginTop="10dp" android:text="Select Multiple Videos From Gallery"/> </LinearLayout>
There are two video views and one button is there.
When the user clicks the button, compiler will open new screen to show all the videos of the device.
Video views will preview the selected videos. There are two video views in total.
Now Write down the below code snippet in the MainActivity.kt file.
import android.Manifest import android.annotation.SuppressLint import android.app.Activity import android.content.ContentUris import android.content.Context import android.content.Intent import android.database.Cursor import android.net.Uri import android.os.Build import android.os.Environment import android.provider.DocumentsContract import android.provider.MediaStore import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.annotation.RequiresApi import android.util.Log import android.widget.Button import android.widget.Toast import android.widget.VideoView import com.karumi.dexter.Dexter import com.karumi.dexter.MultiplePermissionsReport import com.karumi.dexter.PermissionToken import com.karumi.dexter.listener.DexterError import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.PermissionRequestErrorListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener import java.util.ArrayList class MainActivity : AppCompatActivity() { private var videoView: VideoView? = null private var videoView2: VideoView? = null private var btn: Button? = null private var selectedVideos: List<String>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestReadPermissions() btn = findViewById(R.id.btn) as Button videoView = findViewById(R.id.vv) as VideoView videoView2 = findViewById(R.id.vv2) as VideoView btn!!.setOnClickListener { if (Build.VERSION.SDK_INT < 19) { val intent = Intent() intent.type = "video/mp4" intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) intent.action = Intent.ACTION_GET_CONTENT startActivityForResult(Intent.createChooser(intent, "Select videos"), SELECT_VIDEOS) } else { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) intent.type = "video/mp4" startActivityForResult(intent, SELECT_VIDEOS_KITKAT) } } } @RequiresApi(Build.VERSION_CODES.JELLY_BEAN) public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { selectedVideos = getSelectedVideos(requestCode, data!!) Log.d("path", selectedVideos!!.toString()) videoView!!.setVideoPath(selectedVideos!![0]) videoView!!.requestFocus() videoView!!.start() if (selectedVideos!!.size > 1) { videoView2!!.setVideoPath(selectedVideos!![1]) videoView2!!.requestFocus() videoView2!!.start() } } } @RequiresApi(Build.VERSION_CODES.JELLY_BEAN) private fun getSelectedVideos(requestCode: Int, data: Intent): List<String> { val result = ArrayList<String>() val clipData = data.clipData if (clipData != null) { for (i in 0 until clipData.itemCount) { val videoItem = clipData.getItemAt(i) val videoURI = videoItem.uri val filePath = getPath(this, videoURI) if (filePath != null) { result.add(filePath) } } } else { val videoURI = data.data val filePath = getPath(this, videoURI) if (filePath != null) { result.add(filePath) } } return result } companion object { private val TAG = "VideoPickerActivity" private val SELECT_VIDEOS = 1 private val SELECT_VIDEOS_KITKAT = 1 @SuppressLint("NewApi") fun getPath(context: Context, uri: Uri?): String? { val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri!!)) { val docId = DocumentsContract.getDocumentId(uri) val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val type = split[0] if ("primary".equals(type, ignoreCase = true)) { return Environment.getExternalStorageDirectory().toString() + "/" + split[1] } // TODO handle non-primary volumes } else if (isDownloadsDocument(uri)) { val id = DocumentsContract.getDocumentId(uri) val contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id) ) return getDataColumn(context, contentUri, null, null) } else if (isMediaDocument(uri)) { val docId = DocumentsContract.getDocumentId(uri) val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val type = split[0] var contentUri: Uri? = null if ("image" == type) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI } else if ("video" == type) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI } else if ("audio" == type) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI } val selection = "_id=?" val selectionArgs = arrayOf(split[1]) return getDataColumn(context, contentUri, selection, selectionArgs) }// MediaProvider // DownloadsProvider } else if ("content".equals(uri!!.scheme!!, ignoreCase = true)) { // Return the remote address return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null) } else if ("file".equals(uri.scheme!!, ignoreCase = true)) { return uri.path }// File // MediaStore (and general) return null } fun getDataColumn( context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>? ): String? { var cursor: Cursor? = null val column = "_data" val projection = arrayOf(column) try { cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null) if (cursor != null && cursor.moveToFirst()) { val index = cursor.getColumnIndexOrThrow(column) return cursor.getString(index) } } finally { cursor?.close() } return null } /** * @param uri The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. */ fun isExternalStorageDocument(uri: Uri): Boolean { return "com.android.externalstorage.documents" == uri.authority } /** * @param uri The Uri to check. * @return Whether the Uri authority is DownloadsProvider. */ fun isDownloadsDocument(uri: Uri): Boolean { return "com.android.providers.downloads.documents" == uri.authority } /** * @param uri The Uri to check. * @return Whether the Uri authority is MediaProvider. */ fun isMediaDocument(uri: Uri): Boolean { return "com.android.providers.media.documents" == uri.authority } /** * @param uri The Uri to check. * @return Whether the Uri authority is Google Photos. */ fun isGooglePhotosUri(uri: Uri): Boolean { return "com.google.android.apps.photos.content" == uri.authority } } private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog(); } } override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) { token.continuePermissionRequest() } }).withErrorListener(object : PermissionRequestErrorListener { override fun onError(error: DexterError) { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } }) .onSameThread() .check() } }
More Focus
First of all, see the following code snippet
private var videoView: VideoView? = null private var videoView2: VideoView? = null private var btn: Button? = null private var selectedVideos: List<String>? = null
For the first two lines, compiler will create the objects of the Video view class.
Then, it will give us the button class’s object.
Last line will create the arrayList with the string variables. It’s name would be selectedVideos
In the onCreate() method, compiler will run the requestReadpermissions() method.
Following are the source lines for requestReadpermissions() method.
private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog(); } } override fun onPermissionRationaleShouldBeShown(permissions: List<PermissionRequest>, token: PermissionToken) { token.continuePermissionRequest() } }).withErrorListener(object : PermissionRequestErrorListener { override fun onError(error: DexterError) { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } }) .onSameThread() .check() }
This method is implementing the runtime permissions.
In this process, we are using Dexter library which have integrated in our project during step 2.
It will ask user to grant Read external storage permission so that we can read all the videos from the android device of the user.
Compiler will follow the below coding lines when the user clicks the button.
btn!!.setOnClickListener { if (Build.VERSION.SDK_INT < 19) { val intent = Intent() intent.type = "video/mp4" intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) intent.action = Intent.ACTION_GET_CONTENT startActivityForResult(Intent.createChooser(intent, "Select videos"), SELECT_VIDEOS) } else { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) intent.type = "video/mp4" startActivityForResult(intent, SELECT_VIDEOS_KITKAT) } }
On the button click, if the android device have version of android less than 19, it will go to if() block otherwise it will run else() block.
Inside both the blocks, compiler will create one intent object.
It will attach some settings like Video,mp4, Allow multiple etc. to the intent.
Now using this intent, compiler will start new activity.
This activity will show up all the videos of the android device.
User can select one or more videos from this screen.
When the user have selected his desired videos, compiler will execute the onActivityResult() method.
Following is the source snippet for onActivityResult() method.
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN) public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { selectedVideos = getSelectedVideos(requestCode, data!!) Log.d("path", selectedVideos!!.toString()) videoView!!.setVideoPath(selectedVideos!![0]) videoView!!.requestFocus() videoView!!.start() if (selectedVideos!!.size > 1) { videoView2!!.setVideoPath(selectedVideos!![1]) videoView2!!.requestFocus() videoView2!!.start() } } }
In this method, compiler will first get the paths of all the selected videos using getSelecetdVideos() method.
After this, it will set the videos into the video views to preview them.
If user have selected more than one video than only compiler will preview the second video view otherwise not.
Download Kotlin Select Multiple Video From Github
https://github.com/demonuts/Kotlin-Select-Multiple-Video-From-Gallery-programmatically-Video-Picker