需求:对于无显示设备的android设备,如何获取到当前设备画面
条件:首先在android设备中搭建一个web服务器,可以参考基于前面介绍的ijetty服务器
实现:
方法1:
参考系统hide代码,android.view.Surface.java
public boolean takeScreenShot(String imagePath){
if(imagePath.equals("" )){
imagePath = Environment.getExternalStorageDirectory()+File. separator+"Screenshot.png" ;
}
Bitmap mScreenBitmap;
WindowManager mWindowManager;
DisplayMetrics mDisplayMetrics;
Display mDisplay;
mWindowManager = (WindowManager) mcontext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
float[] dims = {mDisplayMetrics.widthPixels , mDisplayMetrics.heightPixels };
mScreenBitmap = Surface. screenshot((int) dims[0], ( int) dims[1]);
if (mScreenBitmap == null) {
return false ;
}
try {
FileOutputStream out = new FileOutputStream(imagePath);
mScreenBitmap.compress(Bitmap.CompressFormat. PNG, 100, out);
} catch (Exception e) {
return false ;
}
return true ;
}
我们要利用web服务器把图像传出来,可以拿到上面代码中的outputStream,然后拷贝到HttpServletResponse的输出流中。
这个screenshot函数还需要一些其他数据,例如display,metrics,dims等,我们参考Surface类中的实现,得出的可用类代码如下:
public class ScreenshotNative {
private Context mContext;
private WindowManager mWindowManager;
private Display mDisplay;
private DisplayMetrics mDisplayMetrics;
private Matrix mDisplayMatrix;
private Bitmap mScreenBitmap;
private static final Object sLock = new Object();
public ScreenshotNative(Context context) {
mContext = context;
mDisplayMatrix = new Matrix();
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
}
private float getDegreesForRotation(int value) {
switch (value) {
case Surface.ROTATION_90:
return 360f - 90f;
case Surface.ROTATION_180:
return 360f - 180f;
case Surface.ROTATION_270:
return 360f - 270f;
}
return 0f;
}
public void takeScreenshot(OutputStream out) throws IOException {
// We need to orient the screenshot correctly (and the Surface api seems to take screenshots
// only in the natural orientation of the device :!)
//
mDisplay.getRealMetrics(mDisplayMetrics);
float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
float degrees = getDegreesForRotation(mDisplay.getRotation());
boolean requiresRotation = (degrees > 0);
if (requiresRotation) {
// Get the dimensions of the device in its native orientation
mDisplayMatrix.reset();
mDisplayMatrix.preRotate(-degrees);
mDisplayMatrix.mapPoints(dims);
dims[0] = Math.abs(dims[0]);
dims[1] = Math.abs(dims[1]);
}
Log.d("takeScreenshot", "takeScreenshot, dims, w-h: " + dims[0] + "-" + dims[1] + "; " +
"dm w-h: " + mDisplayMetrics.widthPixels + mDisplayMetrics.heightPixels +
"Thread=" + Thread.currentThread().getName());
// Take the screenshot
synchronized (sLock) {
mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
if (mScreenBitmap == null) {
throw new IOException("Bitmap is null after taking native screenshot!");
}
if (requiresRotation) {
// Rotate the screenshot to the current orientation
Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(ss);
c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
c.rotate(degrees);
c.translate(-dims[0] / 2, -dims[1] / 2);
c.drawBitmap(mScreenBitmap, 0, 0, null);
c.setBitmap(null);
// Recycle the previous bitmap
mScreenBitmap.recycle();
mScreenBitmap = ss;
}
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
mScreenBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
Log.d("takeScreenshot","Thread=" + Thread.currentThread().getName());
mScreenBitmap.recycle();
// Clear any references to the bitmap
mScreenBitmap = null;
}
}
}
使用方法如下:
private void screenshotNative(HttpServletResponse response){
try {
ServletOutputStream outputStream = response.getOutputStream();
new ScreenshotNative(mContext).takeScreenshot(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
这样在GET请求就能拿到对应的流了 然后存在本地即可。
方法2:
使用screencap工具
public void takeScreenShot(){
String mSavedPath = "/sdcard/" + "screenshot.png" ;
try {
Process p = Runtime. getRuntime().exec("screencap -p " + mSavedPath);
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
代码执行后,再把文件拷到servlet的输出流中就好了。screencap只支持png格式的存储。
以上两种方法都需要添加权限:
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
并使用system uid