【问题标题】:screen shot using media projection not perfoming any action使用 mediaprojection 的屏幕截图未执行任何操作
【发布时间】:2017-12-14 12:01:43
【问题描述】:

大家好,我有一个来自 (@commonsware) 的示例屏幕截图项目,它使用媒体项目在任何屏幕上执行屏幕截图(在前台服务模式下运行并带有通知)

但是它没有拍任何照片,只是在按钮点击时发出哔哔声

我的方法也是更改目录但不知道如何 我需要更改它,因为我想在应用程序内的 recyclerview 中加载所有图像

任何帮助将不胜感激

这是整个服务代码:

public class ScreenShotService extends Service {
private static final int NOTIFY_ID = 9906;
static final String EXTRA_RESULT_CODE = "resultCode";
static final String EXTRA_RESULT_INTENT = "resultIntent";
static final String ACTION_RECORD = BuildConfig.APPLICATION_ID + ".RECORD";
static final String ACTION_SHUTDOWN = BuildConfig.APPLICATION_ID + ".SHUTDOWN";
static final int VIRT_DISPLAY_FLAGS = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
private MediaProjection projection;
private VirtualDisplay vdisplay;
final private HandlerThread handlerThread = new HandlerThread(getClass().getSimpleName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
private Handler handler;
private WindowManager windowManager;
private MediaProjectionManager mediaProjectionManager;
private int resultCode;
private Intent resultData;
final private ToneGenerator beeper = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);

@Override
public void onCreate() {
    super.onCreate();

    mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
    windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
    handlerThread.start();
    handler=new Handler(handlerThread.getLooper());
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent.getAction() == null) {
        resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, 1337);
        resultData = intent.getParcelableExtra(EXTRA_RESULT_INTENT);
        foregroundify();
    }
    else if (intent.getAction().equals(ACTION_RECORD)) {
        if (resultData!=null) {
            startCapture();
        }
        else {
            Intent ui=
                    new Intent(this, Main.class)
                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            startActivity(ui);
        }
    }
    else if (intent.getAction().equals(ACTION_SHUTDOWN)) {
        beeper.startTone(ToneGenerator.TONE_PROP_NACK);
        stopForeground(true);
        stopSelf();
    }

    return(START_NOT_STICKY);
}

@Override
public void onDestroy() {
    stopCapture();

    super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    throw new IllegalStateException("Binding not supported. Go away.");
}

WindowManager getWindowManager() {
    return(windowManager);
}

Handler getHandler() {
    return(handler);
}

void processImage(final byte[] png) {
    new Thread() {
        @Override
        public void run() {File output=new File(getExternalFilesDir(null),
                    "screenshot.png");
            try {

                FileOutputStream fos=new FileOutputStream(output);
                fos.write(png);
                fos.flush();
                fos.getFD().sync();
                fos.close();

                MediaScannerConnection.scanFile(ScreenShotService.this,
                        new String[] {output.getAbsolutePath()},
                        new String[] {"image/png"},
                        null);
            }
            catch (Exception e) {
                Log.e(getClass().getSimpleName(), "Exception writing out screenshot", e);
            }
        }
    }.start();

    beeper.startTone(ToneGenerator.TONE_PROP_ACK);
    stopCapture();
}

private void stopCapture() {
    if (projection!=null) {
        projection.stop();
        vdisplay.release();
        projection=null;
    }
}

private void startCapture() {
    projection = mediaProjectionManager.getMediaProjection(resultCode, resultData);
    ImageTransmogrifier it = new ImageTransmogrifier(this);

    MediaProjection.Callback cb = new MediaProjection.Callback() {
        @Override
        public void onStop() {
            vdisplay.release();
        }
    };

    vdisplay=projection.createVirtualDisplay("shooter",
            it.getWidth(), it.getHeight(),
            getResources().getDisplayMetrics().densityDpi,
            VIRT_DISPLAY_FLAGS, it.getSurface(), null, handler);
    projection.registerCallback(cb, handler);
}

private void foregroundify() {
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

    builder.setAutoCancel(true)
            .setDefaults(Notification.DEFAULT_ALL);

    builder.setContentTitle(getString(R.string.app_name))
            .setSmallIcon(R.drawable.rec_icon)
            .setTicker(getString(R.string.app_name));

    builder.addAction(R.drawable.ic_record_white_24dp,
            getString(R.string.notify_record),
            buildPendingIntent(ACTION_RECORD));

    builder.addAction(R.drawable.ic_eject_white_24dp,
            getString(R.string.notify_shutdown),
            buildPendingIntent(ACTION_SHUTDOWN));

    startForeground(NOTIFY_ID, builder.build());
}

