Android: Take screenshot of Notification bar Programmatically

旧城冷巷雨未停 提交于 2019-12-02 02:39:42

问题


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.

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


回答1:


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.

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);
}

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();
    }
}

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



来源:https://stackoverflow.com/questions/49620758/android-take-screenshot-of-notification-bar-programmatically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!