private void getScreenSize() { DisplayMetrics metrics = new DisplayMetrics(); WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.getDefaultDisplay().getRealMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
Log.d(TAG, "屏幕分辨率: " + screenWidth + "x" + screenHeight);
}
// 计算距离下一个 15 秒整点的时间
private void setImageReaderListener() {
if (imageReader != null) {
Handler handler = new Handler(Looper.getMainLooper());
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image screenCopyImageRender = null;
Bitmap PicBitmap = null;
try {
screenCopyImageRender = reader.acquireLatestImage();
if (screenCopyImageRender != null) {
// Log.d(TAG,"新图像以推送"); // logListener.callBack("截图获取成功"); Image.Plane[] planes = screenCopyImageRender.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int imageWidth = screenCopyImageRender.getWidth(); int imageHeight = screenCopyImageRender.getHeight();
// 计算包含填充的宽度
int bitmapWidth = rowStride / pixelStride;
// 确保缓冲区从头开始读取数据
buffer.position(0);
// 重新创建正确大小的 Bitmap
PicBitmap = Bitmap.createBitmap(bitmapWidth, imageHeight, Bitmap.Config.ARGB_8888);
buffer.position(0);
PicBitmap.copyPixelsFromBuffer(buffer);
// currentFullScreenImage = PicBitmap; commonPlay.updateCurrentFullScreenImage(PicBitmap); long currentMillis = System.currentTimeMillis(); int seconds = (int) ((currentMillis / 1000) % 60); // 当前时间的秒数 if (seconds % 15 == 0){ uploadLog(currentEmail,currentRoleName,"图像推送触发"); } } } catch (Exception e) { Log.e(TAG, "处理图像异常", e); } finally { if (screenCopyImageRender != null) { try { screenCopyImageRender.close(); } catch (Exception e) { Log.w(TAG, "Image 已关闭或关闭失败", e); } } }
}
}, handler);
} else {
Log.d(TAG,"镜像为空");
}
}
private void refreshVirtualDisplay(){
Log.d(TAG,"定时刷新 VirtualDisplay");
uploadLog(currentEmail,currentRoleName,"定时刷新 VirtualDisplay");
DelayedTaskExecutor refreshExecutor = new DelayedTaskExecutor();
refreshExecutor.addTask(() -> {
updateCaptureParametersForLandscape();
}, 5*60*1000);
refreshExecutor.setOnAllTasksCompletedListener(()->{
refreshVirtualDisplay();
});
refreshExecutor.executeTasks();
}
private void updateCaptureParametersForLandscape() {
// 1. 更新屏幕尺寸
getScreenSize();
Log.d(TAG, "更新后的屏幕分辨率: " + screenWidth + "x" + screenHeight);
// 2. 创建一个新的 ImageReader ,尺寸为更新后的屏幕宽高
ImageReader newImageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 3);
// 3. 尝试通过反射调用 VirtualDisplay 的 resize 和 setSurface 方法更新参数
if (virtualDisplay != null) {
try {
// 调用 resize(int width, int height, int densityDpi)
Method resizeMethod = virtualDisplay.getClass().getMethod("resize", int.class, int.class, int.class);
resizeMethod.invoke(virtualDisplay, screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi);
Log.d(TAG, "VirtualDisplay 调整尺寸成功");
// 调用 setSurface(Surface surface) 更新 Surface
Method setSurfaceMethod = virtualDisplay.getClass().getMethod("setSurface", Surface.class);
setSurfaceMethod.invoke(virtualDisplay, newImageReader.getSurface());
Log.d(TAG, "VirtualDisplay Surface 更新成功");
} catch (Exception e) {
Log.e(TAG, "更新 VirtualDisplay 失败: " + e.getMessage());
// 如调用失败,可考虑其他处理方式,比如提示用户或者重启录制
}
} else {
// 如果 virtualDisplay 为空,则重新创建一个(但通常不建议这样做,以避免重复授权问题)
virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture", screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, newImageReader.getSurface(), null, null);
Log.d(TAG, "VirtualDisplay 已重新创建");
}
// 4. 关闭旧的 ImageReader 并更新引用
if (imageReader != null) {
imageReader.close();
}
imageReader = newImageReader;
commonPlay = new CommonPlay(context, mediaProjection, mediaProjectionManager, imageReader);
setImageReaderListener();
}
private void startScreenCapture(int resultCode, Intent data) {
// 1️⃣ 获取 MediaProjection
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
getScreenSize();
if (mediaProjection == null) {
Log.e("ScreenCapture", "MediaProjection is null");
return;
}
Log.d(TAG, "startScreenCapture: " + screenWidth + "x" + screenHeight);
// 2️⃣ 创建 ImageReader ,用于接收屏幕数据
imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 3);
// 注册回调
mediaProjection.registerCallback(projectionCallback, new Handler(Looper.getMainLooper()));
// 3️⃣ 创建 VirtualDisplay ,将屏幕内容映射到 ImageReader
virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture", screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null);
commonPlay = new CommonPlay(context, mediaProjection, mediaProjectionManager, imageReader);
setImageReaderListener();
refreshVirtualDisplay();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "My Channel";
String description = "Channel for my foreground service";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// 注册通知渠道
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
// 创建通知
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("My Service").setContentText("Service is running in the foreground").setSmallIcon(R.drawable.ic_launcher_background) // 小图标
.build();
// 启动前台服务
startForeground(1, notification);
int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED);
Intent data = intent.getParcelableExtra("data");
if (resultCode == Activity.RESULT_OK && data != null) {
startScreenCapture(resultCode, data);
}
return START_STICKY;
}
![]() |
1
sankemao 6 天前
如果屏幕上像素没有变化,拿不到截图的
|
![]() |
2
flyqie 6 天前 via Android
话说...这怎么帖子排版全丢了。。。
|
3
fenglirookie OP @flyqie 不知道,,我粘贴进来就这样
|
4
fenglirookie OP @sankemao 像素怎么会变化呢?不是画面变化了就会推送吗?还说的 16 毫秒就会推送一次
|