Detect only screenshot with FileObserver Android

前端 未结 4 1476
失恋的感觉
失恋的感觉 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:01

    I have improve the code from alijandro's comment to make it easy-to-use class and fix the problem when content observer has detect the image from camera (should be screenshot image only). Then wrap it to delegate class for convenient to use.


    • ScreenshotDetectionDelegate.java

    public class ScreenshotDetectionDelegate {
        private WeakReference activityWeakReference;
        private ScreenshotDetectionListener listener;
    
        public ScreenshotDetectionDelegate(Activity activityWeakReference, ScreenshotDetectionListener listener) {
            this.activityWeakReference = new WeakReference<>(activityWeakReference);
            this.listener = listener;
        }
    
        public void startScreenshotDetection() {
            activityWeakReference.get()
                    .getContentResolver()
                    .registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver);
        }
    
        public void stopScreenshotDetection() {
            activityWeakReference.get().getContentResolver().unregisterContentObserver(contentObserver);
        }
    
        private ContentObserver contentObserver = new ContentObserver(new Handler()) {
            @Override
            public boolean deliverSelfNotifications() {
                return super.deliverSelfNotifications();
            }
    
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);
            }
    
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                super.onChange(selfChange, uri);
                if (isReadExternalStoragePermissionGranted()) {
                    String path = getFilePathFromContentResolver(activityWeakReference.get(), uri);
                    if (isScreenshotPath(path)) {
                        onScreenCaptured(path);
                    }
                } else {
                    onScreenCapturedWithDeniedPermission();
                }
            }
        };
    
        private void onScreenCaptured(String path) {
            if (listener != null) {
                listener.onScreenCaptured(path);
            }
        }
    
        private void onScreenCapturedWithDeniedPermission() {
            if (listener != null) {
                listener.onScreenCapturedWithDeniedPermission();
            }
        }
    
        private boolean isScreenshotPath(String path) {
            return path != null && path.toLowerCase().contains("screenshots");
        }
    
        private String getFilePathFromContentResolver(Context context, Uri uri) {
            try {
                Cursor cursor = context.getContentResolver().query(uri, new String[]{
                        MediaStore.Images.Media.DISPLAY_NAME,
                        MediaStore.Images.Media.DATA
                }, null, null, null);
                if (cursor != null && cursor.moveToFirst()) {
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    cursor.close();
                    return path;
                }
            } catch (IllegalStateException ignored) {
            }
            return null;
        }
    
        private boolean isReadExternalStoragePermissionGranted() {
            return ContextCompat.checkSelfPermission(activityWeakReference.get(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        }
    
        public interface ScreenshotDetectionListener {
            void onScreenCaptured(String path);
    
            void onScreenCapturedWithDeniedPermission();
        }
    }
    

    • ScreenshotDetectionActivity.java

    import android.Manifest;
    import android.content.pm.PackageManager;
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.Toast;
    
    public abstract class ScreenshotDetectionActivity extends AppCompatActivity implements ScreenshotDetectionDelegate.ScreenshotDetectionListener {
        private static final int REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION = 3009;
    
        private ScreenshotDetectionDelegate screenshotDetectionDelegate = new ScreenshotDetectionDelegate(this, this);
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            checkReadExternalStoragePermission();
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            screenshotDetectionDelegate.startScreenshotDetection();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            screenshotDetectionDelegate.stopScreenshotDetection();
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION:
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        showReadExternalStoragePermissionDeniedMessage();
                    }
                    break;
                default:
                    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    
        @Override
        public void onScreenCaptured(String path) {
            // Do something when screen was captured
        }
    
        @Override
        public void onScreenCapturedWithDeniedPermission() {
            // Do something when screen was captured but read external storage permission has denied
        }
    
        private void checkReadExternalStoragePermission() {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestReadExternalStoragePermission();
            }
        }
    
        private void requestReadExternalStoragePermission() {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION);
        }
    
        private void showReadExternalStoragePermissionDeniedMessage() {
            Toast.makeText(this, "Read external storage permission has denied", Toast.LENGTH_SHORT).show();
        }
    }
    

    • MainActivity.java

    import android.os.Bundle;
    import android.view.View;
    import android.widget.Toast;
    
    public class MainActivity extends ScreenshotDetectionActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        public void onScreenCaptured(String path) {
            Toast.make(this, path, Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onScreenCapturedWithDeniedPermission() {
            Toast.make(this, "Please grant read external storage permission for screenshot detection", Toast.LENGTH_SHORT).show();
        }
    }
    

提交回复
热议问题