These snippets allows grabbing a screenshot of a View or Activity as a bitmap.
There are special version to make this work on SurfaceViews and TextureViews.
To grab a complete Activity, simply apply the snippets below on its root view.
Simple, old method
view.isDrawingCacheEnabled = true
val sourceBitmap = view.drawingCache
val bitmap = sourceBitmap.copy(sourceBitmap.config, false)
These methods are deprecated, but still work. Note that it might not even be necessary to clone the Bitmap, e.g. if you write it directly to a file before it is recycled or modified.
New method (Android O and above)
This is supposed to work a lot better with SurfaceViews, but I have had no success grabbing a still
frame from an ExoPlayer that uses a SurfaceView. However, if you set up ExoPlayer to use a TextureView instead,
this method works, you should use the PixelCopy API:
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(
window,
Rect(
locationOfViewInWindow[0],
locationOfViewInWindow[1],
locationOfViewInWindow[0] + view.width,
locationOfViewInWindow[1] + view.height
), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
},
Handler()
)
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
TextureView special
The above method works with a TextureView as well, but if it is only a TextureView you’re interested in, there is
a shortcut:
val bitmap = textureView.bitmap
Wrapping it all together
In one monster snippet. window is a field availablt in the context of an Activity,
so use requireActivity().window when this is used in a Fragment.
fun createScreenshot(view: View, callback: (Bitmap) -> Unit) {
if (view is TextureView) {
callback(view.bitmap.copy(view.bitmap.config, false))
return
}
window?.let { window ->
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(
window,
Rect(
locationOfViewInWindow[0],
locationOfViewInWindow[1],
locationOfViewInWindow[0] + view.width,
locationOfViewInWindow[1] + view.height
), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
},
Handler()
)
} else {
view.isDrawingCacheEnabled = true
callback(view.drawingCache.copy(view.drawingCache.config, false))
}
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
}
}
