diff --git a/app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt b/app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt index c306af6..88e0c46 100644 --- a/app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt +++ b/app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt @@ -1318,10 +1318,30 @@ class ScreenCaptureService : Service() { { PGHLog.d(TAG, "📸 Capturing long screenshot frame") - val captured = longScreenshotCapture?.captureFrame() ?: false - if (!captured) - { - PGHLog.w(TAG, "⚠️ Failed to capture long screenshot frame") + // Get the current image from the existing screen capture system + latestImage?.let { image -> + // Convert the image to Mat first, then to Bitmap + val mat = convertImageToMat(image) + + if (mat != null) { + // Convert Mat to Bitmap + val bitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888) + Utils.matToBitmap(mat, bitmap) + + // Pass the bitmap to the long screenshot system + val captured = longScreenshotCapture?.captureFrame(bitmap) ?: false + if (!captured) { + PGHLog.w(TAG, "⚠️ Failed to capture long screenshot frame") + } + + // Clean up resources + bitmap.recycle() + mat.release() + } else { + PGHLog.w(TAG, "⚠️ Failed to convert image to Mat for long screenshot") + } + } ?: run { + PGHLog.w(TAG, "⚠️ No image available for long screenshot capture") } } diff --git a/app/src/main/java/com/quillstudios/pokegoalshelper/capture/LongScreenshotCapture.kt b/app/src/main/java/com/quillstudios/pokegoalshelper/capture/LongScreenshotCapture.kt index 2b98107..8fda498 100644 --- a/app/src/main/java/com/quillstudios/pokegoalshelper/capture/LongScreenshotCapture.kt +++ b/app/src/main/java/com/quillstudios/pokegoalshelper/capture/LongScreenshotCapture.kt @@ -44,10 +44,8 @@ class LongScreenshotCapture( private const val MAX_SCREENSHOTS = 50 } - // Core components + // Core components private var mediaProjection: MediaProjection? = null - private var virtualDisplay: VirtualDisplay? = null - private var imageReader: ImageReader? = null // Screen dimensions private var screenWidth = 0 @@ -75,7 +73,7 @@ class LongScreenshotCapture( private var errorCallback: ((error: String) -> Unit)? = null /** - * Initialize the long screenshot system with existing MediaProjection + * Initialize the long screenshot system (lightweight - no VirtualDisplay needed) */ fun initialize(mediaProjection: MediaProjection, screenWidth: Int, screenHeight: Int, screenDensity: Int): Boolean { @@ -94,31 +92,12 @@ class LongScreenshotCapture( this.screenHeight = screenHeight this.screenDensity = screenDensity - // Create dedicated ImageReader for long screenshots - imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, BUFFER_COUNT) - imageReader?.setOnImageAvailableListener(onImageAvailableListener, handler) - - // Create dedicated VirtualDisplay for long screenshots - virtualDisplay = mediaProjection.createVirtualDisplay( - "LongScreenshotCapture", - screenWidth, - screenHeight, - screenDensity, - DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, - imageReader?.surface, - null, - handler - ) - - if (virtualDisplay == null) - { - PGHLog.e(TAG, "❌ Failed to create VirtualDisplay for long screenshots") - cleanup() - return false - } + // Note: We don't create our own VirtualDisplay/ImageReader since Android doesn't allow + // multiple VirtualDisplays from the same MediaProjection. Instead, we'll capture + // screenshots by requesting them from the existing screen capture system. isInitialized.set(true) - PGHLog.i(TAG, "✅ Long screenshot capture system initialized successfully") + PGHLog.i(TAG, "✅ Long screenshot capture system initialized successfully (lightweight mode)") return true } @@ -172,8 +151,9 @@ class LongScreenshotCapture( /** * Capture a single frame manually (on-demand) + * This will be called by the service which will provide the actual image data */ - fun captureFrame(): Boolean + fun captureFrame(imageData: Bitmap?): Boolean { if (!isCapturing.get()) { @@ -190,20 +170,21 @@ class LongScreenshotCapture( return try { - PGHLog.d(TAG, "📸 Triggering manual frame capture") + PGHLog.d(TAG, "📸 Processing manual frame capture") - // Force a capture by accessing the ImageReader - // The VirtualDisplay should automatically provide images to the ImageReader - imageReader?.acquireLatestImage()?.let { image -> - PGHLog.d(TAG, "📸 Image acquired from ImageReader, processing...") + if (imageData != null) + { + PGHLog.d(TAG, "📸 Image data received, processing...") - // Process the image in a coroutine + // Process the bitmap in a coroutine captureScope.launch { - processImageAsync(image) + processBitmapAsync(imageData) } return true - } ?: run { - PGHLog.w(TAG, "⚠️ No image available from ImageReader") + } + else + { + PGHLog.w(TAG, "⚠️ No image data provided") return false } @@ -304,27 +285,7 @@ class LongScreenshotCapture( this.errorCallback = callback } - private val onImageAvailableListener = ImageReader.OnImageAvailableListener { reader -> - if (!isCapturing.get()) return@OnImageAvailableListener - - try - { - val image = reader.acquireLatestImage() - if (image != null) - { - captureScope.launch { - processImageAsync(image) - } - } - } - catch (e: Exception) - { - PGHLog.e(TAG, "❌ Error in onImageAvailableListener", e) - errorCallback?.invoke("Image capture failed: ${e.message}") - } - } - - private suspend fun processImageAsync(image: Image) = withContext(Dispatchers.IO) + private suspend fun processBitmapAsync(bitmap: Bitmap) = withContext(Dispatchers.IO) { try { @@ -332,89 +293,37 @@ class LongScreenshotCapture( val filename = "screenshot_${timestamp}.png" val file = File(storageDir, filename) - // Convert image to bitmap and save - val bitmap = convertImageToBitmap(image) - if (bitmap != null) - { - saveBitmapToFile(bitmap, file) - - val screenshot = CapturedScreenshot( - id = timestamp, - filename = filename, - filePath = file.absolutePath, - timestamp = timestamp, - width = screenWidth, - height = screenHeight - ) - - capturedScreenshots.offer(screenshot) - val count = screenshotCount.incrementAndGet() - - PGHLog.i(TAG, "📸 Screenshot #$count captured: $filename") - - // Notify progress on main thread - handler.post { - progressCallback?.invoke(count) - } - - bitmap.recycle() - } - else - { - PGHLog.e(TAG, "❌ Failed to convert image to bitmap") - errorCallback?.invoke("Failed to process screenshot") - } + // Save bitmap to file + saveBitmapToFile(bitmap, file) - } - catch (e: Exception) - { - PGHLog.e(TAG, "❌ Error processing image", e) - errorCallback?.invoke("Failed to save screenshot: ${e.message}") - } - finally - { - image.close() - } - } - - private fun convertImageToBitmap(image: Image): Bitmap? - { - return try - { - val planes = image.planes - val buffer = planes[0].buffer - val pixelStride = planes[0].pixelStride - val rowStride = planes[0].rowStride - val rowPadding = rowStride - pixelStride * screenWidth - - val bitmap = Bitmap.createBitmap( - screenWidth + rowPadding / pixelStride, - screenHeight, - Bitmap.Config.ARGB_8888 + val screenshot = CapturedScreenshot( + id = timestamp, + filename = filename, + filePath = file.absolutePath, + timestamp = timestamp, + width = bitmap.width, + height = bitmap.height ) - bitmap.copyPixelsFromBuffer(buffer) + capturedScreenshots.offer(screenshot) + val count = screenshotCount.incrementAndGet() - // Crop if there's padding - if (rowPadding == 0) - { - bitmap - } - else - { - val croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, screenWidth, screenHeight) - bitmap.recycle() - croppedBitmap + PGHLog.i(TAG, "📸 Screenshot #$count captured: $filename") + + // Notify progress on main thread + handler.post { + progressCallback?.invoke(count) } } catch (e: Exception) { - PGHLog.e(TAG, "❌ Error converting image to bitmap", e) - null + PGHLog.e(TAG, "❌ Error processing bitmap", e) + errorCallback?.invoke("Failed to save screenshot: ${e.message}") } } + private fun saveBitmapToFile(bitmap: Bitmap, file: File) { FileOutputStream(file).use { stream -> @@ -454,10 +363,6 @@ class LongScreenshotCapture( // Cancel any ongoing coroutines captureScope.cancel() - // Clean up capture resources - virtualDisplay?.release() - imageReader?.close() - // Clear collections capturedScreenshots.clear() screenshotCount.set(0) @@ -466,8 +371,6 @@ class LongScreenshotCapture( clearStoredScreenshots() // Clear references - virtualDisplay = null - imageReader = null mediaProjection = null progressCallback = null errorCallback = null