Screen capture and recording callbacks

      Technique summary
    Technique Screen capture and recording callbacks
    Against Screen recording attacks
    Limitations Screen recording callback requires Android ≥15 and the DETECT_SCREEN_RECORDING permission
    Screen capture callback requires Android ≥14 and the DETECT_SCREEN_CAPTURE permission
    The screen recording callback will not trigger if the recording is started before the callback is registered, unless the application is paused and resumed
    Side effects None
    Recommendations Screen recording callback can be used for applications running on Android 15 and newer. Not recommended as a first line of defense, because it can be bypassed by starting recording before the application starts.

    Screen capture callback

    Starting Android 14 you can register a callback that would trigger whenever a screen is captured.

    // The callback function for screen capture private void onScreenCaptureCallback() { Toast.makeText(this, "Screen being captured!!", Toast.LENGTH_LONG).show(); } // Register the callback when your activity starts @Override protected void onStart() { super.onStart(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { registerScreenCaptureCallback(getMainExecutor(), this::onScreenCaptureCallback); } } // Unregister the callback when your activity stops @Override protected void onStop() { super.onStop(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { try { unregisterScreenCaptureCallback(this::onScreenCaptureCallback); } catch(IllegalStateException e) { System.err.println(e.getCause()); e.printStackTrace(); } } } // The callback function for screen capture private fun onScreenCaptureCallback() { Toast.makeText(this, "Screen being captured!!", Toast.LENGTH_LONG).show() } // Register the callback when your activity starts override fun onStart() { super.onStart() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { registerScreenCaptureCallback(mainExecutor) { onScreenCaptureCallback() } } } // Unregister the callback when your activity stops override fun onStop() { super.onStop() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { try { unregisterScreenCaptureCallback { onScreenCaptureCallback() } } catch (e: IllegalStateException) { System.err.println(e.cause) e.printStackTrace() } } }

    Screen recording callback

    Android 15 provides a means to know when there is a change on the screen recording state. It is possible to register a callback to be called whenever there is a change. The callback receives the state, which can be compared with the values WindowManager.SCREEN_RECORDING_STATE_VISIBLE and WindowManager.SCREEN_RECORDING_STATE_NOT_VISIBLE. The callback can run on the main thread or in a background thread.

    For example:

    public void enableScreenDetection(Activity activity) { Context context = activity.getApplicationContext(); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { Log.d(TAG, "Enabling screen detection (only for Android 15)"); Executor executor = Executors.newSingleThreadExecutor(); // background thread // Executor executor = context.getMainExecutor(); // main thread windowManager.addScreenRecordingCallback(executor, state -> { if (state == WindowManager.SCREEN_RECORDING_STATE_VISIBLE) { showMessageOnToast(activity, "[!] Screen recording started!"); Log.d(TAG, "Recording"); } else if (state == WindowManager.SCREEN_RECORDING_STATE_NOT_VISIBLE) { showMessageOnToast(activity, "[!] Screen recording stopped"); Log.d(TAG, "Not recording"); } }); } else { showMessageOnToast(activity, "Screen detection is only available from Android 15"); } } private void showMessageOnToast(Activity activity, String message) { activity.runOnUiThread(() -> Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()); }

    Guardsquare

    Table of contents