Android 系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。
由于厂商自定义 Android 系统的多样性,再加上快捷键的不同以及第三方应用,监听截屏快捷键这事基本不靠谱,可以直接忽略。
本文使用的测试手机,一加 2(One Plus 2)。
添加权限:
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
- />
代码示例:
- public class ScreenshotActivity extends AppCompatActivity {
- private final String TAG = "Screenshot";
- private static final String PATH = Environment.getExternalStorageDirectory() + File.separator
- + Environment.DIRECTORY_PICTURES + File.separator + "Screenshots" + File.separator;
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_screenshot);
- mFileObserver = new CustomFileObserver(PATH);
- }
- @Override
- protected void onResume() {
- super.onResume();
- mFileObserver.startWatching();
- Log.d(TAG, PATH);
- }
- @Override
- protected void onStop() {
- super.onStop();
- mFileObserver.stopWatching();
- }
- /**
- * 目录监听器
- */
- private class CustomFileObserver extends FileObserver {
- private String mPath;
- public CustomFileObserver(String path) {
- super(path);
- this.mPath = path;
- }
- public CustomFileObserver(String path, int mask) {
- super(path, mask);
- this.mPath = path;
- }
- @Override
- public void onEvent(int event, String path) {
- Log.d(TAG, path + " " + event);
- // 监听到事件,做一些过滤去重处理操作
- }
- }
- }
打印的日志:
一加 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 256
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 32
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2
- D/Screenshot: Screenshot_2016-12-16-17-49-18.png 8
三星 S4
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 256
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 32
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 8
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 32
- D/Screenshot: Screenshot_2016-12-16-19-01-08.png 16
可以通过指定构造函数中的 mask,监听某一个事件。
类型 | int 值 | 说明 |
---|---|---|
FileObserver.ACCESS | 1 | 读取某个文件 |
FileObserver.MODIFY | 2 | 向某个文件写入数据 |
FileObserver.ATTRIB | 4 | 文件的属性被修改(权限 / 日期 / 拥有者) |
FileObserver.CLOSE_WRITE | 8 | 写入数据后关闭 |
FileObserver.CLOSE_NOWRITE | 16 | 只读模式打开文件后关闭 |
FileObserver.OPEN | 32 | 打开某个文件 |
FileObserver.MOVED_FROM | 64 | 有文件或者文件夹从被监听的文件夹中移走 |
FileObserver.MOVED_TO | 128 | 有文件或者文件夹移动到被监听的文件夹 |
FileObserver.CREATE | 256 | 文件或者文件夹被创建 |
FileObserver.DELETE | 512 | 文件被删除 |
FileObserver.DELETE_SELF | 1024 | 被监听的文件或者目录被删除 |
FileObserver.MOVE_SELF | 2048 | 被监听的文件或者目录被移走 |
几点注意事项:
权限,否则可能收不到事件
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
基于第三点和第四点,这种方法并不能适用于所有的机型。
注意:如果自己写 Demo 没有收到事件,检查一下权限和监听的目录
ContentObserver 用来监听指定 uri 的所有资源变化,我们可以用它来监听图片资源变化情况,然后做过滤。
添加权限
- <uses-permission android:name="MediaStore.Images.Media.INTERNAL_CONTENT_URI"
- />
- <uses-permission android:name="MediaStore.Images.Media.EXTERNAL_CONTENT_URI"
- />
代码示例:
- public class ScreenshotActivity extends AppCompatActivity {
- private static final String[] KEYWORDS = {
- "screenshot", "screen_shot", "screen-shot", "screen shot",
- "screencapture", "screen_capture", "screen-capture", "screen capture",
- "screencap", "screen_cap", "screen-cap", "screen cap"
- };
- /** 读取媒体数据库时需要读取的列 */
- private static final String[] MEDIA_PROJECTIONS = {
- MediaStore.Images.ImageColumns.DATA,
- MediaStore.Images.ImageColumns.DATE_TAKEN,
- };
- /** 内部存储器内容观察者 */
- private ContentObserver mInternalObserver;
- /** 外部存储器内容观察者 */
- private ContentObserver mExternalObserver;
- private HandlerThread mHandlerThread;
- private Handler mHandler;
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_screenshot);
- mHandlerThread = new HandlerThread("Screenshot_Observer");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- // 初始化
- mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, mHandler);
- mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mHandler);
- // 添加监听
- this.getContentResolver().registerContentObserver(
- MediaStore.Images.Media.INTERNAL_CONTENT_URI,
- false,
- mInternalObserver
- );
- this.getContentResolver().registerContentObserver(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- false,
- mExternalObserver
- );
- }
- protected void onDestroy() {
- super.onDestroy();
- // 注销监听
- this.getContentResolver().unregisterContentObserver(mInternalObserver);
- this.getContentResolver().unregisterContentObserver(mExternalObserver);
- }
- private void handleMediaContentChange(Uri contentUri) {
- Cursor cursor = null;
- try {
- // 数据改变时查询数据库中最后加入的一条数据
- cursor = this.getContentResolver().query(
- contentUri,
- MEDIA_PROJECTIONS,
- null,
- null,
- MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1"
- );
- if (cursor == null) {
- return;
- }
- if (!cursor.moveToFirst()) {
- return;
- }
- // 获取各列的索引
- int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
- int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);
- // 获取行数据
- String data = cursor.getString(dataIndex);
- long dateTaken = cursor.getLong(dateTakenIndex);
- // 处理获取到的第一行数据
- handleMediaRowData(data, dateTaken);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (cursor != null && !cursor.isClosed()) {
- cursor.close();
- }
- }
- }
- /**
- * 处理监听到的资源
- */
- private void handleMediaRowData(String data, long dateTaken) {
- if (checkScreenShot(data, dateTaken)) {
- Log.d(TAG, data + " " + dateTaken);
- } else {
- Log.d(TAG, "Not screenshot event");
- }
- }
- /**
- * 判断是否是截屏
- */
- private boolean checkScreenShot(String data, long dateTaken) {
- data = data.toLowerCase();
- // 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了
- for (String keyWork : KEYWORDS) {
- if (data.contains(keyWork)) {
- return true;
- }
- }
- return false;
- }
- /**
- * 媒体内容观察者(观察媒体数据库的改变)
- */
- private class MediaContentObserver extends ContentObserver {
- private Uri mContentUri;
- public MediaContentObserver(Uri contentUri, Handler handler) {
- super(handler);
- mContentUri = contentUri;
- }
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- Log.d(TAG, mContentUri.toString());
- handleMediaContentChange(mContentUri);
- }
- }
- }
日志:
- D/Screenshot: content://media/external/images/media
- D/Screenshot: /storage/emulated/0/Pictures/Screenshots/Screenshot_2016-12-19-11-24-02.png 1482117842287
注意事项:
目前这是在网上搜索到的关于截屏监听方法的总结,如果大家还有什么比较好的监听方法,欢迎分享。
参考:
来源: