问题
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