Android监听用户截屏、投屏、录屏行为

一.截屏

方案一:使用系统广播监听截屏操作

​ 从Android Q(10.0)开始,Intent.ACTION_SCREEN_CAPTURED_CHANGED字段不再被支持。这是因为Google安卓10 中引入一个新的隐私限制,即限制应用用户开启屏幕录制功能截屏功能获取相应的广播。

  1. 创建一个BroadcastReceiver类来接收截屏广播:
public class ScreenCaptureReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_SCREEN_CAPTURES_CHANGED.equals(action)) {
            // 截屏操作
            // 在这里执行你的逻辑操作
        }
    }
}
  1. 在AndroidManifest.xml文件声明截屏广播接收器
<receiver
    android:name=".ScreenCaptureReceiver"
    android:enabled="true"&gt;
    <intent-filter&gt;
        <action android:name="android.intent.action.SCREEN_CAPTURE_CHANGED" /&gt;
    </intent-filter&gt;
</receiver&gt;
  1. 注册截屏广播接收器,开始监听截屏操作:
ScreenCaptureReceiver receiver = new ScreenCaptureReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_CAPTURE_CHANGED);
registerReceiver(receiver, filter);
  1. 在不需要监听时,记得取消注册截屏广播接收器
unregisterReceiver(receiver);
  1. 在BroadcastReceiver中的onReceive方法可以执行一些逻辑操作,例如显示一个提示消息
public class ScreenCaptureReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_SCREEN_CAPTURE_CHANGED.equals(action)) {
            // 截屏操作
            Toast.makeText(context, "用户进行了截屏操作", Toast.LENGTH_SHORT).show();
        }
    }
}

方案二:使用ContentObserver监听截屏操作

​ 另一种监听截屏操作的方法使用ContentObserver来监听系统截屏文件的变化。以下是一个示例代码

public class ScreenCaptureObserver extends ContentObserver {
    private static final String TAG = "ScreenCaptureObserver";
    private static final String SCREENSHOTS_DIR = Environment.getExternalStorageDirectory().toString() + "/Pictures/Screenshots";
    private Context mContext;

    public ScreenCaptureObserver(Context context) {
        super(null);
        mContext = context;
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        Log.d(TAG, "Screen capture detected");
        if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/[0-9]+")) {
            Cursor cursor = null;
            try {
                cursor = mContext.getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
                if (cursor != null &amp;&amp; cursor.moveToFirst()) {
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    if (path != null &amp;&amp; path.startsWith(SCREENSHOTS_PATH)) {
                        // 此处为用户截屏行为响应逻辑
                    }
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        }
    }

    public void start() {
        ContentResolver contentResolver = mContext.getContentResolver();
        contentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, this);
    }

    public void stop() {
        ContentResolver contentResolver = mContext.getContentResolver();
        contentResolver.unregisterContentObserver(this);
    }
}

使用示例

ScreenCaptureObserver observer = new ScreenCaptureObserver(this);
observer.start();

对比与选型建议

使用 BroadcastReceiver

方案一的优点:

方案一的缺点:

使用 ContentObserver

方案二的优点:

方案二的缺点:

选型建议

​ 根据需求,如果只关心截屏的发生与否,并不需要获取截屏的具体内容方案可以考虑。如果需要获取截屏内容的具体信息方案比较适合。如果只需要监听应用内的截屏操作,方案一比较方便。如果需要监听系统级别的截屏操作,需要使用方案二。

二.录屏

​ 在 Android 开发中,要监听用户的录屏操作,可以使用以下两种方案:

方案一:使用 MediaProjection API

Android 录屏 – 简书 (jianshu.com)

Android Q之后又前台服务限制

  1. 首先,在你的应用创建一个 MediaProjectionManager 对象获取用户录屏权限
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private MediaProjection.Callback projectionCallback;

mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
  1. 请求用户授权录屏权限,在回调中获取 MediaProjection 对象
private static final int REQUEST_CODE_SCREEN_CAPTURE = 1;

Intent intent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(intent, REQUEST_CODE_SCREEN_CAPTURE);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE_SCREEN_CAPTURE &amp;&amp; resultCode == RESULT_OK) {
        mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
        startScreenCapture();
    }
}
  1. 开始屏幕录制,并通过 MediaProjection.Callback 监听录屏状态
private VirtualDisplay virtualDisplay;
private MediaRecorder mediaRecorder;

private void startScreenCapture() {
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    int screenWidth = metrics.widthPixels;
    int screenHeight = metrics.heightPixels;
    int screenDensity = metrics.densityDpi;

    mediaRecorder = new MediaRecorder();
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mediaRecorder.setVideoSize(screenWidth, screenHeight);
    mediaRecorder.setVideoFrameRate(30);
    mediaRecorder.setOutputFile(getOutputFilePath());

    Surface surface = mediaRecorder.getSurface();
    virtualDisplay = mediaProjection.createVirtualDisplay(
            "ScreenCapture",
            screenWidth,
            screenHeight,
            screenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            surface,
            null,
            null);

    mediaRecorder.prepare();
    mediaRecorder.start();

    projectionCallback = new MediaProjection.Callback() {
        @Override
        public void onStop() {
            stopScreenCapture();
        }
    };

    mediaProjection.registerCallback(projectionCallback, null);
}

