Make example on Kotlin Take Screenshot Programmatically And Share.
This tutorial will guide you to take screenshot of any Particular Layout Programmatically using Kotlin.
We will be able to share the screen shot using various social platforms like facebook, whatsapp, gmail etc.
See the below youtube video for output of this example.
Step 1. New Project With Permissions
Make a new project in the android studio. Set Kotlin as the source language and Empty activity as the default activity.
Now go to your AndroidManifest.xml file. You should add the below lines in this file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
These lines are adding the READ and WRITE permissions in our project.
Now let us implement runtime permissions. For this, open build.gradle (Module: app) file and write the below line in it.
implementation 'com.karumi:dexter:5.0.0'
Above line will integrate the dexter laboratory in our example. It will help us in the implementation of the runtime permissions structure.
We will use the classes of this library in our kotlin file.
Step 2. Taking Screen shot
Now let us take the screen shot programmatically using the Kotlin code.
Go to activity_main.xml file and add the following 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"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="25sp" android:layout_marginTop="10dp" android:text="Take Screenshot Programmatically"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center"> <ImageView android:layout_width="270dp" android:layout_height="0dp" android:id="@+id/iv" android:background="@color/colorAccent" android:scaleType="fitXY" android:layout_weight="1" android:layout_marginTop="10dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnSS" android:layout_marginTop="10dp" android:text="Take Screenshot"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnShare" android:layout_marginTop="10dp" android:text="Share"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnPL" android:layout_marginTop="10dp" android:text="SS of Particular Layout"/> </LinearLayout> </LinearLayout>
Above XML layout file have one text view, one image view and three buttons.
Text view is static and it’s value will remain unchanged. In the image view, we will preview the screen shot.
There are three buttons : TAKE SCREENSHOT , SHARE and SS OF PARTICULAR LAYOUT
Now you should write down the below lines in MainActivity.kt file.
import android.Manifest import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.os.Environment import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.os.StrictMode import android.util.Log import android.view.View import android.widget.Button import android.widget.ImageView import android.widget.Toast 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.io.File import java.io.FileOutputStream import java.util.Date class MainActivity : AppCompatActivity() { private var btnSS: Button? = null private var btnshare: Button? = null private var btnPL: Button? = null private var iv: ImageView? = null private var sharePath = "no" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val builder = StrictMode.VmPolicy.Builder() StrictMode.setVmPolicy(builder.build()) requestReadPermissions() btnSS = findViewById(R.id.btnSS) btnshare = findViewById(R.id.btnShare) btnPL = findViewById(R.id.btnPL) iv = findViewById(R.id.iv) btnSS!!.setOnClickListener { takeScreenshot() } btnshare!!.setOnClickListener { if (sharePath != "no") { share(sharePath) } } btnPL!!.setOnClickListener { val intent = Intent(this@MainActivity, ParticularLayoutActivity::class.java) startActivity(intent) } } private fun takeScreenshot() { val now = Date() android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now) try { // image naming and path to include sd card appending name you choose for file val mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpeg" // create bitmap screen capture val v1 = window.decorView.rootView v1.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(v1.drawingCache) v1.isDrawingCacheEnabled = false val imageFile = File(mPath) val outputStream = FileOutputStream(imageFile) val quality = 100 bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) outputStream.flush() outputStream.close() //setting screenshot in imageview val filePath = imageFile.path val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath) iv!!.setImageBitmap(ssbitmap) sharePath = filePath } catch (e: Throwable) { // Several error may come out with file handling or DOM e.printStackTrace() } } private fun share(sharePath: String) { Log.d("ffff", sharePath) val file = File(sharePath) val uri = Uri.fromFile(file) val intent = Intent(Intent.ACTION_SEND) intent.type = "image/*" intent.putExtra(Intent.EXTRA_STREAM, uri) startActivity(intent) } private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_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 Words
First of all, see the following
private var btnSS: Button? = null private var btnshare: Button? = null private var btnPL: Button? = null private var iv: ImageView? = null private var sharePath = "no"
Compiler will first create the three objects of the Button class. There is one object of Image view.
Then there is a variable named sharePath which will hold the string value.
Now read the following
private fun requestReadPermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_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() }
Above is the code block for the requestReadPermissions() method.
This method is asking for the runtime permissions (read and write) to the user.
We are using the Dexter library in this method.
Now focus on the below lines
btnPL!!.setOnClickListener { val intent = Intent(this@MainActivity, ParticularLayoutActivity::class.java) startActivity(intent) }
Compiler will run the above code when the user clicks the SS OF PARTICULAR LAYOUT button.
It will simply open the ParticularLayoutActivity. We will create this activity in the next step.
Now read the below code
btnSS!!.setOnClickListener { takeScreenshot() }
This line is the click event of the TAKE SCREENSHOT button. Compiler will execute the takeScreenshot() function.
Below are the code lines for the takeScreenshot() function.
private fun takeScreenshot() { val now = Date() android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now) try { // image naming and path to include sd card appending name you choose for file val mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpeg" // create bitmap screen capture val v1 = window.decorView.rootView v1.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(v1.drawingCache) v1.isDrawingCacheEnabled = false val imageFile = File(mPath) val outputStream = FileOutputStream(imageFile) val quality = 100 bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) outputStream.flush() outputStream.close() //setting screenshot in imageview val filePath = imageFile.path val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath) iv!!.setImageBitmap(ssbitmap) sharePath = filePath } catch (e: Throwable) { // Several error may come out with file handling or DOM e.printStackTrace() }
This method is taking the screen shot of the whole screen.
For this it will use various classes like Date, Bitmap, Environment etc.
At last, this method will create the bitmap of the screen which is our final screen shot (screen shot will be an image in the jpeg format). Compiler will preview this bitmap into the Image View.
Now see the below writings
btnshare!!.setOnClickListener { if (sharePath != "no") { share(sharePath) } }
On the click event of SHARE button, compiler will run the above code. It will call the share() method whose coding lines are as the below.
private fun share(sharePath: String) { Log.d("ffff", sharePath) val file = File(sharePath) val uri = Uri.fromFile(file) val intent = Intent(Intent.ACTION_SEND) intent.type = "image/*" intent.putExtra(Intent.EXTRA_STREAM, uri) startActivity(intent) }
In the parameter, this method is getting the path to the screen shot (a path where screen shot image is saved).
Compiler will create one share intent. In this intent, it will bind the screen shot image using the URI of this screen shot image.
You can share the screen shot via this intent. It will allow user to share via whatsapp, instagram, facebbok etc.
Step 3. Screen shot of Any Specific Layout
We have take the screen shot of whole screen in the last step. But what if you want to take screen shot of any particular layout of small piece of screen ?
This step will give you the answer to this question.
So let us make a new activity and give it a name as ParticularLayoutActivity.
In your activity_particular_layout.xml file, add the following source snippet
<?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=".ParticularLayoutActivity"> <ImageView android:layout_width="170dp" android:layout_height="150dp" android:id="@+id/ivpl" android:layout_marginLeft="30dp" android:background="@color/colorAccent" android:layout_marginTop="10dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnim" android:layout_marginTop="10dp" android:text="Take SS of below Image"/> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:id="@+id/image" android:scaleType="fitXY" android:layout_marginTop="10dp" android:layout_marginLeft="10dp" android:src="@mipmap/ic_launcher"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btntx" android:text="Take SS of below TextView"/> <TextView android:layout_width="180dp" android:layout_height="50dp" android:id="@+id/tx" android:gravity="center" android:background="#1be94e" android:textColor="#000" android:text="I'm textview, Take My SS "/> </LinearLayout>
There are two image views in the above file. Two buttons are also there : TAKE SS OF BELOW IMAGE and TAKE SS OF BELOW TEXTVIEW
Now in your ParticularLayoutActivity.kt file, you should write the below lines
import android.graphics.Bitmap import android.graphics.BitmapFactory import android.os.Environment import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Button import android.widget.ImageView import android.widget.TextView import java.io.File import java.io.FileOutputStream import java.util.Date class ParticularLayoutActivity : AppCompatActivity() { private var btnIm: Button? = null private var btntx: Button? = null private var imageView: ImageView? = null private var ivpl: ImageView? = null private var tv: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_particular_layout) btnIm = findViewById(R.id.btnim) btntx = findViewById(R.id.btntx) tv = findViewById(R.id.tx) imageView = findViewById(R.id.image) ivpl = findViewById(R.id.ivpl) btnIm!!.setOnClickListener { takeSS(imageView) } btntx!!.setOnClickListener { takeSS(tv) } } private fun takeSS(v: View?) { val now = Date() android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now) try { // image naming and path to include sd card appending name you choose for file val mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpeg" // create bitmap screen capture v!!.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(v.drawingCache) v.isDrawingCacheEnabled = false val imageFile = File(mPath) val outputStream = FileOutputStream(imageFile) val quality = 100 bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) outputStream.flush() outputStream.close() //setting screenshot in imageview val filePath = imageFile.path val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath) ivpl!!.setImageBitmap(ssbitmap) //sharePath = filePath; } catch (e: Throwable) { // Several error may come out with file handling or DOM e.printStackTrace() } } }
See the following first
btnIm!!.setOnClickListener { takeSS(imageView) }
When the user clicks TAKE SS OF BELOW IMAGE button, compiler will run the above code.
It will execute the takeSS() method. Following is the lines for takeSS() method.
private fun takeSS(v: View?) { val now = Date() android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now) try { // image naming and path to include sd card appending name you choose for file val mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpeg" // create bitmap screen capture v!!.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(v.drawingCache) v.isDrawingCacheEnabled = false val imageFile = File(mPath) val outputStream = FileOutputStream(imageFile) val quality = 100 bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) outputStream.flush() outputStream.close() //setting screenshot in imageview val filePath = imageFile.path val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath) ivpl!!.setImageBitmap(ssbitmap) //sharePath = filePath; } catch (e: Throwable) { // Several error may come out with file handling or DOM e.printStackTrace() } }
This method getting the view in it’s parameter. It will take the screen shot of this view.
This view can be of any type like Image View, Text View , Linear Layout etc.
Compiler will save the screen shot of any particular layout or piece of the screen into the .jpeg format.
Now below is the code block for the click event of the TAKE SS OF BELOW TEXTVIEW button.
btntx!!.setOnClickListener { takeSS(tv) }
It will also call the takeSS() method. Only difference is that, we will give text view in the parameter instead of image view.
Download Code Of Kotlin Take Screenshot
https://github.com/demonuts/Kotlin-Take-Screenshot-Programmatically-And-Share-Particular-Layout