悬浮窗截取手机屏幕
2019-12-06 本文已影响0人
小玉1991
用到了MediaProjection 和ImageReader,VirtualDisplay
代码如下
在Acticity中先申请权限
public void requestCapturePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.0 之后才允许使用屏幕截图
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager)
getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(
mediaProjectionManager.createScreenCaptureIntent(),
REQUEST_MEDIA_PROJECTION);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_MEDIA_PROJECTION:
if (resultCode == RESULT_OK && data != null) {
FloatWindowsService.setResultData(data);
startService(new Intent(getApplicationContext(), FloatWindowsService.class));
}
break;
}
}
悬浮窗继承并注册Sercvice,系统API截图的代码
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class FloatWindowsService extends Service {
private long mCounts;
public static Intent newIntent(Context context, Intent mResultData) {
Intent intent = new Intent(context, FloatWindowsService.class);
if (mResultData != null) {
intent.putExtras(mResultData);
}
return intent;
}
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private static Intent mResultData = null;
private ImageReader mImageReader;
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private GestureDetector mGestureDetector;
private ImageView mFloatView;
private int mScreenWidth;
private int mScreenHeight;
private int mScreenDensity;
private static final String PATH = APP_DIR + "ScreenCapture/";
@Override
public void onCreate() {
super.onCreate();
createFloatView();
}
public static Intent getResultData() {
return mResultData;
}
public static void setResultData(Intent mResultData) {
FloatWindowsService.mResultData = mResultData;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressLint("ClickableViewAccessibility")
private void createFloatView() {
mGestureDetector = new GestureDetector(getApplicationContext(), new FloatGestrueTouchListener());
mLayoutParams = new WindowManager.LayoutParams();
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
mScreenDensity = metrics.densityDpi;
mScreenWidth = metrics.widthPixels;
mScreenHeight = metrics.heightPixels;
mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mLayoutParams.format = PixelFormat.RGBA_8888;
// 设置Window flag
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = mScreenWidth;
mLayoutParams.y = 100;
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mFloatView = new ImageView(getApplicationContext());
mFloatView.setImageBitmap(BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_compass));
mWindowManager.addView(mFloatView, mLayoutParams);
mFloatView.setOnTouchListener((v, event) -> mGestureDetector.onTouchEvent(event));
}
private class FloatGestrueTouchListener implements GestureDetector.OnGestureListener {
int lastX, lastY;
int paramX, paramY;
@Override
public boolean onDown(MotionEvent event) {
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
paramX = mLayoutParams.x;
paramY = mLayoutParams.y;
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
startScreenShot();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int dx = (int) e2.getRawX() - lastX;
int dy = (int) e2.getRawY() - lastY;
mLayoutParams.x = paramX + dx;
mLayoutParams.y = paramY + dy;
// 更新悬浮窗位置
mWindowManager.updateViewLayout(mFloatView, mLayoutParams);
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
}
private void startScreenShot() {
Logger.info("FloatWin", "start-->" + System.currentTimeMillis());
mFloatView.setVisibility(View.GONE);
if (mMediaProjection != null) {
virtualDisplay();
} else {
setUpMediaProjection();
virtualDisplay();
}
}
public void setUpMediaProjection() {
if (mResultData == null) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
} else {
mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData);
}
}
private MediaProjectionManager getMediaProjectionManager() {
return (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
}
private void virtualDisplay() {
// createImageReader
mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 1);
mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",
mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mImageReader.getSurface(), null, null);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
Logger.info("FloatWin", "get image-->" + System.currentTimeMillis());
Bitmap bitmap = null;
try {
if (image != null) {
bitmap = saveBitmap(image);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
SaveTask mSaveTask = new SaveTask();
mSaveTask.execute(bitmap);
mImageReader.close();
}
}
}, getBackgroundHandler());
}
Handler backgroundHandler;
private Handler getBackgroundHandler() {
if (backgroundHandler == null) {
HandlerThread backgroundThread =
new HandlerThread("catwindow", android.os.Process
.THREAD_PRIORITY_BACKGROUND);
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
return backgroundHandler;
}
public class SaveTask extends AsyncTask<Bitmap, Void, Bitmap> {
@Override
protected Bitmap doInBackground(Bitmap... params) {
if (params == null || params.length < 1 || params[0] == null) {
return null;
}
Bitmap bitmap = params[0];
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//主线程中提示
if (bitmap != null) {
mCounts = 0;
Logger.info("FloatWin", "saved image-->" + System.currentTimeMillis());
bitmap.recycle();
CustomToast.showGrayToast(getApplicationContext(), "保存成功");
mFloatView.setVisibility(View.VISIBLE);
} else {
mCounts++;
if (mCounts < 10) {
Logger.info("FloatWin", "image is null, reshot");
startScreenShot();
}else {
Logger.info("FloatWin", "image is null, retry too many times");
}
}
}
}
@Nullable
private Bitmap saveBitmap(Image image) {
int width = image.getWidth();
int height = image.getHeight();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
//每个像素的间距
int pixelStride = planes[0].getPixelStride();
//总的间距
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
File fileImage = null;
if (bitmap != null) {
try {
File forder = new File(PATH);
if (!forder.exists()) {
forder.mkdir();
}
fileImage = new File(PATH + System.currentTimeMillis() + ".jpg");
if (!fileImage.exists()) {
fileImage.createNewFile();
}
FileOutputStream out = new FileOutputStream(fileImage);
if (out != null) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
Intent media = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(fileImage);
media.setData(contentUri);
sendBroadcast(media);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
fileImage = null;
} catch (IOException e) {
e.printStackTrace();
fileImage = null;
}
}
if (fileImage != null) {
return bitmap;
}
return null;
}
private void tearDownMediaProjection() {
if (mMediaProjection != null) {
mMediaProjection.stop();
mMediaProjection = null;
}
}
private void stopVirtual() {
if (mVirtualDisplay == null) {
return;
}
mVirtualDisplay.release();
mVirtualDisplay = null;
}
@Override
public void onDestroy() {
// to remove mFloatLayout from windowManager
super.onDestroy();
if (mFloatView != null) {
mWindowManager.removeView(mFloatView);
}
stopVirtual();
tearDownMediaProjection();
}
}