private void stopScreenCapture() {
    if (virtualDisplay != null) {
        virtualDisplay.release();
        virtualDisplay = null;
    }

    if (mediaRecorder != null) {
        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();
        mediaRecorder = null;
    }

    if (mediaProjection != null) {
        mediaProjection.unregisterCallback(projectionCallback);
        mediaProjection.stop();
        mediaProjection = null;
    }
}

方案二:使用 ContentObserver 监听屏幕录制状态变化

  1. 创建一个继承ContentObserver观察者类,并重写 onChange() 方法
public class ScreenRecordObserver extends ContentObserver {
    private static final String SCREEN_RECORD_STATE_PATH = "/sys/class/graphics/fb0/screen_state";

    private OnScreenRecordStateChangedListener listener;

    public ScreenRecordObserver(Handler handler) {
        super(handler);
    }

    public void setOnScreenRecordStateChangedListener(OnScreenRecordStateChangedListener listener) {
        this.listener = listener;
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        if (listener != null) {
            boolean isRecording = isScreenRecording();
            listener.onScreenRecordStateChanged(isRecording);
        }
    }

    private boolean isScreenRecording() {
        try {
            FileInputStream fis = new FileInputStream(SCREEN_RECORD_STATE_PATH);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis));
            String state = bufferedReader.readLine();
            bufferedReader.close();

            return !"0".equals(state);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }
}

public interface OnScreenRecordStateChangedListener {
    void onScreenRecordStateChanged(boolean isRecording);
}
  1. 注册观察者,监听屏幕录制状态变化。
private ScreenRecordObserver screenRecordObserver;

screenRecordObserver = new ScreenRecordObserver(new Handler());
screenRecordObserver.setOnScreenRecordStateChangedListener(new OnScreenRecordStateChangedListener() {
    @Override
    public void onScreenRecordStateChanged(boolean isRecording) {
        if (isRecording) {
            // 屏幕开始录制
        } else {
            // 屏幕停止录制
        }
    }
});

getContentResolver().registerContentObserver(Uri.parse("content://" + SCREEN_RECORD_STATE_PATH), true, screenRecordObserver);

对比与选型建议

使用 MediaProjection API

方案一的优点:

方案一的缺点:

使用 ContentObserver 监听屏幕录制状态变化

方案二的优点:

方案二的缺点:

  • 不能精确确定录屏的开始和结束时间

  • 无法获取到录屏的具体内容。

选型建议

​ 根据需求,如果需要准确监听录屏的开始和结束时间,并且需要获取到录屏的具体内容,推荐使用方案一。

​ 但如果只是需要知道录屏状态变化,而不关心具体的时间和内容,方案二比较简单方便。

三.投屏

在 Android 开发中,要监听用户的投屏操作,可以使用以下两种方案:

方案一:使用 MediaRouter API

​ 首先,在你的 AndroidManifest.xml 文件添加以下权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  1. 创建一个 MediaRouter.Callback 对象,并重写 onRouteSelected()onRouteUnselected() 方法
private MediaRouter mediaRouter;
private MediaRouter.Callback mediaRouterCallback;

mediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);

mediaRouterCallback = new MediaRouter.Callback() {
    @Override
    public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
        // 投屏开始
    }
    
    @Override
    public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo route) {
        // 投屏结束
    }
};
  1. 注册监听器,并指定监听的路由类型
mediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mediaRouterCallback);

方案二:使用 DisplayManager API

​ 首先,在 AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  1. 创建一个 DisplayManager.DisplayListener 对象,并重写 onDisplayAdded()onDisplayRemoved()onDisplayChanged() 方法
private DisplayManager displayManager;
private DisplayManager.DisplayListener displayListener;

displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);

displayListener = new DisplayManager.DisplayListener() {
    @Override
    public void onDisplayAdded(int displayId) {
        // 投屏开始
    }

    @Override
    public void onDisplayRemoved(int displayId) {
        // 投屏结束
    }

    @Override
    public void onDisplayChanged(int displayId) {
        // 投屏状态变化
    }
};
  1. 注册监听器
displayManager.registerDisplayListener(displayListener, null);

对比与选型建议

使用 MediaRouter API

方案一的优点:

方案一的缺点:

  • 只能监听到路由类型ROUTE_TYPE_LIVE_VIDEO 的投屏操作,其他类型的投屏操作无法监听到。
使用 DisplayManager API

方案二的优点:

  • 可以监听到所有的投屏操作,不限制特定的路由类型
  • 可以监听到投屏的开始和结束时间

方案二的缺点:

  • 需要注册更多的监听器处理投屏状态变化的逻辑
  • 无法获取到具体的投屏内容。
选型建议

​ 根据需求,如果只需要监听特定类型的投屏操作,并且需要获取投屏的具体内容,推荐使用方案一。

​ 如果需要监听所有类型的投屏操作,方案二比较适合。

​ 同时,如果只关心投屏的开始和结束时间,并不需要具体的投屏内容,两种方案都可以考虑

原文地址:https://blog.csdn.net/ldld1717/article/details/134756724

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_36920.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注