Skip to content

Commit

Permalink
Use PixelCopy API when supported (#147)
Browse files Browse the repository at this point in the history
This supports hardware rendering.
  • Loading branch information
mattprecious authored Nov 11, 2024
1 parent 6f0535f commit dd4600c
Showing 1 changed file with 59 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
Expand All @@ -29,8 +30,10 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.PixelCopy;
import android.view.Surface;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.ColorInt;
Expand All @@ -50,6 +53,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.graphics.Paint.Style;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.PixelCopy.SUCCESS;
import static com.mattprecious.telescope.Preconditions.checkNotNull;

/**
Expand Down Expand Up @@ -193,7 +197,7 @@ public void onReceive(Context context, Intent intent) {
Activity.RESULT_CANCELED);

if (resultCode != Activity.RESULT_OK) {
captureCanvasScreenshot();
captureWindowScreenshot();
return;
}

Expand Down Expand Up @@ -428,8 +432,7 @@ void trigger() {
switch (screenshotMode) {
case SYSTEM:
if (projectionManager != null
&& !screenshotChildrenOnly
&& screenshotTarget == this
&& shouldCaptureWholeWindow()
&& !windowHasSecureFlag()) {
// Take a full screenshot of the device. Request permission first.
registerRequestCaptureReceiver();
Expand All @@ -439,7 +442,7 @@ void trigger() {

// System was requested but isn't supported. Fall through.
case CANVAS:
captureCanvasScreenshot();
captureWindowScreenshot();
break;
case NONE:
doneAnimator.start();
Expand All @@ -457,6 +460,10 @@ private void vibrateIfNecessary() {
}
}

private boolean shouldCaptureWholeWindow() {
return !screenshotChildrenOnly && screenshotTarget == this;
}

private boolean windowHasSecureFlag() {
// Find an activity.
Context context = getContext();
Expand All @@ -480,21 +487,44 @@ void checkLens() {
}
}

void captureCanvasScreenshot() {
private void captureWindowScreenshot() {
capturingStart();

// Wait for the next frame to be sure our progress bars are hidden.
post(() -> {
View view = getTargetView();
view.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
Window window = findWindow();
if (Build.VERSION.SDK_INT >= 26 && shouldCaptureWholeWindow() && window != null) {
Bitmap screenshot = Bitmap.createBitmap(window.peekDecorView().getWidth(),
window.peekDecorView().getHeight(), Bitmap.Config.ARGB_8888);
PixelCopy.request(window, screenshot, copyResult -> {
if (copyResult == SUCCESS) {
finishCanvasScreenshot(screenshot);
} else {
Log.e(
TAG,
"Failed to capture window screenshot (" + copyResult + "). Falling back to canvas."
);
captureCanvasScreenshot(view);
}
}, handler);
} else {
captureCanvasScreenshot(view);
}
});
}

capturingEnd();
private void captureCanvasScreenshot(View view) {
view.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
finishCanvasScreenshot(screenshot);
}

checkLens();
lens.onCapture(screenshot, processed -> new SaveScreenshotTask(processed).execute());
});
private void finishCanvasScreenshot(Bitmap screenshot) {
capturingEnd();
checkLens();
lens.onCapture(screenshot, processed -> new SaveScreenshotTask(processed).execute());
}

private void capturingStart() {
Expand Down Expand Up @@ -525,6 +555,22 @@ View getTargetView() {
return view;
}

private Window findWindow() {
Context c = getContext();
while (true) {
if (c instanceof Activity) {
return ((Activity) c).getWindow();
}

if (c instanceof ContextWrapper) {
c = ((ContextWrapper) c).getBaseContext();
} else {
return null;
}
}
}


/** Recursive delete of a file or directory. */
private static void delete(File file) {
if (file.isDirectory()) {
Expand Down Expand Up @@ -721,7 +767,7 @@ static Handler getBackgroundHandler() {
Log.e(TAG,
"Failed to capture system screenshot. Setting the screenshot mode to CANVAS.", e);
setScreenshotMode(ScreenshotMode.CANVAS);
post(this::captureCanvasScreenshot);
post(this::captureWindowScreenshot);
} finally {
if (bitmap != null) {
bitmap.recycle();
Expand Down

0 comments on commit dd4600c

Please sign in to comment.