I am currently developing an application for Android and wanted to know how to detect a screenshot. I tried with FileObserver but the problem is that all events are detected ( when device goes into sleep, message, etc. ) . How to detect only screenshot ?
Thank you in advance !
How did you use FileObserver
to detect screen shot creation? When using FileObserver
, only monitor the file creation event in screen shot directory.
String path = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES
+ File.separator + "Screenshots" + File.separator;
Log.d(TAG, path);
FileObserver fileObserver = new FileObserver(path, FileObserver.CREATE) {
@Override
public void onEvent(int event, String path) {
Log.d(TAG, event + " " + path);
}
};
fileObserver.startWatching();
Don't forget to declare corresponding permissions to access content in SD card.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Another solution to detect the screen shot is using ContentObserver
, because there will be a record inserted to the system media database after screen shot. Following is the code snippet using ContentObserver
to monitor the event. By using ContentObserver
, it's not necessary to declare write/read external storage
permissions, but you have to do some filters on the file name to make sure it's a screen shot event.
HandlerThread handlerThread = new HandlerThread("content_observer");
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
getContentResolver().registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
true,
new ContentObserver(handler) {
@Override
public boolean deliverSelfNotifications() {
Log.d(TAG, "deliverSelfNotifications");
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "onChange " + uri.toString());
if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/[0-9]+")) {
Cursor cursor = null;
try {
cursor = getContentResolver().query(uri, new String[] {
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA
}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final String fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
final String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
// TODO: apply filter on the file name to ensure it's screen shot event
Log.d(TAG, "screen shot added " + fileName + " " + path);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
super.onChange(selfChange, uri);
}
}
);
Updated
If you use second method, you have to request READ_EXTERNAL_STORAGE
after version Android M, otherwise it will throw SecurityException
. For more information how to request runtime permission, refer here.