Detect only screenshot with FileObserver Android

前端 未结 4 1471
失恋的感觉
失恋的感觉 2020-12-13 07:25

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

4条回答
  •  被撕碎了的回忆
    2020-12-13 08:13

    I made a git project for Android screenshot detection using Content Observer.

    It is working fine from API 14 to the most recent version (at the time of posting).


    1.ScreenShotContentObserver .class
    (original screenshot delete -> inform screenshot taken and give screenshot bitmap )

    public class ScreenShotContentObserver extends ContentObserver {
    
        private final String TAG = this.getClass().getSimpleName();
        private static final String[] PROJECTION = new String[]{
                MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.DATE_ADDED, MediaStore.Images.ImageColumns._ID
        };
        private static final long DEFAULT_DETECT_WINDOW_SECONDS = 10;
        private static final String SORT_ORDER = MediaStore.Images.Media.DATE_ADDED + " DESC";
    
        public static final String FILE_POSTFIX = "FROM_ASS";
        private static final String WATERMARK = "Scott";
        private ScreenShotListener mListener;
        private ContentResolver mContentResolver;
        private String lastPath;
    
        public ScreenShotContentObserver(Handler handler, ContentResolver contentResolver, ScreenShotListener listener) {
            super(handler);
            mContentResolver = contentResolver;
            mListener = listener;
        }
    
        @Override
        public boolean deliverSelfNotifications() {
            Log.e(TAG, "deliverSelfNotifications");
            return super.deliverSelfNotifications();
        }
    
        @Override
        synchronized public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                //above API 16 Pass~!(duplicated call...)
                return;
            }
            Log.e(TAG, "[Start] onChange : " + selfChange);
            try {
                process(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                Log.e(TAG, "[Finish] general");
            } catch (Exception e) {
                Log.e(TAG, "[Finish] error : " + e.toString(), e);
            }
        }
    
        @Override
        synchronized public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            Log.e(TAG, "[Start] onChange : " + selfChange + " / uri : " + uri.toString());
    
            if (uri.toString().startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) {
                try {
                    process(uri);
                    Log.e(TAG, "[Finish] general");
                } catch (Exception e) {
                    Log.e(TAG, "[Finish] error : " + e.toString(), e);
                }
            } else {
                Log.e(TAG, "[Finish] not EXTERNAL_CONTENT_URI ");
            }
        }
    
        public void register() {
            Log.d(TAG, "register");
            mContentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, this);
        }
    
        public void unregister() {
            Log.d(TAG, "unregister");
            mContentResolver.unregisterContentObserver(this);
        }
    
        private boolean process(Uri uri) throws Exception {
            Data result = getLatestData(uri);
            if (result == null) {
                Log.e(TAG, "[Result] result is null!!");
                return false;
            }
            if (lastPath != null && lastPath.equals(result.path)) {
                Log.e(TAG, "[Result] duplicate!!");
                return false;
            }
            long currentTime = System.currentTimeMillis() / 1000;
            if (matchPath(result.path) && matchTime(currentTime, result.dateAdded)) {
                lastPath = result.path;
                Uri screenUri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/" + result.id);
                Log.e(TAG, "[Result] This is screenshot!! : " + result.fileName + " | dateAdded : " + result.dateAdded + " / " + currentTime);
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContentResolver, screenUri);
                Bitmap copyBitmap = bitmap.copy(bitmap.getConfig(), true);
                bitmap.recycle();
                int temp = mContentResolver.delete(screenUri, null, null);
                Log.e(TAG, "Delete Result : " + temp);
                if (mListener != null) {
                    mListener.onScreenshotTaken(copyBitmap, result.fileName);
                }
                return true;
            } else {
                Log.e(TAG, "[Result] No ScreenShot : " + result.fileName);
            }
            return false;
        }
    
        private Data getLatestData(Uri uri) throws Exception {
            Data data = null;
            Cursor cursor = null;
            try {
                cursor = mContentResolver.query(uri, PROJECTION, null, null, SORT_ORDER);
                if (cursor != null && cursor.moveToFirst()) {
                    long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID));
                    String fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    long dateAdded = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
    
                    if (fileName.contains(FILE_POSTFIX)) {
                        if (cursor.moveToNext()) {
                            id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID));
                            fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
                            path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                            dateAdded = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
                        } else {
                            return null;
                        }
                    }
    
                    data = new Data();
                    data.id = id;
                    data.fileName = fileName;
                    data.path = path;
                    data.dateAdded = dateAdded;
                    Log.e(TAG, "[Recent File] Name : " + fileName);
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
            return data;
        }
    
        private boolean matchPath(String path) {
            return (path.toLowerCase().contains("screenshots/") && !path.contains(FILE_POSTFIX));
        }
    
        private boolean matchTime(long currentTime, long dateAdded) {
            return Math.abs(currentTime - dateAdded) <= DEFAULT_DETECT_WINDOW_SECONDS;
        }
    
        class Data {
            long id;
            String fileName;
            String path;
            long dateAdded;
        }
    }
    
    1. Util.class

      public static void saveImage(Context context, Bitmap bitmap, String title) throws Exception {
          OutputStream fOut = null;
          title = title.replaceAll(" ", "+");
          int index = title.lastIndexOf(".png");
          String fileName = title.substring(0, index) + ScreenShotContentObserver.FILE_POSTFIX + ".png";
          final String appDirectoryName = "Screenshots";
          final File imageRoot = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appDirectoryName);
          imageRoot.mkdirs();
          final File file = new File(imageRoot, fileName);
          fOut = new FileOutputStream(file);
      
          bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
          fOut.flush();
          fOut.close();
      
          ContentValues values = new ContentValues();
          values.put(MediaStore.Images.Media.TITLE, "XXXXX");
          values.put(MediaStore.Images.Media.DESCRIPTION, "description here");
          values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
          values.put(MediaStore.Images.ImageColumns.BUCKET_ID, file.hashCode());
          values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, file.getName());
          values.put("_data", file.getAbsolutePath());
          ContentResolver cr = context.getContentResolver();
          Uri newUri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
          context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
      }
      

提交回复
热议问题