Detect Screenshots in Android
By: Nikit Bhandari
Tags: Android App Development, Android Apps, Android, AndroidDev, Kotlin

Photo by Daniel Romero on Unsplash

Recently I was figuring out ways to detect screenshots in Android. It turns out there is no official API to do that but there are workarounds to detect if a user has taken a screenshot while using the app.

You might have wondered how apps like Snapchat and Instagram can detect screenshots as soon as you take one. In this blog post, we will be exploring how to do that.

The approach is straightforward and to be honest when I found out what the solution is, I couldn’t believe how simple the solution was. Basically, when the user is using the app we will check the images in their device and see if a new image has been added in the “Screenshots” folder. That’s it!

Let’s dive straight into the code

We would be using a ContentObserver to observe any changes in the images in the user’s device. It takes a Handler as a parameter and the onChange method gets triggered every time there is a change detected in the URI that we specify.

Next, we need to register the ContentObserver , the registerContentObserver method takes three arguments. The first is the URI that the ContentObserver would be observing. The second parameter notifyForDescendants should be true if we want to observe changes for all URIs that start with the URI that we have specified otherwise if we want to be notified only when changes occur to that exact URI this parameter can be false . The last parameter is the ContentObserver that we want to register.

So now that we have registered our ContentObserver let’s see how to detect screenshots. The idea is simple whenever there is a change in the media files while the user is using the app, we will get the URI and then we will try to extract the file path from that URI. We can use the DATA attribute of the MediaStore.Images API to get the file path but that attribute has been deprecated in API 29, although that attribute is still there even in API 30 it is mentioned in the documentation that the developers should not assume that the file will always be available. In API 29, a new attribute called RELATIVE_PATH has been introduced. So for devices having API 29 or higher we can use RELATIVE_PATH and DISPLAY_NAME to get the file path of the screenshot file and for other devices, we can continue to use the DATA attribute.

In the following code snippet, we are querying the DATA attribute using the URI that was returned to us from the ContentObserver . If that path contains the string “screenshot” anywhere in it, we can conclude that the user has taken a screenshot.

Similarly the same can be done using DISPLAY_NAME and RELATIVE_PATH like it has been done in the code snippet below.

Don’t forget to unregister the ContentObserver when the user is not using your app. You can do it in the onStop .

Since we are accessing the media files of the user’s device, we need to add that permission in the AndroidManifest.xml

So if you know any app that tracks screenshots while you are using the app, you can simply revoke this permission and the app will not be able to track when you take screenshots, I tried doing this in the Instagram app and they were not able to detect when I took a screenshot. Although if you do this in Snapchat they simply won’t allow you to use the app.

This solution would only work for devices that store the screenshots in the “Screenshots” folder or the file name has the string “screenshot” in it. In a stock Android device, the screenshots would be saved in the “Screenshots” folders but if the OEM decides to change that we can’t detect those screenshots. Anyway if you find an exception like that you can easily add another check for that directory since you already have the file path as it is returned from the ContentObserver .

The GitHub repository of the project has been linked below, feel free to play with the app.

If you have any kind of feedback, feel free to connect with me on Twitter.