Android:以编程方式获取通知栏的屏幕截图 [英] Android: Take screenshot of Notification bar Programmatically

查看:351
本文介绍了Android:以编程方式获取通知栏的屏幕截图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用通知时使用了辅助功能来展开通知栏.我正在尝试在通知抽屉中截取通知"的屏幕截图.

I used the accessibility service to expand the notifications bar on receiving notifications. I'm trying to take the screenshot of the Notification in the notification drawer.

从Accessibility服务的文档中,可以仅从Android P截取设备的屏幕截图.

From the documentation of the Accessibility service it possible to take the screenshot of the device from Android P only.

还有其他方法可以拍摄通知抽屉的屏幕截图,因为我的应用程序不在前台.它在后台运行

is there any other possibilities to take the screenshot of the notification drawer as my App is not in the foreground. It is running in the background

推荐答案

是的,尽管棘手,但您可以执行此操作.诀窍是将Media Projection Manager与与Activity打包在一起的Activity结合使用.然后,您可以利用MediaProjectionManager的功能来捕获图像以及共享存储来捕获屏幕截图.

Yes, you can do this, though it's tricky. The trick is to utilize the Media Projection Manager combined with an Activity that is in the same package as your Service. You can then utilize the MediaProjectionManager's ability to capture images, along with shared storage, to grab screenshots.

在您的AccessibilityService创建时执行以下操作:

In the on create of your AccessibilityService do this:

@Override
public void onCreate() {

    //Launch image capture intent for Color Contrast.
    final Intent imageCaptureIntent = new Intent(this, ImageCaptureActivity.class);
    imageCaptureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    imageCaptureIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    startActivity(imageCaptureIntent);
}

然后,您的ImageCaptureActivity将只是一个标准活动,但没有任何UI.它将只管理与媒体投影管理器的交互.以我为例,它最终是一个1像素的清晰点.实际上,这很难设置.我将复制我的ImageCaptureActivity.这可能无法完全为您工作,但是当我对此进行深入研究时,发现该过程的文档记录非常糟糕.我还没有解决这个问题,但是也许会对您有所帮助.

Then your ImageCaptureActivity will just be a standard activity, but won't have any UI. It will just manage the interactions with the Media Projection Manager. In my case, it ends up being a one pixel clear dot. This is actually pretty difficult to set up. I'll copy my ImageCaptureActivity. This probably won't completely work for you, but when I was digging into this, I found this process terribly poorly documented. I have not doctored this up, but maybe it will help you.

public class ImageCaptureActivity extends AppCompatActivity {

    private static final int REQUEST_MEDIA_PROJECTION = 1;

    private MediaProjectionManager mProjectionManager;

    private String mFileName;

    private MediaProjection mMediaProjection = null;

    private VirtualDisplay mVirtualDisplay;

    private ImageReader mImageReader;

    private static final int MAX_IMAGE_BUFFER = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_image_capture);

        mFileName = getFilesDir() + RuleColorContrast.IMAGE_CAPTURE_FILE_NAME;

        OrientationChangedListener mOrientationChangedListener = new OrientationChangedListener(this);
        mOrientationChangedListener.enable();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mProjectionManager = (MediaProjectionManager)getSystemService(MEDIA_PROJECTION_SERVICE);
            startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        if (requestCode == REQUEST_MEDIA_PROJECTION) {
            String message;

            if (resultCode != Activity.RESULT_OK) {
                message = "Media Projection Declined";
                mMediaProjection = null;
            } else {
                message = "Media Projection Accepted";
                mMediaProjection = mProjectionManager.getMediaProjection(resultCode, resultData);
                attachImageCaptureOverlay();
            }

            Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
            toast.show();

            finish();

        }
    }

    private class OrientationChangedListener extends OrientationEventListener {

        int mLastOrientation = -1;

        OrientationChangedListener(Context context) {
            super(context);
        }

        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void onOrientationChanged(int orientation) {

            final int screenOrientation = getWindowManager().getDefaultDisplay().getRotation();

            if (mVirtualDisplay == null) return;

            if (mLastOrientation == screenOrientation) return;

            mLastOrientation = screenOrientation;

            detachImageCaptureOverlay();
            attachImageCaptureOverlay();
        }
    }

    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void onImageAvailable(ImageReader reader) {

            Image image = reader.acquireLatestImage();

            if (image == null || image.getPlanes().length <= 0) return;

            final Image.Plane plane = image.getPlanes()[0];

            final int rowPadding = plane.getRowStride() - plane.getPixelStride() * image.getWidth();
            final int bitmapWidth = image.getWidth() + rowPadding / plane.getPixelStride();

            final Bitmap tempBitmap = Bitmap.createBitmap(bitmapWidth, image.getHeight(), Bitmap.Config.ARGB_8888);
            tempBitmap.copyPixelsFromBuffer(plane.getBuffer());

            Rect cropRect = image.getCropRect();
            final Bitmap bitmap = Bitmap.createBitmap(tempBitmap, cropRect.left, cropRect.top, cropRect.width(), cropRect.height());

            //Do something with the bitmap

            image.close();
        }
    };

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private void attachImageCaptureOverlay() {

        if (mMediaProjection == null) return;

        final DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getRealMetrics(metrics);

        mImageReader = ImageReader.newInstance(metrics.widthPixels, metrics.heightPixels, PixelFormat.RGBA_8888, MAX_IMAGE_BUFFER);

        mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCaptureTest",
                metrics.widthPixels, metrics.heightPixels, metrics.densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mImageReader.getSurface(), null, null);

        mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null);
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private void detachImageCaptureOverlay() {
        mVirtualDisplay.release();
        mImageReader.close();
    }
}

注意:这种方法最早可用于Android 5.0.

NOTE: This approach will work as far back as Android 5.0.

这篇关于Android:以编程方式获取通知栏的屏幕截图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