private PendingIntent buildPendingIntent(String action) {
    Intent i=new Intent(this, getClass());

    i.setAction(action);

    return(PendingIntent.getService(this, 0, i, 0));
}

}

还有图像变换器类:

public class ImageTransmogrifier implements ImageReader.OnImageAvailableListener {
private final int width;
private final int height;
private final ImageReader imageReader;
private final ScreenShotService svc;
private Bitmap latestBitmap=null;

ImageTransmogrifier(ScreenShotService svc) {
    this.svc=svc;

    Display display=svc.getWindowManager().getDefaultDisplay();
    Point size=new Point();

    display.getSize(size);

    int width=size.x;
    int height=size.y;

    while (width*height > (2<<19)) {
        width=width>>1;
        height=height>>1;
    }

    this.width=width;
    this.height=height;

    imageReader=ImageReader.newInstance(width, height,
            PixelFormat.RGBA_8888, 2);
    imageReader.setOnImageAvailableListener(this, svc.getHandler());
}

@Override
public void onImageAvailable(ImageReader reader) {
    final Image image=imageReader.acquireLatestImage();

    if (image!=null) {
        Image.Plane[] planes=image.getPlanes();
        ByteBuffer buffer=planes[0].getBuffer();
        int pixelStride=planes[0].getPixelStride();
        int rowStride=planes[0].getRowStride();
        int rowPadding=rowStride - pixelStride * width;
        int bitmapWidth=width + rowPadding / pixelStride;

        if (latestBitmap == null ||
                latestBitmap.getWidth() != bitmapWidth ||
                latestBitmap.getHeight() != height) {
            if (latestBitmap != null) {
                latestBitmap.recycle();
            }

            latestBitmap=Bitmap.createBitmap(bitmapWidth,
                    height, Bitmap.Config.ARGB_8888);
        }

        latestBitmap.copyPixelsFromBuffer(buffer);

        if (image != null) {
            image.close();
        }

        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        Bitmap cropped=Bitmap.createBitmap(latestBitmap, 0, 0,
                width, height);

        cropped.compress(Bitmap.CompressFormat.PNG, 100, baos);

        byte[] newPng=baos.toByteArray();

        svc.processImage(newPng);
    }
}

Surface getSurface() {
    return(imageReader.getSurface());
}

int getWidth() {
    return(width);
}

int getHeight() {
    return(height);
}

void close() {
    imageReader.close();
}

}

【问题讨论】:

  • “然而它没有拍任何照片”——你如何确定这一点?你在哪里找图片?如果您不加修改地运行我的示例应用程序,它可以工作吗?
  • 嘿@Co​​mmonsWare 我运行的是纯代码,甚至没有任何修改,但存储中没有 png 文件(我到处搜索)
  • “我正在运行纯代码,甚至没有任何修改”——你的代码肯定有修改。我写了the code that you started with。我一生中从未编写过名为Main 的活动,您也更改了其他值。所以,我再问一遍:如果您不加修改地运行我的示例应用程序,它可以工作吗?如果不是,您正在测试什么设备型号,在您捕获图像时前景是什么?
  • @CommonsWare 我在标题中写道,我试图在 recyclerview 中获取并检索它们,这意味着我将活动名称更改为我自己的项目,当我说我没有修改任何东西时这意味着我没有修改任何重要的东西(在 imagetransmogrifier 或任何我什至不知道它们是什么的东西),我扩展了通知,只是点击了记录,除了一声哔哔声,它甚至没有像我预期的那样折叠状态栏,我在 huwawei mate10 上运行它,我已经测试了你的项目,但它也不起作用
  • “在 imagetransmogrifier 或任何我什至不知道它们是什么的东西中”——这在my book 的媒体投影 API 章节中有所介绍。除此之外,使用adb shell 查看文件是否写入external storage,并使用调试器逐步执行Thread 内部Threadrun() 方法,以查看该代码是否被调用。跨度>

标签: android screenshot android-mediaprojection foreground-service


【解决方案1】:

它仅在您按下录制按钮时有效。[![button][1]][1]。然后就可以在作者建议的目录中找到了

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多